跳到主要内容

宿主

宿主就是 Zeus 程序的总开关。它负责创建通道、打开通道、启动采集循环、停止时释放资源。

最小写法

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();

读法是:

  1. ZeusHost.Create:声明“这个程序有哪些通道、设备和服务”。
  2. StartAsync:真正打开通道并启动后台服务。
  3. Channels.Get:拿到运行中的通道。
  4. StopAsync:关闭通道并释放资源。

Create 阶段只声明,不打开

这段代码只是在登记通道:

await using var app = ZeusHost.Create(builder =>
{
builder.AddSerialPort("meter", "COM3", 9600);
});

此时串口还没有打开。真正打开是在:

await app.StartAsync();

所以如果你在 StartAsync 前调用 WriteAsync,会看到“当前为 Created,无法写入”。

注册顺序怎么写

一般按这个顺序:

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, raw => raw * 0.1);
});
});
顺序为什么
先配置采集采集间隔是宿主级设置
再注册通道设备需要绑定已有通道
再注册设备设备会引用通道名
最后启动宿主所有东西都声明完再打开

运行时可以查什么

var channel = app.Channels.Get("bus");
var device = app.Devices.Get<ModbusDevice>("oven");
var temperature = app.Points.Get<double>("temperature");
目录用途
app.Channels查通道,例如串口、TCP、虚拟通道
app.Devices查设备,例如 Modbus 设备
app.Points查点表,例如温度、压力、开关量

找不到名称时,异常会列出当前已经注册的名称,方便你对照拼写。

在宿主里注册自己的服务

Zeus 使用 .NET 依赖注入。你可以把自己的业务服务放进去:

await using var app = ZeusHost.Create(builder =>
{
builder.Services.AddSingleton<MyBusinessService>();
builder.AddVirtualChannel("meter");
});

这适合把采集后的业务处理、报警判断、数据库写入等逻辑拆出窗体类。

常见问题

现象原因处理
通道名称已存在注册了两个同名通道给通道改名,例如 ovenBusplcBus
当前为 Created,无法写入还没启动宿主await app.StartAsync()
某个通道启动失败串口被占用、TCP 连不上或参数错误其它通道会继续启动,查看日志和通道 State
关闭程序后端口仍被占用没释放宿主使用 await using,或在关闭窗口时调用释放逻辑

下一步:没有硬件先看 虚拟通道,接真实设备看 串口TCP 客户端