Files
Print_server/Inspectron.Epson/DiscoveryService.cs
EugeneTes e8d20c77c7 size to kitchen
printer logs removed
2026-02-05 11:39:06 +01:00

153 lines
5.0 KiB
C#

using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
namespace Inspectron.Epson;
public class DiscoveryService : IDiscoveryService
{
private const int DiscoveryPort = 3289;
private const string DiscoveryMessage = "EPSONQ";
private const int MessageLength = 14;
private readonly ILogger? _logger;
public DiscoveryService(ILogger? logger = null)
{
_logger = logger;
}
/// <summary>
/// Discovers Epson printers on the local network using UDP broadcast
/// </summary>
/// <param name="timeout">How long to wait for responses (default: 5 seconds)</param>
/// <param name="onPrinterDiscovered">Optional callback invoked when a printer is discovered</param>
/// <returns>List of discovered printer information</returns>
public async Task<List<DiscoveredPrinter>> DiscoverPrintersAsync(
TimeSpan? timeout = null,
Action<DiscoveredPrinter>? onPrinterDiscovered = null)
{
timeout ??= TimeSpan.FromSeconds(5);
using var udpClient = new UdpClient();
udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, 0));
// Send discovery broadcast message
var msg = BuildDiscoveryMessage();
var broadcastEndpoint = new IPEndPoint(IPAddress.Broadcast, DiscoveryPort);
await udpClient.SendAsync(msg, msg.Length, broadcastEndpoint);
// Receive responses
var discoveredPrinters = new List<DiscoveredPrinter>();
var endTime = DateTime.UtcNow.Add(timeout.Value);
while (DateTime.UtcNow < endTime)
{
try
{
var remainingTime = endTime - DateTime.UtcNow;
if (remainingTime <= TimeSpan.Zero)
break;
var receiveTask = udpClient.ReceiveAsync();
var timeoutTask = Task.Delay(remainingTime);
var completedTask = await Task.WhenAny(receiveTask, timeoutTask);
if (completedTask == receiveTask)
{
var result = await receiveTask;
// Check if we've already discovered this printer
if (!discoveredPrinters.Any(p => p.IPAddress.Equals(result.RemoteEndPoint.Address)))
{
var ipAddress = result.RemoteEndPoint.Address.ToString();
var printer = new DiscoveredPrinter
{
IPAddress = ipAddress,
DiscoveredAt = DateTime.UtcNow
};
// Try to get printer model by connecting and querying
printer.ModelName = await GetPrinterModelAsync(ipAddress);
discoveredPrinters.Add(printer);
onPrinterDiscovered?.Invoke(printer);
}
}
else
{
break; // Timeout reached
}
}
catch (Exception)
{
// Ignore errors and continue waiting for other responses
break;
}
}
return discoveredPrinters;
}
private static byte[] BuildDiscoveryMessage()
{
// msg = b'EPSONQ' + bytes([0x00] * 8)
var msg = new byte[MessageLength];
Array.Copy(System.Text.Encoding.ASCII.GetBytes(DiscoveryMessage), msg, 6);
msg[6] = 3;
for (int i = 7; i < msg.Length; i++)
{
msg[i] = 0x00;
}
msg[10] = 0x10;
return msg;
}
/// <summary>
/// Connects to a printer and retrieves its model name
/// </summary>
private async Task<string?> GetPrinterModelAsync(string ipAddress, int port = 9100)
{
try
{
_logger?.LogDebug("Connecting to printer at {IP} to retrieve model", ipAddress);
await using var epsonPrinter = new EpsonPrinter();
await epsonPrinter.ConnectAsync(ipAddress, port, timeoutSeconds: 3);
var printerId = await epsonPrinter.GetPrinterIdAsync();
if (printerId.HasValue)
{
var modelName = GetModelNameFromId(printerId.Value);
_logger?.LogDebug("Printer at {IP} identified as {Model} (ID: 0x{Id:X2})",
ipAddress, modelName, printerId.Value);
return modelName;
}
_logger?.LogDebug("Could not retrieve printer ID from {IP}", ipAddress);
return null;
}
catch (Exception ex)
{
_logger?.LogWarning(ex, "Failed to get printer model from {IP}", ipAddress);
return null;
}
}
/// <summary>
/// Converts a printer ID byte to a model name string
/// </summary>
private static string GetModelNameFromId(byte printerId)
{
return printerId switch
{
0x01 => "TM-T30III",
0x0D => "TM-U220II",
0x13 => "TM-U220II",
_ => $"Unknown (0x{printerId:X2})"
};
}
}