sandervandevelde / advantech.wise4012e.modbus.simulation Goto Github PK
View Code? Open in Web Editor NEWApplication which simulates an Advantech Wise 4012e IO module. The application is written in .Net Core.
License: MIT License
Application which simulates an Advantech Wise 4012e IO module. The application is written in .Net Core.
License: MIT License
Hi
The instruction Go to 'settings.json' and replace the localhost address by your specific local IP Address (you can look it up using 'ipconfig') suggests that you can only interact with this module if it is installed on the IoT edge device (local IP) or in same network?
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("> ");
}
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.