Temperature Controller
Treat holding register 0 as oven temperature. Build against a virtual slave first, then replace the channel with a serial port on site.
var memory = new ModbusSlaveMemory();
memory.HoldingRegisters[0] = 1800; // raw value, scaled by 0.1 to 180.0
await using var app = ZeusHost.Create(builder =>
{
builder.AddAcquisition(TimeSpan.FromMilliseconds(500));
builder.AddVirtualChannel("bus", new ModbusSlaveResponder(1, ModbusTransport.Rtu, memory));
builder.AddModbusRtu("oven", "bus", points: map =>
map.HoldingRegister("temperature", 0, 0.1)
.HoldingRegister("setpoint", 1, 0.1).Writable("setpoint"));
});
await app.StartAsync();
var pv = app.Points.Get<double>("temperature");
await app.Points.WriteAsync("setpoint", 180.0);
Replace the field channel later:
builder.AddSerialPort("bus", "COM3", 9600);
builder.AddModbusRtu("oven", "bus", unitId: 1);
WinForms can display the temperature with app.Points.BindText("temperature", label). WPF should expose app.Points.AsBindingSource("temperature", WpfUiDispatcher.Current()) from the ViewModel. Both UIs write the setpoint with WriteAsync("setpoint", 180.0), and protocol code does not change when the channel changes.