Host
The host is the main switch for a Zeus application. It creates channels, opens them, starts acquisition, and releases resources on shutdown.
Minimal Pattern
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("meter");
});
await app.StartAsync();
var meter = app.Channels.Get("meter");
await meter.WriteAsync(new byte[] { 0x01 });
await app.StopAsync();
Read it as:
ZeusHost.Create: declare channels, devices, and services.StartAsync: open channels and start background services.Channels.Get: access a running channel.StopAsync: close channels and pause services.
Create Does Not Open Ports
This only registers the channel:
await using var app = ZeusHost.Create(builder =>
{
builder.AddSerialPort("meter", "COM3", 9600);
});
The port opens only after:
await app.StartAsync();
Calling WriteAsync before StartAsync fails because the channel is still Created.
Registration Order
Use this order in most apps:
await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(500));
builder.AddSerialPort("bus", "COM3", 9600);
builder.AddModbusRtu("oven", "bus", unitId: 1, points: map =>
{
map.HoldingRegister("temperature", 0, 0.1)
.HoldingRegister("setpoint", 1, 0.1).Writable("setpoint");
});
});
| Order | Reason |
|---|---|
| Configure acquisition | Polling interval is host-level behavior |
| Register channels | Devices bind to channel names |
| Register devices | Devices expose protocol APIs and points |
| Start host | Open everything after all declarations are complete |
Runtime Access
var channel = app.Channels.Get("bus");
var device = app.Devices.Get<ModbusDevice>("oven");
var temperature = app.Points.Get<double>("temperature");
Missing names produce exceptions that include currently registered names.
Restart After Stop
StopAsync closes channels and pauses acquisition, but the host can be started again:
await app.StopAsync();
await app.StartAsync();
After DisposeAsync, create a new host.
Runtime Topology Changes
await app.AddVirtualChannelAsync("bus");
app.AddModbusRtu("oven", "bus", points: map => map.HoldingRegister("pv", 0));
await app.RemoveDeviceAsync("oven");
await app.RemoveChannelAsync("bus");
When the host is running, new channels open immediately. Removing a channel removes bound devices by default.
If the supplied CancellationToken is already canceled, runtime add/remove APIs return cancellation before mutating registries; they do not leave a half-registered channel/device or half-remove existing topology. When the host is running and a new required channel fails while opening, it is rolled back from the channel registry.
Reconnects
After a channel becomes Faulted, Zeus waits 1 second, retries, then backs off up to 30 seconds by default. Explicit CloseAsync does not reconnect.
Caller cancellation is not considered a channel failure. If OpenAsync, WriteAsync, StartAsync, or runtime channel registration observes the caller's token cancellation, Zeus preserves OperationCanceledException, does not mark the channel Faulted, and does not schedule reconnect. Reconnect only takes over after real open, receive, or write failures put the channel in Faulted.
builder.AddReconnect(options =>
{
options.Enabled = true;
options.InitialDelay = TimeSpan.FromSeconds(1);
options.MaxDelay = TimeSpan.FromSeconds(30);
});
Disable reconnects if you want to drive recovery manually through StateChanged and OpenAsync.
Register Your Services
Zeus uses .NET dependency injection:
await using var app = ZeusHost.Create(builder =>
{
builder.Services.AddSingleton<MyBusinessService>();
builder.AddVirtualChannel("meter");
});
This is a good place for acquisition processing, alarm logic, or database writers that should not live inside a form class.
Custom devices that need a logger from the container can use the factory overload that receives IServiceProvider:
builder.AddDevice("meter", "bus", (services, name, channel) =>
new TemperatureMeter(name, channel, services.GetRequiredService<ILogger<TemperatureMeter>>()));
Configure Logging
builder.Logging is a standard ILoggingBuilder. The default is the Generic Host console logger. Attach JSON, files, or Serilog here:
await using var app = ZeusHost.Create(builder =>
{
builder.Logging.AddJsonConsole();
builder.Logging.SetMinimumLevel(LogLevel.Information);
builder.AddVirtualChannel("meter");
});
Channel open/close, reconnect, acquisition failures, and point write-back failures go to ILogger with stable ids from ZeusLogEvents. Filter by EventId in the field instead of matching Chinese message text.
To log TX/RX for every channel while troubleshooting:
builder.AddCommunicationLogging(); // Debug by default
The default level is Debug so hex payloads do not drown business logs. The category defaults to Zeus.Communication and can be changed in the options callback.
Next: Virtual Channel, Serial Port, or TCP / UDP.