Skip to content

Commit 55afc7e

Browse files
committed
feat(em511): Add the driver with some functions
also added some tests, should run! Signed-off-by: Bobo Bäck Engström <bobo@id8-engineering.io>
1 parent 951badb commit 55afc7e

4 files changed

Lines changed: 153 additions & 5 deletions

File tree

src/em511/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
"""Hello package."""
2+
from .em511 import Em511
3+
24

35

46
def hello() -> str:

src/em511/em511.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
"""Driver class for EM511"""
2+
3+
class Em511:
4+
"""Em511 driver class"""
5+
6+
# ---------------------------------------------------------------------
7+
# Initialization & Connection
8+
# ---------------------------------------------------------------------
9+
10+
def __init__(self, device_address: int, client, auto_connect=True) -> None:
11+
"""Constructor"""
12+
self.device_address = device_address
13+
self.client = client
14+
self.connected = False
15+
16+
if auto_connect:
17+
self.connect()
18+
19+
def connect(self) -> bool:
20+
"""Try to connect Modbus client."""
21+
if not self.client.connect():
22+
print("Could not open COM port", flush=True)
23+
self.connected = False
24+
return False
25+
self.connected = True
26+
return True
27+
28+
#---------------------------------------------------------------------
29+
30+
def _read_registers(self, address: int, count: int) -> list[int] | None:
31+
"""Internal helper to read Modbus registers safely."""
32+
if not self.connected and not self.connect():
33+
print("Connection failed", flush=True)
34+
return None
35+
36+
result = self.client.read_input_registers(address=address, count=count, device_id=self.device_address)
37+
if result.isError():
38+
print(f"Read error at {address}: {result}", flush=True)
39+
return None
40+
return result.registers
41+
42+
# ---------------------------------------------------------------------
43+
# Core Read Functions
44+
# ---------------------------------------------------------------------
45+
46+
def read_V(self) -> float | None:
47+
"""Return V value"""
48+
regs = self._read_registers(0, 2)
49+
if not regs:
50+
return None
51+
value = (regs[1] << 16) + regs[0]
52+
return value / 10
53+
54+
#---------------------------------------------------------------------
55+
56+
def read_A(self) -> float | None:
57+
"""Return A value"""
58+
regs = self._read_registers(2, 2)
59+
if not regs:
60+
return None
61+
value = (regs[1] << 16) + regs[0]
62+
return value / 1000
63+
64+
#---------------------------------------------------------------------
65+
66+
def read_W(self) -> float | None:
67+
"""Return W value"""
68+
regs = self._read_registers(4, 2)
69+
if not regs:
70+
return None
71+
value = (regs[1] << 16) + regs[0]
72+
return value / 10
73+
74+
#---------------------------------------------------------------------
75+
76+
def read_W_dmd(self) -> float | None:
77+
"""Return W Dmd value"""
78+
regs = self._read_registers(10, 2)
79+
if not regs:
80+
return None
81+
value = (regs[1] << 16) + regs[0]
82+
return value / 10
83+
84+
#---------------------------------------------------------------------
85+
86+
def read_W_dmd_peak(self) -> float | None:
87+
"""Return W dmd peak value"""
88+
regs = self._read_registers(12, 2)
89+
if not regs:
90+
return None
91+
value = (regs[1] << 16) + regs[0]
92+
return value / 10
93+
94+
#---------------------------------------------------------------------
95+
96+
def read_Hz(self) -> float | None:
97+
"""Return Hz value"""
98+
regs = self._read_registers(15, 1)
99+
if not regs:
100+
return None
101+
value = regs[0]
102+
return value / 10
103+
104+
#---------------------------------------------------------------------
105+
106+
def read_kWh_tot(self) -> float | None:
107+
"""Return kWh value"""
108+
regs = self._read_registers(16, 2)
109+
if not regs:
110+
return None
111+
value = (regs[1] << 16) + regs[0]
112+
return value / 10
113+
114+
#---------------------------------------------------------------------

src/em511/my_functions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
"""My functions file, not for the user"""
2+

src/em511/test_hello.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,37 @@
1-
# noqa: D100
2-
import em511
1+
"""Test file for driver"""
2+
from em511 import Em511
3+
from pymodbus.client import ModbusSerialClient
4+
from time import sleep
35

6+
"""Init client"""
7+
client = ModbusSerialClient(
8+
port="/dev/ttyUSB0",
9+
baudrate=9600,
10+
parity="E",
11+
stopbits=1,
12+
bytesize=8,
13+
timeout=1,
14+
)
15+
print("client params is set")
416

5-
def test_hello() -> None:
6-
"""Test hello function."""
7-
assert em511.hello() == "Hello from python-em511!" # noqa: S101
17+
"""Init constructor"""
18+
AC_meter = Em511(102, client)
19+
20+
def test():
21+
22+
if client.connect():
23+
print("Client is connected", flush=True)
24+
print("Testing Functions", flush=True)
25+
print("V: ",AC_meter.read_V())
26+
print("A: ",AC_meter.read_A())
27+
print("W: ",AC_meter.read_W())
28+
print("W dmd: ",AC_meter.read_W_dmd())
29+
print("W dmd peak: ",AC_meter.read_W_dmd_peak())
30+
print("Hz : ",AC_meter.read_Hz())
31+
print("kWh tot : ",AC_meter.read_kWh_tot())
32+
33+
else:
34+
print("Could not open COM port", flush=True)
35+
36+
if __name__ == "__main__":
37+
test()

0 commit comments

Comments
 (0)