Added OpenHAB config files generation and command line command to use that. Also added transforms for OpenHAB integration.
This commit is contained in:
@@ -21,8 +21,68 @@ namespace Barsik
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class MDStatMonitoringUnit : BaseMonitoringUnit
|
class MDStatMonitoringUnit : BaseMonitoringUnit
|
||||||
{
|
{
|
||||||
|
List<int> knownRaids;
|
||||||
|
|
||||||
public MDStatMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers)
|
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()
|
public override void Run()
|
||||||
|
|||||||
+7
-4
@@ -1,25 +1,28 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Barsik
|
namespace Barsik
|
||||||
{
|
{
|
||||||
class BaseMonitoringUnit
|
abstract class BaseMonitoringUnit
|
||||||
{
|
{
|
||||||
protected JsonElement config;
|
protected JsonElement config;
|
||||||
protected RegistersContainer registers;
|
protected RegistersContainer registers;
|
||||||
|
|
||||||
protected int baseAddress;
|
protected int baseAddress;
|
||||||
|
protected string unitName;
|
||||||
|
|
||||||
public BaseMonitoringUnit(JsonElement config, RegistersContainer registers)
|
public BaseMonitoringUnit(JsonElement config, RegistersContainer registers)
|
||||||
{
|
{
|
||||||
this.config = config.Clone();
|
this.config = config.Clone();
|
||||||
this.registers = registers;
|
this.registers = registers;
|
||||||
baseAddress = config.GetProperty("BaseAddress").GetInt32();
|
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)
|
public static BaseMonitoringUnit Create(JsonElement config, RegistersContainer registers)
|
||||||
{
|
{
|
||||||
|
|||||||
+69
-21
@@ -1,10 +1,12 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.CommandLine;
|
using System.CommandLine;
|
||||||
using System.CommandLine.Invocation;
|
using System.CommandLine.Invocation;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ namespace Barsik
|
|||||||
{
|
{
|
||||||
private static RegistersContainer registers;
|
private static RegistersContainer registers;
|
||||||
private static List<BaseMonitoringUnit> units;
|
private static List<BaseMonitoringUnit> units;
|
||||||
|
private static JsonDocument configJson;
|
||||||
|
|
||||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
@@ -27,42 +30,87 @@ namespace Barsik
|
|||||||
};
|
};
|
||||||
runCommand.Handler = CommandHandler.Create<string>(RunService);
|
runCommand.Handler = CommandHandler.Create<string>(RunService);
|
||||||
rootCommand.AddCommand(runCommand);
|
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();
|
rootCommand.InvokeAsync(args).Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
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>();
|
|
||||||
|
|
||||||
|
private static JsonDocument LoadConfig(string config)
|
||||||
|
{
|
||||||
if (string.IsNullOrEmpty(config))
|
if (string.IsNullOrEmpty(config))
|
||||||
{
|
{
|
||||||
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
string assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
config = Path.Combine(assemblyFolder, "barsik.json");
|
config = Path.Combine(assemblyFolder, "barsik.json");
|
||||||
}
|
}
|
||||||
string configStr = File.ReadAllText(config);
|
string configStr = File.ReadAllText(config);
|
||||||
int port = 0;
|
return JsonDocument.Parse(configStr);
|
||||||
using (JsonDocument doc = 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 root = doc.RootElement;
|
var unit = BaseMonitoringUnit.Create(unitElement, registers);
|
||||||
port = root.GetProperty("Port").GetInt32();
|
if (unit != null)
|
||||||
foreach (var unitElement in root.GetProperty("Units").EnumerateArray())
|
|
||||||
{
|
{
|
||||||
var unit = BaseMonitoringUnit.Create(unitElement, registers);
|
units.Add(unit);
|
||||||
if (unit != null)
|
|
||||||
{
|
|
||||||
units.Add(unit);
|
|
||||||
Thread unitThread = new Thread(new ThreadStart(unit.Run));
|
|
||||||
unitThread.Start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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");
|
||||||
|
|
||||||
|
configJson = LoadConfig(config);
|
||||||
|
units = LoadUnits(configJson);
|
||||||
|
foreach (var unit in units)
|
||||||
|
{
|
||||||
|
Thread unitThread = new Thread(new ThreadStart(unit.Run));
|
||||||
|
unitThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
logger.Info("Configuration loaded, we have " + units.Count + " units");
|
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();
|
server.Run();
|
||||||
logger.Info("Exiting");
|
logger.Info("Exiting");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
<Configuration>Release</Configuration>
|
<Configuration>Release</Configuration>
|
||||||
<Platform>Any CPU</Platform>
|
<Platform>Any CPU</Platform>
|
||||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<PublishDir>bin\Debug\netcoreapp2.1\publish\</PublishDir>
|
<PublishDir>bin\Publish</PublishDir>
|
||||||
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
<SelfContained>false</SelfContained>
|
<SelfContained>false</SelfContained>
|
||||||
<_IsPortable>true</_IsPortable>
|
<_IsPortable>true</_IsPortable>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -11,15 +12,16 @@ namespace Barsik
|
|||||||
class SensorsMonitoringUnit : BaseMonitoringUnit
|
class SensorsMonitoringUnit : BaseMonitoringUnit
|
||||||
{
|
{
|
||||||
const string CORE_STR = "Core{0} Temp:";
|
const string CORE_STR = "Core{0} Temp:";
|
||||||
|
const float MULTIPLIER = 100;
|
||||||
|
int cores;
|
||||||
|
|
||||||
public SensorsMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers)
|
public SensorsMonitoringUnit(JsonElement config, RegistersContainer registers) : base(config, registers)
|
||||||
{
|
{
|
||||||
|
cores = config.GetProperty("Cores").GetInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Run()
|
public override void Run()
|
||||||
{
|
{
|
||||||
int cores = config.GetProperty("Cores").GetInt32();
|
|
||||||
var multiplier = config.GetProperty("Multiplier").GetDouble();
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
|
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("sensors");
|
||||||
@@ -60,7 +62,7 @@ namespace Barsik
|
|||||||
// fill register data starting from baseAddress
|
// fill register data starting from baseAddress
|
||||||
for (int i = 0; i < cores; i++)
|
for (int i = 0; i < cores; i++)
|
||||||
{
|
{
|
||||||
registers[baseAddress + i] = (int)(t[i] * multiplier);
|
registers[baseAddress + i] = (int)(t[i] * MULTIPLIER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Thread.Sleep(2000);
|
Thread.Sleep(2000);
|
||||||
@@ -84,5 +86,33 @@ namespace Barsik
|
|||||||
float.TryParse(v.Substring(pos, pos2 - pos), out res);
|
float.TryParse(v.Substring(pos, pos2 - pos), out res);
|
||||||
return 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
@@ -1,11 +1,12 @@
|
|||||||
{
|
{
|
||||||
|
"Name": "My_Server",
|
||||||
|
"IP": "192.168.0.5",
|
||||||
"Port": 4500,
|
"Port": 4500,
|
||||||
"Units": [
|
"Units": [
|
||||||
{
|
{
|
||||||
"Name": "CPU",
|
"Name": "CPU",
|
||||||
"Type": "Sensors",
|
"Type": "Sensors",
|
||||||
"BaseAddress": 1,
|
"BaseAddress": 1,
|
||||||
"Multiplier": 100,
|
|
||||||
"Cores": 2
|
"Cores": 2
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ Description=Barsik monitoring service
|
|||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=dotnet /root/barsik/Barsik.dll
|
ExecStart=/usr/bin/dotnet /root/barsik/Barsik.dll run
|
||||||
User=root
|
User=root
|
||||||
Group=root
|
Group=root
|
||||||
RuntimeDirectory=/root/barsik
|
RuntimeDirectory=/root/barsik
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
(function(i) {
|
||||||
|
return i / 100;
|
||||||
|
})(input)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
(function(i) {
|
||||||
|
return i * 100;
|
||||||
|
})(input)
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Transformations should be put into `/opt/openhab2/conf/transform` to work.
|
||||||
|
|
||||||
|
Some of monitoring units use them in configuration.
|
||||||
Reference in New Issue
Block a user