diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln
index 64acaf80f..beaac246d 100644
--- a/csharp/InnovEnergy.sln
+++ b/csharp/InnovEnergy.sln
@@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Lib\Logging\Logg
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Adam6360D", "Lib\Devices\Adam6360D\Adam6360D.csproj", "{A3C79247-4CAA-44BE-921E-7285AB39E71F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IEM3kGridMeter", "Lib\Devices\IEM3kGridMeter\IEM3kGridMeter.csproj", "{1391165D-51F1-45B4-8B7F-042A20AA0277}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -190,6 +192,10 @@ Global
{A3C79247-4CAA-44BE-921E-7285AB39E71F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3C79247-4CAA-44BE-921E-7285AB39E71F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3C79247-4CAA-44BE-921E-7285AB39E71F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1391165D-51F1-45B4-8B7F-042A20AA0277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1391165D-51F1-45B4-8B7F-042A20AA0277}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1391165D-51F1-45B4-8B7F-042A20AA0277}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1391165D-51F1-45B4-8B7F-042A20AA0277}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A}
@@ -223,5 +229,6 @@ Global
{B816BB44-E97E-4E02-B80A-BEDB5B923A96} = {DDDBEFD0-5DEA-4C7C-A9F2-FDB4636CF092}
{1A56992B-CB72-490F-99A4-DF1186BA3A18} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854}
{A3C79247-4CAA-44BE-921E-7285AB39E71F} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
+ {1391165D-51F1-45B4-8B7F-042A20AA0277} = {4931A385-24DC-4E78-BFF4-356F8D6D5183}
EndGlobalSection
EndGlobal
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/Doc/Acti 9 iEM3000_A9MEM3255.pdf b/csharp/Lib/Devices/IEM3kGridMeter/Doc/Acti 9 iEM3000_A9MEM3255.pdf
new file mode 100644
index 000000000..fc758ccd2
Binary files /dev/null and b/csharp/Lib/Devices/IEM3kGridMeter/Doc/Acti 9 iEM3000_A9MEM3255.pdf differ
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/Doc/DOCA0005EN-13.pdf b/csharp/Lib/Devices/IEM3kGridMeter/Doc/DOCA0005EN-13.pdf
new file mode 100644
index 000000000..3d954f8cd
Binary files /dev/null and b/csharp/Lib/Devices/IEM3kGridMeter/Doc/DOCA0005EN-13.pdf differ
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/Doc/NHA15801-06.pdf b/csharp/Lib/Devices/IEM3kGridMeter/Doc/NHA15801-06.pdf
new file mode 100644
index 000000000..9da2ba2a5
Binary files /dev/null and b/csharp/Lib/Devices/IEM3kGridMeter/Doc/NHA15801-06.pdf differ
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeter.csproj b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeter.csproj
new file mode 100644
index 000000000..622823c62
--- /dev/null
+++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeter.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+ InnovEnergy.Lib.Devices.IEM3kGridMeter
+
+
+
+
+
+
+
+
+
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs
new file mode 100644
index 000000000..de9e04b62
--- /dev/null
+++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs
@@ -0,0 +1,50 @@
+using InnovEnergy.Lib.Protocols.Modbus.Channels;
+using InnovEnergy.Lib.Protocols.Modbus.Clients;
+using InnovEnergy.Lib.Protocols.Modbus.Slaves;
+using InnovEnergy.Lib.Utils;
+
+namespace InnovEnergy.Lib.Devices.IEM3kGridMeter;
+
+public class Iem3KGridMeterDevice: ModbusDevice
+{
+ 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))
+ {
+ }
+
+ public Iem3KGridMeterDevice(ModbusClient client) : base(client)
+ {
+ }
+
+
+ public new Iem3KGridMeterRegisters? Read()
+ {
+ try
+ {
+ return base.Read();
+ }
+ catch
+ {
+ // TODO: Log
+ $"Failed to read data from {nameof(Iem3KGridMeterDevice)}".WriteLine();
+ return null;
+ }
+ }
+
+
+ public new void Write(Iem3KGridMeterRegisters registers)
+ {
+ try
+ {
+ base.Write(registers);
+ }
+ catch
+ {
+ // TODO: Log
+ $"Failed to write data to {nameof(Iem3KGridMeterDevice)}".WriteLine();
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs
new file mode 100644
index 000000000..19fe9907a
--- /dev/null
+++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs
@@ -0,0 +1,73 @@
+using InnovEnergy.Lib.Protocols.Modbus.Reflection.Attributes;
+using InnovEnergy.Lib.StatusApi.DeviceTypes;
+using InnovEnergy.Lib.Units.Composite;
+
+#pragma warning disable CS0649
+
+namespace InnovEnergy.Lib.Devices.IEM3kGridMeter;
+
+using Float32 = Single;
+
+
+[AddressOffset(-2)] // why?
+public class Iem3KGridMeterRegisters : IAc3Meter
+{
+
+ // TODO
+ // The registers below are kept as example (from EmuMeter)
+ // replace with actual registers from datasheet
+
+ [HoldingRegister(9002)] private Float32 _ActivePowerL1;
+ [HoldingRegister(9004)] private Float32 _ActivePowerL2;
+ [HoldingRegister(9006)] private Float32 _ActivePowerL3;
+
+ [HoldingRegister(9012)] private Float32 _ReactivePowerL1;
+ [HoldingRegister(9014)] private Float32 _ReactivePowerL2;
+ [HoldingRegister(9016)] private Float32 _ReactivePowerL3;
+
+ [HoldingRegister(9022)] private Float32 _ApparentPowerL1;
+ [HoldingRegister(9024)] private Float32 _ApparentPowerL2;
+ [HoldingRegister(9026)] private Float32 _ApparentPowerL3;
+
+ [HoldingRegister(9102)] private Float32 _CurrentL1;
+ [HoldingRegister(9104)] private Float32 _CurrentL2;
+ [HoldingRegister(9106)] private Float32 _CurrentL3;
+
+ [HoldingRegister(9200)] private Float32 _VoltageL1N;
+ [HoldingRegister(9202)] private Float32 _VoltageL2N;
+ [HoldingRegister(9204)] private Float32 _VoltageL3N;
+
+ [HoldingRegister(9310)] private Float32 _Frequency;
+
+ public Ac3Bus Ac => Ac3Bus.FromPhasesAndFrequency
+ (
+ l1: AcPhase.FromVoltageCurrentActiveReactiveApparent
+ (
+ _VoltageL1N,
+ _CurrentL1,
+ _ActivePowerL1,
+ _ReactivePowerL1,
+ _ApparentPowerL1
+ ),
+ l2: AcPhase.FromVoltageCurrentActiveReactiveApparent
+ (
+ _VoltageL2N,
+ _CurrentL2,
+ _ActivePowerL2,
+ _ReactivePowerL2,
+ _ApparentPowerL2
+ ),
+ l3: AcPhase.FromVoltageCurrentActiveReactiveApparent
+ (
+ _VoltageL3N,
+ _CurrentL3,
+ _ActivePowerL3,
+ _ReactivePowerL3,
+ _ApparentPowerL3
+ ),
+ frequency: _Frequency
+ );
+}
+
+
+