Added OpenHAB config files generation and command line command to use that. Also added transforms for OpenHAB integration.

This commit is contained in:
ftc
2021-01-08 16:55:19 +03:00
parent b9a1084d7a
commit 2e0b96ff7a
10 changed files with 183 additions and 32 deletions
+60
View File
@@ -21,8 +21,68 @@ namespace Barsik
/// </summary>
class MDStatMonitoringUnit : BaseMonitoringUnit
{
List<int> knownRaids;
public MDStatMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers)
{
knownRaids = new List<int>();
int currentAddress = baseAddress;
// the file is not so big, so read it completely
var lines = File.ReadAllLines("/proc/mdstat");
for (int i = 0; i < lines.Length;)
{
if (lines[i].StartsWith("md") && i < lines.Length - 1)
{
// we found device description
// second line of it is as follows:
// 2930264896 blocks super 1.0 [2/2] [UU]
// we need last characters in brackets []
int last_pos = lines[i + 1].LastIndexOf(']');
int pos;
for (pos = last_pos; pos > 0 && lines[i + 1][pos] != '['; pos--) ;
if (lines[i + 1][pos] != '[') knownRaids.Add(0);
else knownRaids.Add(last_pos - pos - 1);
i += 2;
}
else i++;
}
}
public override void GenerateItemsConfig(string name, StringBuilder config)
{
for (int i = 0; i < knownRaids.Count; i++)
{
for (int j = 0; j < knownRaids[i]; j++)
{
config.Append(string.Format("Switch {0}_RAID{1}Disk{2} \"{0} RAID{1} Disk{2} status\" <switch>", name, i, j));
config.Append(" {channel=\"");
config.AppendFormat("modbus:data:{0}:{1}:", name, unitName);
config.AppendFormat("RAID{0}Disk{1}:switch", name, i, j);
config.Append("\"}\n");
}
}
}
public override void GenerateThingsConfig(StringBuilder config)
{
int diskAmount = 0;
foreach (var size in knownRaids) diskAmount += size;
config.Append("\tBridge poller ");
config.Append(unitName);
config.AppendFormat("[start = {0}, length = {1}, type = \"holding\", refresh = 500] {{\n", baseAddress, diskAmount);
int currentAddress = baseAddress;
for (int i = 0; i < knownRaids.Count; i++)
{
for (int j = 0; j < knownRaids[i]; j++)
{
string name = string.Format("RAID{0}Disk{1}", i, j);
config.Append("\t\tThing data ");
config.Append(name);
config.AppendFormat("[readStart = \"{0}\", readValueType = \"int16\"]\n", currentAddress);
currentAddress++;
}
}
config.Append("\t}\n");
}
public override void Run()
+7 -4
View File
@@ -1,25 +1,28 @@
using System;
using System.Text;
using System.Text.Json;
namespace Barsik
{
class BaseMonitoringUnit
abstract class BaseMonitoringUnit
{
protected JsonElement config;
protected RegistersContainer registers;
protected int baseAddress;
protected string unitName;
public BaseMonitoringUnit(JsonElement config, RegistersContainer registers)
{
this.config = config.Clone();
this.registers = registers;
baseAddress = config.GetProperty("BaseAddress").GetInt32();
unitName = config.GetProperty("Name").GetString();
}
public virtual void Run()
{
}
public abstract void Run();
public abstract void GenerateThingsConfig(StringBuilder config);
public abstract void GenerateItemsConfig(string name, StringBuilder config);
public static BaseMonitoringUnit Create(JsonElement config, RegistersContainer registers)
{
+71 -23
View File
@@ -1,10 +1,12 @@
using NLog;
using System;
using System.Collections.Generic;
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;
@@ -14,6 +16,7 @@ namespace Barsik
{
private static RegistersContainer registers;
private static List<BaseMonitoringUnit> units;
private static JsonDocument configJson;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
@@ -27,42 +30,87 @@ namespace Barsik
};
runCommand.Handler = CommandHandler.Create<string>(RunService);
rootCommand.AddCommand(runCommand);
var openhabConfigCommand = new Command("openhab-config")
{
new Option<string>("--config", () => "", "Path to configuration file")
};
openhabConfigCommand.Handler = CommandHandler.Create<string>(GenerateOpenhabConfig);
rootCommand.AddCommand(openhabConfigCommand);
// Init common things
registers = new RegistersContainer();
//
rootCommand.InvokeAsync(args).Wait();
}
private static JsonDocument LoadConfig(string config)
{
if (string.IsNullOrEmpty(config))
{
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
config = Path.Combine(assemblyFolder, "barsik.json");
}
string configStr = File.ReadAllText(config);
return JsonDocument.Parse(configStr);
}
private static List<BaseMonitoringUnit> LoadUnits(JsonDocument config)
{
var units = new List<BaseMonitoringUnit>();
var root = config.RootElement;
foreach (var unitElement in root.GetProperty("Units").EnumerateArray())
{
var unit = BaseMonitoringUnit.Create(unitElement, registers);
if (unit != null)
{
units.Add(unit);
}
}
return units;
}
static void GenerateOpenhabConfig(string config)
{
configJson = LoadConfig(config);
units = LoadUnits(configJson);
var root = configJson.RootElement;
string name = root.GetProperty("Name").GetString();
StringBuilder thingsConfig = new StringBuilder();
StringBuilder itemsConfig = new StringBuilder();
thingsConfig.AppendFormat("Bridge modbus:tcp:{0} [ host=\"{1}\", port={2}, id=1 ] {{\n",
name,
root.GetProperty("IP").GetString(),
root.GetProperty("Port").GetInt32());
// generate units configs
foreach (var unit in units)
{
unit.GenerateThingsConfig(thingsConfig);
unit.GenerateItemsConfig(name, itemsConfig);
}
//
thingsConfig.Append("}\n");
File.WriteAllText(name + ".things", thingsConfig.ToString());
File.WriteAllText(name + ".items", itemsConfig.ToString());
}
static void RunService(string config)
{
Logging.Setup();
logger.Info("Barsik monitoring service starting");
registers = new RegistersContainer();
var server = new ModbusServer(registers);
units = new List<BaseMonitoringUnit>();
if (string.IsNullOrEmpty(config))
configJson = LoadConfig(config);
units = LoadUnits(configJson);
foreach (var unit in units)
{
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
config = Path.Combine(assemblyFolder, "barsik.json");
}
string configStr = File.ReadAllText(config);
int port = 0;
using (JsonDocument doc = JsonDocument.Parse(configStr))
{
var root = doc.RootElement;
port = root.GetProperty("Port").GetInt32();
foreach (var unitElement in root.GetProperty("Units").EnumerateArray())
{
var unit = BaseMonitoringUnit.Create(unitElement, registers);
if (unit != null)
{
units.Add(unit);
Thread unitThread = new Thread(new ThreadStart(unit.Run));
unitThread.Start();
}
}
}
logger.Info("Configuration loaded, we have " + units.Count + " units");
server.Port = port;
var server = new ModbusServer(registers);
server.Port = configJson.RootElement.GetProperty("Port").GetInt32();
server.Run();
logger.Info("Exiting");
}
@@ -7,8 +7,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PublishDir>bin\Debug\netcoreapp2.1\publish\</PublishDir>
<TargetFramework>netcoreapp3.1</TargetFramework>
<PublishDir>bin\Publish</PublishDir>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<_IsPortable>true</_IsPortable>
+33 -3
View File
@@ -1,4 +1,5 @@
using System;
using System.Text;
using System.Text.Json;
using System.Threading;
@@ -11,15 +12,16 @@ namespace Barsik
class SensorsMonitoringUnit : BaseMonitoringUnit
{
const string CORE_STR = "Core{0} Temp:";
const float MULTIPLIER = 100;
int cores;
public SensorsMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers)
{
cores = config.GetProperty("Cores").GetInt32();
}
public override void Run()
{
int cores = config.GetProperty("Cores").GetInt32();
var multiplier = config.GetProperty("Multiplier").GetDouble();
while (true)
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
@@ -60,7 +62,7 @@ namespace Barsik
// fill register data starting from baseAddress
for (int i = 0; i < cores; i++)
{
registers[baseAddress + i] = (int)(t[i] * multiplier);
registers[baseAddress + i] = (int)(t[i] * MULTIPLIER);
}
}
Thread.Sleep(2000);
@@ -84,5 +86,33 @@ namespace Barsik
float.TryParse(v.Substring(pos, pos2 - pos), out res);
return res;
}
public override void GenerateThingsConfig(StringBuilder config)
{
config.Append("\tBridge poller ");
config.Append(unitName);
config.AppendFormat("[start = {0}, length = {1}, type = \"holding\", refresh = 500] {{\n", baseAddress, cores);
int currentAddress = baseAddress;
for (int i = 0; i < cores; i++)
{
string name = string.Format("Core{0}Temp", i);
config.Append("\t\tThing data ");
config.Append(name);
config.AppendFormat("[readStart = \"{0}\", readValueType = \"int16\", readTransform=\"JS(divide100.js)\"]\n", currentAddress);
currentAddress++;
}
config.Append("\t}\n");
}
public override void GenerateItemsConfig(string name, StringBuilder config)
{
for (int i = 0; i < cores; i++)
{
config.Append(string.Format("Number {0}_Core{1}Temp \"{0} CPU Core{1} [%.1f °C]\" <temperature>", name, i));
config.Append(" {channel=\"");
config.AppendFormat("modbus:data:{0}:{1}:Core{2}Temp:number", name, unitName, i);
config.Append("\"}\n");
}
}
}
}
+2 -1
View File
@@ -1,11 +1,12 @@
{
"Name": "My_Server",
"IP": "192.168.0.5",
"Port": 4500,
"Units": [
{
"Name": "CPU",
"Type": "Sensors",
"BaseAddress": 1,
"Multiplier": 100,
"Cores": 2
},
{
+1 -1
View File
@@ -3,7 +3,7 @@ Description=Barsik monitoring service
After=network.target
[Service]
ExecStart=dotnet /root/barsik/Barsik.dll
ExecStart=/usr/bin/dotnet /root/barsik/Barsik.dll run
User=root
Group=root
RuntimeDirectory=/root/barsik
+3
View File
@@ -0,0 +1,3 @@
(function(i) {
return i / 100;
})(input)
+3
View File
@@ -0,0 +1,3 @@
(function(i) {
return i * 100;
})(input)
+3
View File
@@ -0,0 +1,3 @@
Transformations should be put into `/opt/openhab2/conf/transform` to work.
Some of monitoring units use them in configuration.