make AMPT use updated Modbus Lib
This commit is contained in:
parent
0ac7773ac0
commit
a2c0674ecb
|
@ -1,9 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configurations>Debug;Release;Release-Server</Configurations>
|
||||
<Platforms>AnyCPU;linux-arm</Platforms>
|
||||
</PropertyGroup>
|
||||
<Import Project="../../InnovEnergy.Lib.props" />
|
||||
<!-- <Import Project="../../InnovEnergy.Lib.props"/>-->
|
||||
|
||||
<Import Project="../../../App/InnovEnergy.App.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../Protocols/Modbus/Modbus.csproj" />
|
||||
|
|
|
@ -1,118 +1,90 @@
|
|||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Connections;
|
||||
using InnovEnergy.Lib.Units.Composite;
|
||||
using static DecimalMath.DecimalEx;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
public class AmptCommunicationUnit
|
||||
{
|
||||
private ModbusTcpClient? Modbus { get; set; }
|
||||
|
||||
private const UInt16 RegistersPerDevice = 16;
|
||||
private const UInt16 FirstDeviceOffset = 85;
|
||||
|
||||
public String Hostname { get; }
|
||||
public UInt16 Port { get; }
|
||||
public Byte SlaveAddress { get; }
|
||||
|
||||
public AmptCommunicationUnit(String hostname, UInt16 port = 502, Byte slaveAddress = 1)
|
||||
{
|
||||
Hostname = hostname;
|
||||
Port = port;
|
||||
SlaveAddress = slaveAddress;
|
||||
}
|
||||
|
||||
public AmptCommunicationUnitStatus? ReadStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
OpenConnection();
|
||||
return TryReadStatus();
|
||||
}
|
||||
catch
|
||||
{
|
||||
CloseConnection();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
Modbus?.CloseConnection();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Modbus = null;
|
||||
}
|
||||
|
||||
private void OpenConnection()
|
||||
{
|
||||
if (Modbus is null)
|
||||
{
|
||||
var connection = new ModbusTcpConnection(Hostname, Port);
|
||||
Modbus = new ModbusTcpClient(connection, SlaveAddress);
|
||||
}
|
||||
}
|
||||
|
||||
private AmptCommunicationUnitStatus TryReadStatus()
|
||||
{
|
||||
var r = Modbus!.ReadHoldingRegisters(1, 116);
|
||||
|
||||
var currentFactor = Pow(10.0m, r.GetInt16(73));
|
||||
var voltageFactor = Pow(10.0m, r.GetInt16(74));
|
||||
var energyFactor = Pow(10.0m, r.GetInt16(76) + 3); // +3 => converted from Wh to kWh
|
||||
var nbrOfDevices = r.GetUInt16(78);
|
||||
|
||||
var devices = Enumerable
|
||||
.Range(0, nbrOfDevices)
|
||||
.Select(ReadDeviceStatus)
|
||||
.ToList();
|
||||
|
||||
return new AmptCommunicationUnitStatus
|
||||
{
|
||||
Sid = r.GetUInt32(1),
|
||||
IdSunSpec = r.GetUInt16(3),
|
||||
Manufacturer = r.GetString(5, 16),
|
||||
Model = r.GetString(21, 16),
|
||||
Version = r.GetString(45, 8),
|
||||
SerialNumber = r.GetString(53, 16),
|
||||
DeviceAddress = r.GetInt16(69),
|
||||
IdVendor = r.GetUInt16(71),
|
||||
Devices = devices
|
||||
};
|
||||
|
||||
AmptStatus ReadDeviceStatus(Int32 deviceNumber)
|
||||
{
|
||||
var baseAddress = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address
|
||||
|
||||
return new AmptStatus
|
||||
{
|
||||
Dc = new DcBus
|
||||
{
|
||||
Voltage = r.GetUInt32((UInt16)(baseAddress + 6)) * voltageFactor,
|
||||
Current = r.GetUInt16((UInt16)(baseAddress + 5)) * currentFactor
|
||||
},
|
||||
Strings = new DcBus[]
|
||||
{
|
||||
new()
|
||||
{
|
||||
Voltage = r.GetUInt32((UInt16)(baseAddress + 8)) * voltageFactor,
|
||||
Current = r.GetUInt16((UInt16)(baseAddress + 14)) * currentFactor
|
||||
},
|
||||
new()
|
||||
{
|
||||
Voltage = r.GetUInt32((UInt16)(baseAddress + 9)) * voltageFactor,
|
||||
Current = r.GetUInt16((UInt16)(baseAddress + 15)) * currentFactor
|
||||
}
|
||||
},
|
||||
ProductionToday = r.GetUInt32((UInt16)(baseAddress + 12)) * energyFactor,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||
// using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||
// using InnovEnergy.Lib.Protocols.Modbus.Conversions;
|
||||
// using InnovEnergy.Lib.Protocols.Modbus.Slaves;
|
||||
// using InnovEnergy.Lib.Units.Composite;
|
||||
//
|
||||
// namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
//
|
||||
// public class AmptCommunicationUnit : ModbusDevice<CommunicationUnitRegisters>
|
||||
// {
|
||||
//
|
||||
// private const UInt16 RegistersPerDevice = 16;
|
||||
// private const UInt16 FirstDeviceOffset = 85;
|
||||
//
|
||||
//
|
||||
// public AmptCommunicationUnit(String hostname, UInt16 port = 502, Byte slaveAddress = 1) : this
|
||||
// (
|
||||
// channel: new TcpChannel(hostname, port),
|
||||
// slaveAddress
|
||||
// )
|
||||
// {}
|
||||
//
|
||||
//
|
||||
// public AmptCommunicationUnit(Channel channel, Byte slaveAddress) : this
|
||||
// (
|
||||
// client: new ModbusTcpClient(channel, slaveAddress)
|
||||
// )
|
||||
// {}
|
||||
//
|
||||
// public AmptCommunicationUnit(ModbusClient client) : base(client)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
//
|
||||
// private AmptCommunicationUnitStatus TryReadStatus()
|
||||
// {
|
||||
// var r = new ModbusRegisters(116, Modbus.ReadHoldingRegisters(1, 116).ToArray()) ; // TODO
|
||||
//
|
||||
// var currentFactor = Pow(10.0m, r.GetInt16(73));
|
||||
// var voltageFactor = Pow(10.0m, r.GetInt16(74));
|
||||
// var energyFactor = Pow(10.0m, r.GetInt16(76) + 3); // +3 => converted from Wh to kWh
|
||||
// var nbrOfDevices = r.GetUInt16(78);
|
||||
//
|
||||
// var devices = Enumerable
|
||||
// .Range(0, nbrOfDevices)
|
||||
// .Select(ReadDeviceStatus)
|
||||
// .ToList();
|
||||
//
|
||||
// return new AmptCommunicationUnitStatus
|
||||
// {
|
||||
// Sid = r.GetUInt32(1),
|
||||
// IdSunSpec = r.GetUInt16(3),
|
||||
// Manufacturer = r.GetString(5, 16),
|
||||
// Model = r.GetString(21, 16),
|
||||
// Version = r.GetString(45, 8),
|
||||
// SerialNumber = r.GetString(53, 16),
|
||||
// DeviceAddress = r.GetInt16(69),
|
||||
// IdVendor = r.GetUInt16(71),
|
||||
// Devices = devices
|
||||
// };
|
||||
//
|
||||
// AmptStatus ReadDeviceStatus(Int32 deviceNumber)
|
||||
// {
|
||||
// var baseAddress = (UInt16)(FirstDeviceOffset + deviceNumber * RegistersPerDevice); // base address
|
||||
//
|
||||
// return new AmptStatus
|
||||
// {
|
||||
// Dc = new DcBus
|
||||
// {
|
||||
// Voltage = r.GetUInt32((UInt16)(baseAddress + 6)) * voltageFactor,
|
||||
// Current = r.GetUInt16((UInt16)(baseAddress + 5)) * currentFactor
|
||||
// },
|
||||
// Strings = new DcBus[]
|
||||
// {
|
||||
// new()
|
||||
// {
|
||||
// Voltage = r.GetUInt32((UInt16)(baseAddress + 8)) * voltageFactor,
|
||||
// Current = r.GetUInt16((UInt16)(baseAddress + 14)) * currentFactor
|
||||
// },
|
||||
// new()
|
||||
// {
|
||||
// Voltage = r.GetUInt32((UInt16)(baseAddress + 9)) * voltageFactor,
|
||||
// Current = r.GetUInt16((UInt16)(baseAddress + 15)) * currentFactor
|
||||
// }
|
||||
// },
|
||||
// ProductionToday = r.GetUInt32((UInt16)(baseAddress + 12)) * energyFactor,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -1,6 +1,6 @@
|
|||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
public record AmptCommunicationUnitStatus
|
||||
public class AmptCommunicationUnitStatus
|
||||
{
|
||||
public UInt32 Sid { get; init; } // A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map
|
||||
public UInt16 IdSunSpec { get; init; } // A well-known value 1, uniquely identifies this as a SunSpec Common Model
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Slaves;
|
||||
using InnovEnergy.Lib.Units.Composite;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
public class AmptDevice
|
||||
{
|
||||
private readonly ModbusDevice<CommunicationUnitRegisters> _CommunicationUnit;
|
||||
private readonly IEnumerable<ModbusDevice<StringOptimizerRegisters>> _StringOptimizers;
|
||||
|
||||
public AmptDevice(ModbusClient modbusClient)
|
||||
{
|
||||
_CommunicationUnit = new ModbusDevice<CommunicationUnitRegisters>(modbusClient);
|
||||
_StringOptimizers = StringOptimizers(modbusClient);
|
||||
}
|
||||
|
||||
|
||||
public AmptStatus? Read()
|
||||
{
|
||||
var cuStatus = _CommunicationUnit.Read();
|
||||
|
||||
if (cuStatus.NumberOfStrings == 0)
|
||||
return default;
|
||||
|
||||
var rs = _StringOptimizers
|
||||
.Take(cuStatus.NumberOfStrings)
|
||||
.Select(so => so.Read())
|
||||
.ToArray(cuStatus.NumberOfStrings);
|
||||
|
||||
var busVoltage = rs.Average(r => r.Voltage);
|
||||
var busCurrent = rs.Sum(r => r.Current);
|
||||
var strings = rs.SelectMany(GetStrings).ToArray(rs.Length * 2);
|
||||
|
||||
return new AmptStatus
|
||||
(
|
||||
Dc : DcBus.FromVoltageCurrent(busVoltage, busCurrent),
|
||||
Strings: strings
|
||||
);
|
||||
}
|
||||
|
||||
private static IEnumerable<DcBus> GetStrings(StringOptimizerRegisters r)
|
||||
{
|
||||
yield return DcBus.FromVoltageCurrent(r.String1Voltage, r.String1Current);
|
||||
yield return DcBus.FromVoltageCurrent(r.String2Voltage, r.String2Current);
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<ModbusDevice<StringOptimizerRegisters>> StringOptimizers(ModbusClient modbusClient)
|
||||
{
|
||||
var cache = new List<ModbusDevice<StringOptimizerRegisters>>();
|
||||
|
||||
ModbusDevice<StringOptimizerRegisters> GetOptimizer(Int32 i)
|
||||
{
|
||||
if (i < cache.Count)
|
||||
return cache[i];
|
||||
|
||||
var modbusDevice = new ModbusDevice<StringOptimizerRegisters>(modbusClient, i * 16);
|
||||
return modbusDevice.Apply(cache.Add);
|
||||
}
|
||||
|
||||
return Enumerable
|
||||
.Range(0, Byte.MaxValue)
|
||||
.Select(GetOptimizer);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
using InnovEnergy.Lib.StatusApi;
|
||||
using InnovEnergy.Lib.Units;
|
||||
using InnovEnergy.Lib.StatusApi.DeviceTypes;
|
||||
using InnovEnergy.Lib.Units.Composite;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
public record AmptStatus : MpptStatus
|
||||
{
|
||||
public Energy ProductionToday { get; init; } // converted to kW in AmptCU class
|
||||
}
|
||||
public record AmptStatus(DcBus Dc, IReadOnlyList<DcBus> Strings) : IMppt;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
|
||||
|
||||
[OneBasedAddressing]
|
||||
public record CommunicationUnitRegisters
|
||||
{
|
||||
[HoldingRegister<Int16>(73)] public Int16 CurrentScaleFactor { get; private set; }
|
||||
[HoldingRegister<Int16>(74)] public Int16 VoltageScaleFactor { get; private set; }
|
||||
[HoldingRegister<Int16>(76)] public Int16 EnergyScaleFactor { get; private set; }
|
||||
|
||||
[HoldingRegister(78)] public UInt16 NumberOfStrings { get; private set; }
|
||||
}
|
|
@ -0,0 +1,412 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<title>Modbus Map</title>
|
||||
<style>
|
||||
* {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #565A5C;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.content {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
div.textblock {
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
width: 40%;
|
||||
position: relative;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
table.main {
|
||||
border: solid black 2px;
|
||||
border-spacing: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 6px;
|
||||
border: solid black 1px;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
tr.even {
|
||||
background: #EFEFEF;
|
||||
}
|
||||
|
||||
tr.odd {
|
||||
background: #DDDDDD;
|
||||
}
|
||||
|
||||
td.desc {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<br><br>
|
||||
<h2>Modbus Map</h2>
|
||||
<div class="textblock">
|
||||
<p>These Modbus maps are for your reference. The modbus service runs on port 502.</p>
|
||||
<p>Important note: The Ampt ModBus register map uses big endian values.</p>
|
||||
<p><a href="smdx_64050.xml">SunSpec SMDX File</a></p>
|
||||
</div>
|
||||
<br>
|
||||
<h2> SunSpec Registers </h2>
|
||||
<table class="main" style="width:70%">
|
||||
<tbody>
|
||||
<tr class="odd">
|
||||
<td><strong>Start Offset</strong></td>
|
||||
<td><strong>Size</strong></td>
|
||||
<td><strong>Name</strong></td>
|
||||
<td><strong>Type</strong></td>
|
||||
<td><strong>R/W</strong></td>
|
||||
<td><strong>Description</strong></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>SID</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">A well-known value 0x53756e53, uniquely identifies this as a SunSpec Modbus Map</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>3</td>
|
||||
<td>1</td>
|
||||
<td>ID</td>
|
||||
<td>uint16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">A well-known value 1, uniquely identifies this as a SunSpec Common Model</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>4</td>
|
||||
<td>1</td>
|
||||
<td>L</td>
|
||||
<td>uint16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Well-known # of 16-bit registers to follow: 66</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>5</td>
|
||||
<td>16</td>
|
||||
<td>Manufacturer</td>
|
||||
<td>string</td>
|
||||
<td>R</td>
|
||||
<td class="desc">A well-known value registered with SunSpec for compliance: "Ampt"</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>21</td>
|
||||
<td>16</td>
|
||||
<td>Model</td>
|
||||
<td>string</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Manufacturer specific value "Communication Unit"</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>37</td>
|
||||
<td>8</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>45</td>
|
||||
<td>8</td>
|
||||
<td>Version</td>
|
||||
<td>string</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Software Version</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>53</td>
|
||||
<td>16</td>
|
||||
<td>Serial Number</td>
|
||||
<td>string</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Manufacturer specific value</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>69</td>
|
||||
<td>1</td>
|
||||
<td>Device Address</td>
|
||||
<td>int16</td>
|
||||
<td>R/W</td>
|
||||
<td class="desc">Modbus Device ID</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>70</td>
|
||||
<td>1</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>71</td>
|
||||
<td>1</td>
|
||||
<td>ID</td>
|
||||
<td>uint16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Ampt SunSpec Vendor Code 64050</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>72</td>
|
||||
<td>1</td>
|
||||
<td>L</td>
|
||||
<td>uint16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Variable number of 16-bit registers to follow: 12 + N*16</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>73</td>
|
||||
<td>1</td>
|
||||
<td>DCA_SF</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Current scale factor</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>74</td>
|
||||
<td>1</td>
|
||||
<td>DCV_SF</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Voltage scale factor</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>75</td>
|
||||
<td>1</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>76</td>
|
||||
<td>1</td>
|
||||
<td>DCkWh_SF</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Energy Scale Factor</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>77</td>
|
||||
<td>1</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>78</td>
|
||||
<td>1</td>
|
||||
<td>N</td>
|
||||
<td>uint16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Number of strings</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>79</td>
|
||||
<td>6</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6"><strong>1</strong></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>85</td>
|
||||
<td>1</td>
|
||||
<td>String ID</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">The string number</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>86</td>
|
||||
<td>2</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>88</td>
|
||||
<td>2</td>
|
||||
<td>String data timestamp</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">The UTC timestamp of the measurements</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>90</td>
|
||||
<td>1</td>
|
||||
<td>OutDCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String output current in mA</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>91</td>
|
||||
<td>2</td>
|
||||
<td>OutDCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String output voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>93</td>
|
||||
<td>2</td>
|
||||
<td>In1DCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 1 voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>95</td>
|
||||
<td>2</td>
|
||||
<td>In2DCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 2 voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>97</td>
|
||||
<td>2</td>
|
||||
<td>DCWh</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Daily integrated string output energy in Wh</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>99</td>
|
||||
<td>1</td>
|
||||
<td>In1DCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 1 current in mA</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>100</td>
|
||||
<td>1</td>
|
||||
<td>In2DCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 2 current in mA</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6"><strong>2</strong></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>101</td>
|
||||
<td>1</td>
|
||||
<td>String ID</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">The string number</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>102</td>
|
||||
<td>2</td>
|
||||
<td><em>Reserved</em></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>104</td>
|
||||
<td>2</td>
|
||||
<td>String data timestamp</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">The UTC timestamp of the measurements</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>106</td>
|
||||
<td>1</td>
|
||||
<td>OutDCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String output current in mA</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>107</td>
|
||||
<td>2</td>
|
||||
<td>OutDCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String output voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>109</td>
|
||||
<td>2</td>
|
||||
<td>In1DCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 1 voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>111</td>
|
||||
<td>2</td>
|
||||
<td>In2DCV</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 2 voltage in mV</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>113</td>
|
||||
<td>2</td>
|
||||
<td>DCWh</td>
|
||||
<td>uint32</td>
|
||||
<td>R</td>
|
||||
<td class="desc">Daily integrated string output energy in Wh</td>
|
||||
</tr>
|
||||
<tr class="even">
|
||||
<td>115</td>
|
||||
<td>1</td>
|
||||
<td>In1DCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 1 current in mA</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td>116</td>
|
||||
<td>1</td>
|
||||
<td>In2DCA</td>
|
||||
<td>int16</td>
|
||||
<td>R</td>
|
||||
<td class="desc">String input 2 current in mA</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<br><br><br>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
using System.Text.Json;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Channels;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Clients;
|
||||
using InnovEnergy.Lib.Utils;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static Task Main(string[] args)
|
||||
{
|
||||
var ch = new TcpChannel("localhost", 5005);
|
||||
var cl = new ModbusTcpClient(ch, 1);
|
||||
var d = new AmptDevice(cl);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var x = d.Read();
|
||||
|
||||
var options = new JsonSerializerOptions{WriteIndented = true};
|
||||
(x, options).Apply(JsonSerializer.Serialize).WriteLine();
|
||||
|
||||
//Console.WriteLine(x);
|
||||
}
|
||||
|
||||
|
||||
//Console.WriteLine(x);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
|
||||
|
||||
namespace InnovEnergy.Lib.Devices.AMPT;
|
||||
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
|
||||
|
||||
[OneBasedAddressing][BigEndian]
|
||||
public record StringOptimizerRegisters
|
||||
{
|
||||
[HoldingRegister<UInt32>(88) ] public UInt32 Timestamp { get; private set; }
|
||||
|
||||
[HoldingRegister<Int16> (90, Scale = .001)] public Double Current { get; private set; }
|
||||
[HoldingRegister<UInt32>(91, Scale = .001)] public Double Voltage { get; private set; }
|
||||
|
||||
[HoldingRegister<UInt32>(93, Scale = .001)] public Double String1Voltage { get; private set; }
|
||||
[HoldingRegister<UInt32>(95, Scale = .001)] public Double String2Voltage { get; private set; }
|
||||
|
||||
[HoldingRegister<UInt32>(97)] public Double ProductionToday { get; private set; }
|
||||
|
||||
[HoldingRegister<Int16>(99, Scale = .001)] public Double String1Current { get; private set; }
|
||||
[HoldingRegister<Int16>(100, Scale = .001)] public Double String2Current { get; private set; }
|
||||
}
|
Loading…
Reference in New Issue