Skip to content

Commit f788103

Browse files
committed
rewrite modbus server
1 parent 8b7706c commit f788103

1 file changed

Lines changed: 74 additions & 57 deletions

File tree

packages/helpermodules/modbusserver.py

Lines changed: 74 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from socketserver import TCPServer
44
from collections import defaultdict
55
import struct
6-
from typing import Optional
6+
from typing import Optional, Union
77

88
from helpermodules.utils.error_handling import ImportErrorContext
99
with ImportErrorContext():
@@ -31,33 +31,32 @@
3131
log.exception("Fehler im Modbus-Server")
3232

3333

34-
def _form_int32(value, startreg):
35-
secondreg = startreg + 1
34+
def _form_int32(value: Union[int, float], register: int):
3635
try:
3736
binary32 = struct.pack('>l', int(value))
3837
high_byte, low_byte = struct.unpack('>hh', binary32)
39-
data_store[startreg] = high_byte
40-
data_store[secondreg] = low_byte
38+
data_store[register] = high_byte
39+
data_store[register + 1] = low_byte
4140
except Exception:
4241
log.exception("Fehler beim Füllen der Register")
43-
data_store[startreg] = -1
44-
data_store[secondreg] = -1
42+
data_store[register] = -1
43+
data_store[register + 1] = -1
4544

4645

47-
def _form_int16(value, startreg):
46+
def _form_int16(value: Union[int, float, bool], register: int):
4847
try:
4948
value = int(value)
5049
if (value > 32767 or value < -32768):
5150
raise Exception("Number to big")
52-
data_store[startreg] = value
51+
data_store[register] = value
5352
except Exception:
5453
log.exception("Fehler beim Füllen der Register")
55-
data_store[startreg] = -1
54+
data_store[register] = -1
5655

5756

58-
def _form_str(value: Optional[str], startreg):
57+
def _form_str(value: Optional[str], register: int):
5958
if value is None or len(value) == 0:
60-
data_store[startreg] = 0
59+
data_store[register] = 0
6160
else:
6261
bytes = value.encode("utf-8")
6362
length = len(bytes)
@@ -72,79 +71,97 @@ def _form_str(value: Optional[str], startreg):
7271
else:
7372
stream_two_bytes = struct.pack(">bb", bytes[i], 0)
7473
stream_one_word = struct.unpack(">h", stream_two_bytes)[0]
75-
data_store[startreg+register_offset] = stream_one_word
74+
data_store[register + register_offset] = stream_one_word
7675
except Exception:
77-
data_store[startreg+register_offset] = -1
76+
data_store[register + register_offset] = -1
7877
finally:
7978
register_offset += 1
8079

8180

82-
def _get_pos(number, n):
83-
return number // 10**n % 10 - 1
81+
def _charge_point_index(address: int):
82+
return int(str(address)[-3]) - 1
83+
84+
85+
def _value_index(address: int):
86+
return int(str(address)[-2:])
8487

8588

