Addf schnieder meter library and app
This commit is contained in:
parent
6dc07900eb
commit
382043b79c
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Import Project="../../InnovEnergy.Lib.props" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>InnovEnergy.Lib.Devices.IEM3kGridMeter</RootNamespace>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../../Utils/Utils.csproj" />
|
||||||
|
<ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" />
|
||||||
|
<ProjectReference Include="../../StatusApi/StatusApi.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,149 @@
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using CliWrap;
|
||||||
|
using CliWrap.Buffered;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SchniederDriver;
|
||||||
|
|
||||||
|
public readonly struct Nic
|
||||||
|
{
|
||||||
|
private static Command IpCommand { get; } = Cli
|
||||||
|
.Wrap("/sbin/ip")
|
||||||
|
.WithValidation(CommandResultValidation.None);
|
||||||
|
|
||||||
|
private readonly JsonNode _Node;
|
||||||
|
|
||||||
|
private Nic(JsonNode node)
|
||||||
|
{
|
||||||
|
_Node = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean IsEthernet
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _Node["link_type"]!.GetValue<String>() == "ether";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean IsUp
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// ReSharper disable once StringLiteralTypo
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _Node["operstate"]!.GetValue<String>() == "UP";
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<String> Ip4Addresses
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// ReSharper disable once StringLiteralTypo
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _Node["addr_info"]!
|
||||||
|
.AsArray()
|
||||||
|
.TryWhere(n => n!["family"]!.GetValue<String>() == "inet")
|
||||||
|
.TrySelect(n => n!["local"]!.GetValue<String>())
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Array.Empty<String>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// ReSharper disable once StringLiteralTypo
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return _Node["ifname"]!.GetValue<String>();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return "<NO_NAME>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<Boolean> AddPointToPoint(String sourceAddress, String destinationAddress)
|
||||||
|
{
|
||||||
|
var result = await IpCommand
|
||||||
|
.WithArguments($"address add local {sourceAddress} peer {destinationAddress} dev {Name}")
|
||||||
|
.ExecuteAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Boolean> RemoveAddress(String address)
|
||||||
|
{
|
||||||
|
var result = await IpCommand
|
||||||
|
.WithArguments($"address del {address} dev {Name}")
|
||||||
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<Boolean> AddRoute(String route)
|
||||||
|
{
|
||||||
|
var result = await IpCommand
|
||||||
|
.WithArguments($"route add {route} dev {Name}")
|
||||||
|
.ExecuteAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Boolean> RemoveRoute(String route)
|
||||||
|
{
|
||||||
|
var result = await IpCommand
|
||||||
|
.WithArguments($"route del {route} dev {Name}")
|
||||||
|
.ExecuteAsync();
|
||||||
|
|
||||||
|
return result.ExitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async Task<IReadOnlyList<Nic>> GetNetworkInterfaces()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await IpCommand
|
||||||
|
.WithArguments("-details -pretty -json address")
|
||||||
|
.ExecuteBufferedAsync();
|
||||||
|
|
||||||
|
return JsonNode
|
||||||
|
.Parse(result.StandardOutput)!
|
||||||
|
.AsArray()
|
||||||
|
.Where(n => n != null)
|
||||||
|
.Select(n => new Nic(n!))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return Array.Empty<Nic>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
using InnovEnergy.App.SchniederDriver;
|
||||||
|
using InnovEnergy.Lib.Protocols.DBus;
|
||||||
|
using InnovEnergy.Lib.Utils;
|
||||||
|
using InnovEnergy.Lib.Utils.Net;
|
||||||
|
|
||||||
|
|
||||||
|
// dotnet publish EmuMeter.csproj -c Release -r linux-arm -p:PublishSingleFile=true --self-contained true && \
|
||||||
|
// rsync -av bin/Release/net6.0/linux-arm/publish/ root@10.2.1.6:/home/root/emu && clear && \
|
||||||
|
// ssh root@10.2.1.6 /home/root/emu/EmuMeter
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine("Starting Schnieder Driver " + Config.Version);
|
||||||
|
|
||||||
|
var networkInterfaces = await Nic.GetNetworkInterfaces();
|
||||||
|
|
||||||
|
var candidates = networkInterfaces.Where(n => n.IsUp &&
|
||||||
|
n.IsEthernet &&
|
||||||
|
(!n.Ip4Addresses.Any() || n.Ip4Addresses.Contains(Config.OwnAddress)));
|
||||||
|
|
||||||
|
foreach (var nic in candidates)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Found new network interface: {nic.Name}");
|
||||||
|
|
||||||
|
if (!nic.Ip4Addresses.Contains(Config.OwnAddress))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Configuring Point-to-Point connection on {nic.Name}");
|
||||||
|
Console.WriteLine($" own address: {Config.OwnAddress}");
|
||||||
|
Console.WriteLine($" peer address: {Config.PeerAddress}");
|
||||||
|
|
||||||
|
var success = await nic.AddPointToPoint($"{Config.OwnAddress}/16", $"{Config.PeerAddress}/16");
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Failed to configure network interface: {nic.Name}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"Pinging peer @ {Config.PeerAddress}");
|
||||||
|
|
||||||
|
var ping = await Config.PeerAddress.Ping();
|
||||||
|
|
||||||
|
if (ping)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Got answer from {Config.PeerAddress}");
|
||||||
|
var ex = await SchniederMeterDriver.Run($"{Config.PeerAddress}:{Config.PeerPort}", Bus.System);
|
||||||
|
|
||||||
|
Console.WriteLine($"{nameof(SchniederMeterDriver)} FAILED with\n{ex}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"No answer from {Config.PeerAddress}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.Write($"Removing Point-to-Point connection on {nic.Name} ...");
|
||||||
|
var removed = await nic.RemoveAddress($"{Config.OwnAddress}/16");
|
||||||
|
Console.WriteLine(removed ? "done" : "failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Stopping EmuMeter Driver");
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using InnovEnergy.Lib.Devices.IEM3kGridMeter;
|
||||||
|
using InnovEnergy.Lib.Protocols.DBus;
|
||||||
|
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||||
|
using InnovEnergy.Lib.Utils;
|
||||||
|
using InnovEnergy.Lib.Victron.VeDBus;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SchniederDriver;
|
||||||
|
|
||||||
|
public static class SchniederMeterDriver
|
||||||
|
{
|
||||||
|
public static Task<Exception> Run(String hostName, Bus dbusAddress)
|
||||||
|
{
|
||||||
|
return Run(hostName, ModbusTcpClient.DefaultPort, dbusAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Exception> Run(String hostName, UInt16 port, Bus dbusAddress)
|
||||||
|
{
|
||||||
|
// var ep = new UnixDomainSocketEndPoint("/home/eef/graber_dbus.sock");
|
||||||
|
// var auth = AuthenticationMethod.ExternalAsRoot();
|
||||||
|
// dbusAddress = new Bus(ep, auth);
|
||||||
|
|
||||||
|
var schnieder = new Iem3KGridMeterDevice(hostName, port, Config.ModbusNodeId);
|
||||||
|
|
||||||
|
|
||||||
|
var schniederStatus = Observable
|
||||||
|
.Interval(Config.UpdatePeriod)
|
||||||
|
.Select(_ => schnieder.Read())
|
||||||
|
.Publish();
|
||||||
|
|
||||||
|
var poller = schniederStatus.Connect();
|
||||||
|
|
||||||
|
var properties = Config.DefaultProperties;
|
||||||
|
|
||||||
|
var signals = Config
|
||||||
|
.Signals
|
||||||
|
.Select(signal => schniederStatus.Select(signal.ToVeProperty))
|
||||||
|
.Merge()
|
||||||
|
.Do(p => properties.Set(p));
|
||||||
|
|
||||||
|
// TODO: remove when possible
|
||||||
|
// Apparently some VE services need to be periodically reminded that
|
||||||
|
// this service is /Connected
|
||||||
|
schniederStatus.Subscribe(_ => properties.Set("/Connected", 1));
|
||||||
|
|
||||||
|
// Wait until status is read once to make sure all
|
||||||
|
// properties are set when we go onto the bus.
|
||||||
|
var dbus = schniederStatus
|
||||||
|
.Skip(1)
|
||||||
|
.Take(1)
|
||||||
|
.SelectMany(_ => PublishPropertiesOnDBus(properties, dbusAddress));
|
||||||
|
|
||||||
|
return await signals
|
||||||
|
.MergeErrors(dbus)
|
||||||
|
.Finally(poller.Dispose)
|
||||||
|
.SelectErrors();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Task<Exception> PublishPropertiesOnDBus(VeProperties properties, Bus bus)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Connecting to DBus {bus}");
|
||||||
|
return properties.PublishOnDBus(bus, Config.BusName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RootNamespace>InnovEnergy.App.SchniederDriver</RootNamespace>
|
||||||
|
<AssemblyName>SchniederDriver</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="../InnovEnergy.App.props" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../../Lib/Devices/EmuMeter/EmuMeter.csproj" />
|
||||||
|
<ProjectReference Include="../../Lib/Protocols/DBus/DBus.csproj" />
|
||||||
|
<ProjectReference Include="../../Lib/Protocols/Modbus/Modbus.csproj" />
|
||||||
|
<ProjectReference Include="../../Lib/Utils/Utils.csproj" />
|
||||||
|
<ProjectReference Include="../../Lib/Victron/VeDBus/VeDBus.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Lib\Devices\IEM3kGridMeter\IEM3kGridMeter.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CliWrap" Version="3.6.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,16 @@
|
||||||
|
using InnovEnergy.Lib.Devices.EmuMeter;
|
||||||
|
using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes;
|
||||||
|
using InnovEnergy.Lib.Victron.VeDBus;
|
||||||
|
|
||||||
|
namespace InnovEnergy.App.SchniederDriver;
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Does not compile
|
||||||
|
public record Signal(Func<EmuMeterStatus, Object> Source, ObjectPath Path, String Format = "")
|
||||||
|
{
|
||||||
|
public VeProperty ToVeProperty(EmuMeterStatus status)
|
||||||
|
{
|
||||||
|
var value = Source(status);
|
||||||
|
return new VeProperty(Path, value, String.Format($"{{0:{Format}}}", value));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
namespace InnovEnergy.App.SchniederDriver;
|
||||||
|
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
public static IEnumerable<T> TryWhere<T>(this IEnumerable<T> src, Func<T, Boolean> predicate)
|
||||||
|
{
|
||||||
|
foreach (var e in src)
|
||||||
|
{
|
||||||
|
var ok = false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ok = predicate(e);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
yield return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<R> TrySelect<T,R>(this IEnumerable<T> src, Func<T, R> map)
|
||||||
|
{
|
||||||
|
foreach (var e in src)
|
||||||
|
{
|
||||||
|
var ok = false;
|
||||||
|
var result = default(R);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = map(e);
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
yield return result!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
exec 2>&1
|
||||||
|
exec multilog t s25000 n4 /var/log/EmuMeter
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
exec 2>&1
|
||||||
|
exec softlimit -d 100000000 -s 1000000 -a 100000000 /opt/innovenergy/EmuMeter/EmuMeter
|
|
@ -87,6 +87,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doepke", "Lib\Devices\Doepk
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amax5070", "Lib\Devices\Amax5070\Amax5070.csproj", "{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amax5070", "Lib\Devices\Amax5070\Amax5070.csproj", "{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sofar", "App\Sofar\Sofar.csproj", "{6B98449D-BF75-415A-8893-E49518F9307D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofarInverter", "Lib\Devices\SofarInverter\SofarInverter.csproj", "{2C7F3D89-402B-43CB-988E-8D2D853BEF44}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchniederMeterDriver", "App\SchniederMeterDriver\SchniederMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}"
|
||||||
|
EndProject
|
||||||
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -226,6 +232,18 @@ Global
|
||||||
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6B98449D-BF75-415A-8893-E49518F9307D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B98449D-BF75-415A-8893-E49518F9307D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B98449D-BF75-415A-8893-E49518F9307D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6B98449D-BF75-415A-8893-E49518F9307D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
|
@ -265,5 +283,8 @@ Global
|
||||||
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
{73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
|
||||||
{C2B14CD4-1BCA-4933-96D9-92F40EACD2B9} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
{C2B14CD4-1BCA-4933-96D9-92F40EACD2B9} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||||
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||||
|
{6B98449D-BF75-415A-8893-E49518F9307D} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
|
{2C7F3D89-402B-43CB-988E-8D2D853BEF44} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
|
||||||
|
{2E7E7657-3A53-4B62-8927-FE9A082B81DE} = {145597B4-3E30-45E6-9F72-4DD43194539A}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -10,8 +10,8 @@ public class Iem3KGridMeterDevice: ModbusDevice<Iem3KGridMeterRegisters>
|
||||||
public Iem3KGridMeterDevice(String hostname, UInt16 port = 502, Byte slaveId = 1) : this(new TcpChannel(hostname, port), slaveId)
|
public Iem3KGridMeterDevice(String hostname, UInt16 port = 502, Byte slaveId = 1) : this(new TcpChannel(hostname, port), slaveId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iem3KGridMeterDevice(Channel channel, Byte slaveId = 1) : base(new ModbusTcpClient(channel, slaveId))
|
private Iem3KGridMeterDevice(Channel channel, Byte slaveId = 1) : base(new ModbusTcpClient(channel, slaveId))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,4 +47,6 @@ public class Iem3KGridMeterDevice: ModbusDevice<Iem3KGridMeterRegisters>
|
||||||
$"Failed to write data to {nameof(Iem3KGridMeterDevice)}".WriteLine();
|
$"Failed to write data to {nameof(Iem3KGridMeterDevice)}".WriteLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,25 +12,25 @@ using Float32 = Single;
|
||||||
|
|
||||||
|
|
||||||
[AddressOffset(-2)] // why?
|
[AddressOffset(-2)] // why?
|
||||||
public class Iem3KGridMeterRegisters : IAc3Meter
|
public class Iem3KGridMeterRegisters //: IAc3Meter
|
||||||
{
|
{
|
||||||
private const Float32 ZeroBecauseReactivePowerNotSupported = 0;
|
private const Float32 ZeroBecauseReactivePowerNotSupported = 0;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
[HoldingRegister<Float32>(3054)] private Float32 _ActivePowerL1;
|
[HoldingRegister<Float32>(3054)] public Float32 ActivePowerL1;
|
||||||
[HoldingRegister<Float32>(3056)] private Float32 _ActivePowerL2;
|
[HoldingRegister<Float32>(3056)] public Float32 ActivePowerL2;
|
||||||
[HoldingRegister<Float32>(3058)] private Float32 _ActivePowerL3;
|
[HoldingRegister<Float32>(3058)] public Float32 ActivePowerL3;
|
||||||
|
|
||||||
[HoldingRegister<Float32>(3000)] private Float32 _CurrentL1;
|
//[HoldingRegister<Float32>(3000)] private Float32 _CurrentL1;
|
||||||
[HoldingRegister<Float32>(3002)] private Float32 _CurrentL2;
|
//[HoldingRegister<Float32>(3002)] private Float32 _CurrentL2;
|
||||||
[HoldingRegister<Float32>(3004)] private Float32 _CurrentL3;
|
//[HoldingRegister<Float32>(3004)] private Float32 _CurrentL3;
|
||||||
|
//
|
||||||
[HoldingRegister<Float32>(3028)] private Float32 _VoltageL1N;
|
//[HoldingRegister<Float32>(3028)] private Float32 _VoltageL1N;
|
||||||
[HoldingRegister<Float32>(3030)] private Float32 _VoltageL2N;
|
//[HoldingRegister<Float32>(3030)] private Float32 _VoltageL2N;
|
||||||
[HoldingRegister<Float32>(3032)] private Float32 _VoltageL3N;
|
//[HoldingRegister<Float32>(3032)] private Float32 _VoltageL3N;
|
||||||
|
//
|
||||||
[HoldingRegister<Float32>(3110)] private Float32 _Frequency;
|
//[HoldingRegister<Float32>(3110)] private Float32 _Frequency;
|
||||||
|
|
||||||
//[HoldingRegister<Float32>(9012)] private Float32 _ReactivePowerL1;
|
//[HoldingRegister<Float32>(9012)] private Float32 _ReactivePowerL1;
|
||||||
//[HoldingRegister<Float32>(9014)] private Float32 _ReactivePowerL2;
|
//[HoldingRegister<Float32>(9014)] private Float32 _ReactivePowerL2;
|
||||||
|
@ -45,7 +45,7 @@ public class Iem3KGridMeterRegisters : IAc3Meter
|
||||||
//[HoldingRegister<Float32>(9026)] private Float32 _ApparentPowerL3;
|
//[HoldingRegister<Float32>(9026)] private Float32 _ApparentPowerL3;
|
||||||
|
|
||||||
|
|
||||||
public Ac3Bus Ac => new Ac3Bus
|
/*public Ac3Bus Ac => new Ac3Bus
|
||||||
{
|
{
|
||||||
L1 = new ()
|
L1 = new ()
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,9 @@ public class Iem3KGridMeterRegisters : IAc3Meter
|
||||||
Phi = Atan2(ZeroBecauseReactivePowerNotSupported, _ActivePowerL3)
|
Phi = Atan2(ZeroBecauseReactivePowerNotSupported, _ActivePowerL3)
|
||||||
},
|
},
|
||||||
Frequency = _Frequency
|
Frequency = _Frequency
|
||||||
};
|
};*/
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue