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