Hi Sander, @sandervandevelde
When I start the emulator it looks to be running.
Start Advantech Wise4012e Modbus simulation at 127.0.0.1
Slave 1 supports switch 1, switch 2, relay 17, relay 18, knob 40001, knob 40002
False False False False 0000 0000 - Write '1 [bit]' '2 [bit]' '17 [bit]' '18 [bit]' '40001 [int]' '40002 [int]' or Q to exit
1 1
True False False False 0000 0000 - Write '1 [bit]' '2 [bit]' '17 [bit]' '18 [bit]' '40001 [int]' '40002 [int]' or Q to exit
1 0
False False False False 0000 0000 - Write '1 [bit]' '2 [bit]' '17 [bit]' '18 [bit]' '40001 [int]' '40002 [int]' or Q to exit
1 1
True False False False 0000 0000 - Write '1 [bit]' '2 [bit]' '17 [bit]' '18 [bit]' '40001 [int]' '40002 [int]' or Q to exit
But the IoT client cannot connect.. Please advise :) Thanks!
docker logs -f msftmodbus
Connect Slave failed
Connection refused 127.0.0.1:502
Connection lost, reconnecting...
Connect Slave failed
Connection refused 127.0.0.1:502
Connection lost, reconnecting...
Connect Slave failed
Connection refused 127.0.0.1:502
Connection lost, reconnecting...
Connect Slave failed
Connection refused 127.0.0.1:502
Connection lost, reconnecting...
Connect Slave failed
Connection refused 127.0.0.1:502
Connection lost, reconnecting...
Connect Slave failed
Connection refused 127.0.0.1:502
JSON:
{
"deviceId": "mytemperaturemeter",
"moduleId": "msftmodbus",
"etag": "AAAAAAAAAAM=",
"deviceEtag": "Nzg5ODU3NDgw",
"status": "enabled",
"statusUpdateTime": "0001-01-01T00:00:00",
"connectionState": "Connected",
"lastActivityTime": "2019-03-13T13:41:16.2208709",
"cloudToDeviceMessageCount": 0,
"authenticationType": "sas",
"x509Thumbprint": {
"primaryThumbprint": null,
"secondaryThumbprint": null
},
"version": 7,
"properties": {
"desired": {
"PublishInterval": "5000",
"Version": "1",
"SlaveConfigs": {
"Slave01": {
"SlaveConnection": "127.0.0.1",
"HwId": "Wise4012E",
"Operations": {
"Op01": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "40001",
"Count": "1",
"DisplayName": "KnobOne"
},
"Op02": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "40002",
"Count": "1",
"DisplayName": "KnobTwo"
},
"Op03": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "00001",
"Count": "1",
"DisplayName": "SwitchOne"
},
"Op04": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "00002",
"Count": "1",
"DisplayName": "SwitchTwo"
},
"Op05": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "00017",
"Count": "1",
"DisplayName": "RelayOne"
},
"Op06": {
"PollingInterval": "5000",
"UnitId": "1",
"StartAddress": "00018",
"Count": "1",
"DisplayName": "RelayTwo"
}
}
}
},
"$metadata": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PublishInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Version": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"SlaveConfigs": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"Slave01": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"SlaveConnection": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"HwId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Operations": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"Op01": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
},
"Op02": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
},
"Op03": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
},
"Op04": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
},
"Op05": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
},
"Op06": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3,
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"Count": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:44:52.8504242Z",
"$lastUpdatedVersion": 3
}
}
}
}
}
},
"$version": 3
},
"reported": {
"PublishInterval": 5000,
"SlaveConfigs": {
"Slave01": {
"Operations": {
"Op01": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "40001",
"Count": 1,
"DisplayName": "KnobOne",
"CorrelationId": "DefaultCorrelationId"
},
"Op02": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "40002",
"Count": 1,
"DisplayName": "KnobTwo",
"CorrelationId": "DefaultCorrelationId"
},
"Op03": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "00001",
"Count": 1,
"DisplayName": "SwitchOne",
"CorrelationId": "DefaultCorrelationId"
},
"Op04": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "00002",
"Count": 1,
"DisplayName": "SwitchTwo",
"CorrelationId": "DefaultCorrelationId"
},
"Op05": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "00017",
"Count": 1,
"DisplayName": "RelayOne",
"CorrelationId": "DefaultCorrelationId"
},
"Op06": {
"PollingInterval": 5000,
"UnitId": 1,
"StartAddress": "00018",
"Count": 1,
"DisplayName": "RelayTwo",
"CorrelationId": "DefaultCorrelationId"
}
},
"SlaveConnection": "10.10.61.161",
"RetryCount": 10,
"RetryInterval": 50,
"TcpPort": 502,
"HwId": "Wise4012E"
}
},
"$metadata": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PublishInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"SlaveConfigs": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"Slave01": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"Operations": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"Op01": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
},
"Op02": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
},
"Op03": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
},
"Op04": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
},
"Op05": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
},
"Op06": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z",
"PollingInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"UnitId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"StartAddress": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"Count": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"DisplayName": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"CorrelationId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
}
},
"SlaveConnection": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"RetryCount": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"RetryInterval": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"TcpPort": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
},
"HwId": {
"$lastUpdated": "2019-03-14T15:30:12.6537423Z"
}
}
}
},
"$version": 4
}
}
}
I think, there is something with AsyncListen. But still, it has issues.
using Microsoft.Extensions.Configuration;
using Modbus.Data;
using Modbus.Device;
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Advantech.Wise4012e.Modbus.SimulationApp
{
internal class Program
{
public static IConfiguration Configuration { get; set; }
private static readonly CancellationTokenSource token = new CancellationTokenSource();
private const byte SlaveID = 1;
private static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("settings.json");
Configuration = builder.Build();
var address = Configuration["address"];
Console.WriteLine($"Start Advantech Wise4012e Modbus simulation at {address}");
var slaveTcpListener = new TcpListener(IPAddress.Parse(address), 502);
slaveTcpListener.Start();
var slave = ModbusTcpSlave.CreateTcp(SlaveID, slaveTcpListener);
slave.DataStore = DataStoreFactory.CreateDefaultDataStore();
slave.DataStore.DataStoreReadFrom += DataStore_DataStoreReadFrom;
slave.DataStore.DataStoreWrittenTo += DataStore_DataStoreWrittenTo;
slave.DataStore.HoldingRegisters[1] = (ushort)0;
slave.DataStore.HoldingRegisters[2] = (ushort)0;
slave.DataStore.CoilDiscretes[1] = false;
slave.DataStore.CoilDiscretes[2] = false;
slave.DataStore.CoilDiscretes[17] = false;
slave.DataStore.CoilDiscretes[18] = false;
Task.Run(() => Loop(slave));
try
{
slave.ListenAsync().Wait(token.Token);
}
catch (OperationCanceledException)
{
}
slave.Dispose();
}
private static void Loop(object slaveObj)
{
var slave = (ModbusTcpSlave)slaveObj;
Console.WriteLine($"Slave {SlaveID} supports switch 1, switch 2, relay 17, relay 18, knob 40001, knob 40002");
while (true)
{
Console.WriteLine($"> {slave.DataStore.CoilDiscretes[1]} {slave.DataStore.CoilDiscretes[2]} {slave.DataStore.CoilDiscretes[17]} {slave.DataStore.CoilDiscretes[18]} {slave.DataStore.HoldingRegisters[1]:0000} {slave.DataStore.HoldingRegisters[2]:0000} - Write '1 [bit]' '2 [bit]' '17 [bit]' '18 [bit]' '40001 [int]' '40002 [int]' or Q to exit");
Console.Write("> ");
var input = Console.ReadLine();
if (input.ToUpper() == "Q")
{
token.Cancel();
break;
}
var fields = input.Split(' ');
switch (fields[0])
{
case "1":
slave.DataStore.CoilDiscretes[1] = Convert.ToBoolean(Convert.ToInt16(fields[1]));
break;
case "2":
slave.DataStore.CoilDiscretes[2] = Convert.ToBoolean(Convert.ToInt16(fields[1]));
break;
case "17":
slave.DataStore.CoilDiscretes[17] = Convert.ToBoolean(Convert.ToInt16(fields[1]));
break;
case "18":
slave.DataStore.CoilDiscretes[18] = Convert.ToBoolean(Convert.ToInt16(fields[1]));
break;
case "40001":
var value1 = Math.Abs(Convert.ToInt32(fields[1]));
slave.DataStore.HoldingRegisters[1] = value1 > 4500 ? (ushort)4500 : (ushort)value1;
break;
case "40002":
var value2 = Math.Abs(Convert.ToInt32(fields[1]));
slave.DataStore.HoldingRegisters[2] = value2 > 4500 ? (ushort)4500 : (ushort)value2;
break;
}
}
}
private static void DataStore_DataStoreReadFrom(object sender, DataStoreEventArgs e)
{
{
if (e.ModbusDataType == ModbusDataType.HoldingRegister)
{
Console.WriteLine($"\nClient reads {e.ModbusDataType} address {e.StartAddress + 40001} - read {e.Data.B[0]}");
Console.Write("> ");
}
else
{
Console.WriteLine($"\nClient reads {e.ModbusDataType} address {e.StartAddress + 1} - read {e.Data.A[0]}");
Console.Write("> ");
}
}
}
private static void DataStore_DataStoreWrittenTo(object sender, DataStoreEventArgs e)
{
Console.WriteLine($"\nClient writes {e.ModbusDataType} address {e.StartAddress + 1} - write {e.Data.A[0]}");
Console.Write("> ");
}
}
}