Сервер для сбора данных с термодатчиковых модулей
This commit is contained in:
@@ -1 +1,4 @@
|
|||||||
thermo_sensor/config.h
|
thermo_sensor/config.h
|
||||||
|
esp_server/.vs/
|
||||||
|
esp_server/bin/
|
||||||
|
esp_server/obj/
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
public static class Logging
|
||||||
|
{
|
||||||
|
public static void Setup()
|
||||||
|
{
|
||||||
|
var config = new NLog.Config.LoggingConfiguration();
|
||||||
|
|
||||||
|
var logConsole = new NLog.Targets.ConsoleTarget("logconsole");
|
||||||
|
config.AddRuleForAllLevels(logConsole);
|
||||||
|
LogManager.Configuration = config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
class ModbusServer
|
||||||
|
{
|
||||||
|
private RegistersContainer registers;
|
||||||
|
|
||||||
|
public int Port { get; set; }
|
||||||
|
|
||||||
|
public ModbusServer(RegistersContainer registers)
|
||||||
|
{
|
||||||
|
this.registers = registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Run()
|
||||||
|
{
|
||||||
|
var logger = LogManager.GetCurrentClassLogger();
|
||||||
|
logger.Info("Accepting connections on port " + Port);
|
||||||
|
var listener = new TcpListener(IPAddress.Any, Port);
|
||||||
|
listener.Start();
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var client = listener.AcceptTcpClient();
|
||||||
|
logger.Info("Accepted connection from " + client.Client.RemoteEndPoint);
|
||||||
|
var worker = new ModbusServerWorker(registers, client);
|
||||||
|
Thread clientThread = new Thread(new ThreadStart(worker.Run));
|
||||||
|
clientThread.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModbusServerWorker
|
||||||
|
{
|
||||||
|
const int RECEIVE_TIMEOUT = 10000; // 10 seconds
|
||||||
|
|
||||||
|
private RegistersContainer registers;
|
||||||
|
private TcpClient client;
|
||||||
|
private static Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
public ModbusServerWorker(RegistersContainer registers, TcpClient client)
|
||||||
|
{
|
||||||
|
this.registers = registers;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<byte> received;
|
||||||
|
ManualResetEvent readCompleted;
|
||||||
|
int currentReceived;
|
||||||
|
NetworkStream stream;
|
||||||
|
byte[] buffer = new byte[256];
|
||||||
|
|
||||||
|
public void Run()
|
||||||
|
{
|
||||||
|
logger.Debug("Working with client");
|
||||||
|
received = new List<byte>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.ReceiveTimeout = RECEIVE_TIMEOUT;
|
||||||
|
stream = client.GetStream();
|
||||||
|
readCompleted = new ManualResetEvent(false);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
readCompleted.Reset();
|
||||||
|
stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(this.OnReadCompleted), this);
|
||||||
|
readCompleted.WaitOne();
|
||||||
|
if (currentReceived <= 0)
|
||||||
|
{
|
||||||
|
client.Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProcessReceivedData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException)
|
||||||
|
{
|
||||||
|
client.Close();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (stream != null) stream.Dispose();
|
||||||
|
client.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessReceivedData()
|
||||||
|
{
|
||||||
|
lock (received)
|
||||||
|
{
|
||||||
|
if (received.Count < 6) return;
|
||||||
|
int len = (((int)received[4] << 8) | (int)received[5]);
|
||||||
|
if (received.Count < 6 + len) return;
|
||||||
|
if (len < 2) throw new Exception("Wrong length");
|
||||||
|
int transactionId = (((int)received[0] << 8) | (int)received[1]);
|
||||||
|
byte unitId = received[6];
|
||||||
|
byte function = received[7];
|
||||||
|
List<byte> response = new List<byte>();
|
||||||
|
if (function == 0x03) // read holding registers
|
||||||
|
{
|
||||||
|
int addr = (((int)received[8] << 8) | (int)received[9]);
|
||||||
|
int amount = (((int)received[10] << 8) | (int)received[11]);
|
||||||
|
for (int a = addr; a < addr + amount; a++)
|
||||||
|
{
|
||||||
|
int value = registers[a];
|
||||||
|
response.Add((byte)((value >> 8) & 0xFF));
|
||||||
|
response.Add((byte)(value & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unsupported function: " + function);
|
||||||
|
}
|
||||||
|
List<byte> fullResponse = new List<byte>();
|
||||||
|
fullResponse.Add(received[0]);
|
||||||
|
fullResponse.Add(received[1]); // transaction id
|
||||||
|
fullResponse.Add(received[2]);
|
||||||
|
fullResponse.Add(received[3]); // protocol id
|
||||||
|
int responseLength = 3 + response.Count;
|
||||||
|
fullResponse.Add((byte)((responseLength >> 8) & 0xFF));
|
||||||
|
fullResponse.Add((byte)((responseLength) & 0xFF));
|
||||||
|
fullResponse.Add(unitId);
|
||||||
|
fullResponse.Add(function);
|
||||||
|
fullResponse.Add((byte)response.Count);
|
||||||
|
fullResponse.AddRange(response);
|
||||||
|
received.RemoveRange(0, 6 + len);
|
||||||
|
stream.Write(fullResponse.ToArray(), 0, fullResponse.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnReadCompleted(IAsyncResult ar)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
currentReceived = stream.EndRead(ar);
|
||||||
|
lock (received)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < currentReceived; i++) received.Add(buffer[i]);
|
||||||
|
}
|
||||||
|
readCompleted.Set();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
logger.Info("Error receiving " + e);
|
||||||
|
currentReceived = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.CommandLine;
|
||||||
|
using System.CommandLine.Invocation;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static JsonDocument config;
|
||||||
|
static UnitsDatabase db;
|
||||||
|
static RegistersContainer registers;
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||||
|
config = LoadConfig();
|
||||||
|
Logging.Setup();
|
||||||
|
db = new UnitsDatabase(config.RootElement.GetProperty("units"));
|
||||||
|
registers = new RegistersContainer();
|
||||||
|
var rootCommand = new RootCommand();
|
||||||
|
var runCommand = new Command("run")
|
||||||
|
{
|
||||||
|
};
|
||||||
|
runCommand.Handler = CommandHandler.Create<string>(RunService);
|
||||||
|
rootCommand.AddCommand(runCommand);
|
||||||
|
var openhabConfigCommand = new Command("openhab-config")
|
||||||
|
{
|
||||||
|
};
|
||||||
|
openhabConfigCommand.Handler = CommandHandler.Create<string>(GenerateOpenhabConfig);
|
||||||
|
rootCommand.AddCommand(openhabConfigCommand);
|
||||||
|
rootCommand.InvokeAsync(args).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GenerateOpenhabConfig(string obj)
|
||||||
|
{
|
||||||
|
var root = config.RootElement;
|
||||||
|
StringBuilder thingsConfig = new StringBuilder();
|
||||||
|
StringBuilder itemsConfig = new StringBuilder();
|
||||||
|
thingsConfig.AppendFormat("Bridge modbus:tcp:{0} [ host=\"{1}\", port={2}, id=1 ] {{\n",
|
||||||
|
"esp_server",
|
||||||
|
root.GetProperty("IP").GetString(),
|
||||||
|
root.GetProperty("modbusPort").GetInt32());
|
||||||
|
//
|
||||||
|
db.GenerateThingsConfig(thingsConfig);
|
||||||
|
db.GenerateItemsConfig(itemsConfig);
|
||||||
|
//
|
||||||
|
thingsConfig.Append("}\n");
|
||||||
|
|
||||||
|
File.WriteAllText("esp_server.things", thingsConfig.ToString());
|
||||||
|
File.WriteAllText("esp_server.items", itemsConfig.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunService(string obj)
|
||||||
|
{
|
||||||
|
var unitReceiver = new UnitDataReceiver(config.RootElement.GetProperty("port").GetInt32(), db, registers);
|
||||||
|
unitReceiver.Start();
|
||||||
|
var modbusServer = new ModbusServer(registers);
|
||||||
|
modbusServer.Port = config.RootElement.GetProperty("modbusPort").GetInt32();
|
||||||
|
modbusServer.Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonDocument LoadConfig()
|
||||||
|
{
|
||||||
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
|
var config = Path.Combine(assemblyFolder, "esp_server.json");
|
||||||
|
string configStr = File.ReadAllText(config);
|
||||||
|
return JsonDocument.Parse(configStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Any CPU</Platform>
|
||||||
|
<PublishDir>bin\Release\netcoreapp3.1\publish\</PublishDir>
|
||||||
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>false</SelfContained>
|
||||||
|
<PublishSingleFile>False</PublishSingleFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
class RegistersContainer
|
||||||
|
{
|
||||||
|
private Dictionary<int, int> registers;
|
||||||
|
|
||||||
|
public RegistersContainer()
|
||||||
|
{
|
||||||
|
registers = new Dictionary<int, int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int this[int address]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock(registers)
|
||||||
|
{
|
||||||
|
if (registers.ContainsKey(address)) return registers[address];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
lock (registers)
|
||||||
|
{
|
||||||
|
registers[address] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFloat(int address, float value)
|
||||||
|
{
|
||||||
|
byte[] bytes = BitConverter.GetBytes(value);
|
||||||
|
registers[address + 1] = (int)bytes[0] + (((int)bytes[1]) << 8);
|
||||||
|
registers[address] = (int)bytes[2] + (((int)bytes[3]) << 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using NLog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
class UnitDataReceiver
|
||||||
|
{
|
||||||
|
private readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
UnitsDatabase db;
|
||||||
|
RegistersContainer registers;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
public UnitDataReceiver(int port, UnitsDatabase db, RegistersContainer registers)
|
||||||
|
{
|
||||||
|
this.db = db;
|
||||||
|
this.port = port;
|
||||||
|
this.registers = registers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
var t = new Thread(new ThreadStart(this.Run));
|
||||||
|
t.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Run()
|
||||||
|
{
|
||||||
|
UdpClient listener = new UdpClient(port);
|
||||||
|
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.Info("Listening for UDP datagrams on port " + port);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
byte[] bytes = listener.Receive(ref groupEP);
|
||||||
|
string t = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
|
||||||
|
logger.Debug("Received: " + t);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var received = JsonDocument.Parse(t);
|
||||||
|
var id = received.RootElement.GetProperty("id").GetString();
|
||||||
|
var unit = db.GetUnit(id);
|
||||||
|
if (unit == null)
|
||||||
|
{
|
||||||
|
logger.Info("Packet from unknown unit " + id);
|
||||||
|
unit = db.AddUnit(id);
|
||||||
|
}
|
||||||
|
ProcessUnit(unit, received.RootElement);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.Error(e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SocketException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
listener.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessUnit(Unit unit, JsonElement data)
|
||||||
|
{
|
||||||
|
var ip = data.GetProperty("ip").GetString();
|
||||||
|
lock (unit)
|
||||||
|
{
|
||||||
|
unit.ip = ip;
|
||||||
|
foreach (var v in data.EnumerateObject())
|
||||||
|
{
|
||||||
|
if (v.Name == "id" || v.Name == "ip") continue;
|
||||||
|
var uv = unit.GetValue(v.Name);
|
||||||
|
if (uv == null)
|
||||||
|
{
|
||||||
|
logger.Info("Unit " + unit.id + " unknown value " + v.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (v.Value.ValueKind == JsonValueKind.Null) uv.value = float.NaN;
|
||||||
|
if (v.Value.ValueKind == JsonValueKind.Number) uv.value = v.Value.GetSingle();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!float.TryParse(v.Value.GetString(), out uv.value))
|
||||||
|
{
|
||||||
|
uv.value = float.NaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FillRegisters(unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillRegisters(Unit unit)
|
||||||
|
{
|
||||||
|
foreach (var uv in unit.values)
|
||||||
|
{
|
||||||
|
registers.SetFloat(unit.baseAddress + uv.Value.addressOffset, uv.Value.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace ESPServer
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Описание параметра, который может придти от юнита
|
||||||
|
*/
|
||||||
|
class UnitValue
|
||||||
|
{
|
||||||
|
// Название параметра
|
||||||
|
public string name;
|
||||||
|
// Текущее значение
|
||||||
|
public float value;
|
||||||
|
// Сдвиг адреса, по которому это значение будет храниться в modbus
|
||||||
|
public int addressOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Описание конкретного модуля (релейный, датчик, whatever)
|
||||||
|
*/
|
||||||
|
class Unit
|
||||||
|
{
|
||||||
|
// Айдишник юнита (мак-адрес)
|
||||||
|
public string id;
|
||||||
|
// Название (для генерации конфигов например)
|
||||||
|
public string name;
|
||||||
|
// Базовый адрес в модбасе
|
||||||
|
public int baseAddress;
|
||||||
|
// Значения которые есть в юните
|
||||||
|
public Dictionary<string, UnitValue> values;
|
||||||
|
// текущий IP юнита
|
||||||
|
public string ip;
|
||||||
|
|
||||||
|
public UnitValue GetValue(string name)
|
||||||
|
{
|
||||||
|
if (!values.ContainsKey(name))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return values[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MinOffset
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int min = int.MaxValue;
|
||||||
|
foreach (var u in values) if (u.Value.addressOffset < min) min = u.Value.addressOffset;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MaxOffset
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int max = int.MinValue;
|
||||||
|
foreach (var u in values) if (u.Value.addressOffset > max) max = u.Value.addressOffset;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnitsDatabase
|
||||||
|
{
|
||||||
|
List<Unit> units;
|
||||||
|
|
||||||
|
public UnitsDatabase(JsonElement config)
|
||||||
|
{
|
||||||
|
units = new List<Unit>();
|
||||||
|
foreach (var unitConfig in config.EnumerateArray())
|
||||||
|
{
|
||||||
|
var u = new Unit();
|
||||||
|
u.id = unitConfig.GetProperty("id").GetString();
|
||||||
|
u.name = unitConfig.GetProperty("name").GetString();
|
||||||
|
u.baseAddress = unitConfig.GetProperty("address").GetInt32();
|
||||||
|
u.values = new Dictionary<string, UnitValue>();
|
||||||
|
foreach (var knownValue in unitConfig.GetProperty("values").EnumerateArray())
|
||||||
|
{
|
||||||
|
var uv = new UnitValue();
|
||||||
|
uv.name = knownValue.GetProperty("name").GetString();
|
||||||
|
uv.addressOffset = knownValue.GetProperty("offset").GetInt32();
|
||||||
|
u.values[uv.name] = uv;
|
||||||
|
}
|
||||||
|
units.Add(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Unit AddUnit(string id)
|
||||||
|
{
|
||||||
|
lock (units)
|
||||||
|
{
|
||||||
|
var u = new Unit();
|
||||||
|
u.id = id;
|
||||||
|
u.name = id;
|
||||||
|
u.baseAddress = -1;
|
||||||
|
u.values = new Dictionary<string, UnitValue>();
|
||||||
|
units.Add(u);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Unit GetUnit(string id)
|
||||||
|
{
|
||||||
|
lock (units)
|
||||||
|
{
|
||||||
|
foreach (var u in units)
|
||||||
|
{
|
||||||
|
if (u.id == id) return u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region OpenHAB config generation
|
||||||
|
internal void GenerateItemsConfig(StringBuilder config)
|
||||||
|
{
|
||||||
|
foreach (var u in units)
|
||||||
|
{
|
||||||
|
foreach (var uv in u.values)
|
||||||
|
{
|
||||||
|
var v = uv.Value;
|
||||||
|
config.Append(string.Format("Number {0}_{1} \"{0} {1}\"", u.name, v.name));
|
||||||
|
config.Append(" {channel=\"");
|
||||||
|
config.AppendFormat("modbus:data:esp_server:esp_server:");
|
||||||
|
config.AppendFormat("{0}_{1}:number", u.name, v.name);
|
||||||
|
config.Append("\"}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void GenerateThingsConfig(StringBuilder config)
|
||||||
|
{
|
||||||
|
int minAddress = int.MaxValue;
|
||||||
|
int maxAddress = int.MinValue;
|
||||||
|
foreach (var u in units)
|
||||||
|
{
|
||||||
|
if (u.baseAddress + u.MinOffset < minAddress)
|
||||||
|
{
|
||||||
|
minAddress = u.baseAddress + u.MinOffset;
|
||||||
|
}
|
||||||
|
if (u.baseAddress + u.MaxOffset > maxAddress)
|
||||||
|
{
|
||||||
|
maxAddress = u.baseAddress + u.MaxOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// поскольку читаем флоаты, нужен ещё регистр запаса
|
||||||
|
maxAddress++;
|
||||||
|
config.Append("\tBridge poller ");
|
||||||
|
config.Append("esp_server");
|
||||||
|
config.AppendFormat("[start = {0}, length = {1}, type = \"holding\", refresh = 500] {{\n", minAddress, maxAddress - minAddress + 1);
|
||||||
|
foreach (var u in units)
|
||||||
|
{
|
||||||
|
foreach (var uv in u.values)
|
||||||
|
{
|
||||||
|
var v = uv.Value;
|
||||||
|
config.Append("\t\tThing data ");
|
||||||
|
config.Append(u.name + "_" + v.name);
|
||||||
|
config.AppendFormat("[readStart = \"{0}\", readValueType = \"float32\"]\n", u.baseAddress + v.addressOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.Append("\t}\n");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.9" />
|
||||||
|
<PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20574.7" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_LastSelectedProfileId>C:\Work\heat_control\esp_server\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"IP": "192.168.0.10",
|
||||||
|
"port": 7000,
|
||||||
|
"modbusPort": 7001,
|
||||||
|
"units": [
|
||||||
|
{
|
||||||
|
"name": "unit1",
|
||||||
|
"id": "8c:aa:b5:7d:6e:6c",
|
||||||
|
"address": 10,
|
||||||
|
"values": [
|
||||||
|
{ "name": "t", "offset": 0 },
|
||||||
|
{ "name": "h", "offset": 2 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30804.86
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "esp_server", "esp_server.csproj", "{A9FC0FC1-AB9D-4395-A3E2-721EF901226B}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A9FC0FC1-AB9D-4395-A3E2-721EF901226B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9FC0FC1-AB9D-4395-A3E2-721EF901226B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A9FC0FC1-AB9D-4395-A3E2-721EF901226B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A9FC0FC1-AB9D-4395-A3E2-721EF901226B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {75B90B6A-0F87-466B-B503-069E4A09A77C}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user