8689
try:
8790
@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 32000)))
88-
def read_data_store(slave_id, function_code, address):
91+
def read_data_store(slave_id: int, function_code: int, address: int):
8992
"""" Return value of address. """
93+
# Mapping für einfache Zuordnung
94+
int32_map = {
95+
0: lambda cp: cp.get.power,
96+
2: lambda cp: cp.get.imported,
97+
41: lambda cp: cp.get.exported,
98+
}
99+
int16_map = {
100+
4: lambda cp: cp.get.voltages[0] * 100,
101+
5: lambda cp: cp.get.voltages[1] * 100,
102+
6: lambda cp: cp.get.voltages[2] * 100,
103+
7: lambda cp: cp.get.currents[0] * 100,
104+
8: lambda cp: cp.get.currents[1] * 100,
105+
9: lambda cp: cp.get.currents[2] * 100,
106+
14: lambda cp: cp.get.plug_state,
107+
15: lambda cp: cp.get.charge_state,
108+
16: lambda cp: cp.get.evse_current,
109+
30: lambda cp: cp.get.powers[0],
110+
31: lambda cp: cp.get.powers[1],
111+
32: lambda cp: cp.get.powers[2],
112+
43: lambda _: 1,
113+
}
114+
str_map = {
115+
50: lambda _: serial_number,
116+
60: lambda cp: cp.get.rfid,
117+
}
118+
90119
if address > 10099:
91120
Pub().pub("openWB/set/internal_chargepoint/global_data",
92121
{"heartbeat": timecheck.create_timestamp(), "parent_ip": None})
93-
chargepoint = SubData.internal_chargepoint_data[f"cp{_get_pos(address, 2)}"]
94-
askedvalue = int(str(address)[-2:])
95-
if askedvalue == 00:
96-
_form_int32(chargepoint.get.power, address)
97-
elif askedvalue == 2:
98-
_form_int32(chargepoint.get.imported, address)
99-
elif 4 <= askedvalue <= 6:
100-
_form_int16(chargepoint.get.voltages[askedvalue-4]*100, address)
101-
elif 7 <= askedvalue <= 9:
102-
_form_int16(chargepoint.get.currents[askedvalue-7]*100, address)
103-
elif askedvalue == 14:
104-
_form_int16(chargepoint.get.plug_state, address)
105-
elif askedvalue == 15:
106-
_form_int16(chargepoint.get.charge_state, address)
107-
elif askedvalue == 16:
108-
_form_int16(chargepoint.get.evse_current, address)
109-
elif 30 <= askedvalue <= 32:
110-
_form_int16(chargepoint.get.powers[askedvalue-30], address)
111-
elif askedvalue == 41:
112-
_form_int32(chargepoint.get.exported, address)
113-
elif askedvalue == 43:
114-
_form_int16(1, address)
115-
elif askedvalue == 50:
116-
_form_str(serial_number, address)
117-
elif askedvalue == 60:
118-
_form_str(chargepoint.get.rfid, address)
122+
charge_point = SubData.internal_chargepoint_data[f"cp{_charge_point_index(address)}"]
123+
requested_value = _value_index(address)
124+
125+
if requested_value in int32_map:
126+
_form_int32(int32_map[requested_value](charge_point), address)
127+
elif requested_value in int16_map:
128+
_form_int16(int16_map[requested_value](charge_point), address)
129+
elif requested_value in str_map:
130+
_form_str(str_map[requested_value](charge_point), address)
131+
else:
132+
log.warning(f"Unbekannte Adresse: {address}")
119133

120134
return data_store[address]
121135
except Exception:
122136
log.exception("Fehler im Modbus-Server")
123137

124138
try:
125139
@app.route(slave_ids=[1], function_codes=[6, 16], addresses=list(range(0, 32000)))
126-
def write_data_store(slave_id, function_code, address, value):
140+
def write_data_store(slave_id: int, function_code: int, address: int, value):
127141
"""" Set value for address. """
128142
if 10170 < address:
129-
cp_topic = f"openWB/set/internal_chargepoint/{_get_pos(address, 2)}/data/"
130-
askedvalue = int(str(address)[-2:])
131-
if askedvalue == 71:
132-
Pub().pub(f"{cp_topic}set_current", value/100)
133-
elif askedvalue == 80:
134-
Pub().pub(f"{cp_topic}phases_to_use", value)
135-
elif askedvalue == 81:
136-
Pub().pub(f"{cp_topic}trigger_phase_switch", value)
137-
elif askedvalue == 98:
138-
Pub().pub(f"{cp_topic}cp_interruption_duration", value)
139-
elif askedvalue == 99:
140-
Pub().pub("openWB/set/command/modbus_server/todo", {"command": "systemUpdate", "data": {}})
143+
cp_topic = f"openWB/set/internal_chargepoint/{_charge_point_index(address)}/data/"
144+
requested_value = _value_index(address)
145+
146+
write_map = {
147+
71: lambda value: Pub().pub(f"{cp_topic}set_current", value / 100),
148+
80: lambda value: Pub().pub(f"{cp_topic}phases_to_use", value),
149+
81: lambda value: Pub().pub(f"{cp_topic}trigger_phase_switch", value),
150+
98: lambda value: Pub().pub(f"{cp_topic}cp_interruption_duration", value),
151+
99: lambda _: Pub().pub("openWB/set/command/modbus_server/todo",
152+
{"command": "systemUpdate", "data": {}})
153+
}
154+
if requested_value in write_map:
155+
write_map[requested_value](value)
156+
else:
157+
log.warning(f"Unbekannte Adresse beim Schreiben: {address}")
141158
except Exception:
142159
log.exception("Fehler im Modbus-Server")
143160

144161

145162
def start_modbus_server(event_modbus_server):
146163
try:
147-
# Wenn start_modbus_server aus SubData aufegrufen wird, wenn das Topic gesetzt wird, führt das zu einem
164+
# Wenn start_modbus_server aus SubData aufgerufen wird, wenn das Topic gesetzt wird, führt das zu einem
148165
# circular Import.
149166
event_modbus_server.wait()
150167
event_modbus_server.clear()

0 commit comments

Comments
 (0)