Skip to content

Commit

Permalink
add openwb support for PR37SB
Browse files Browse the repository at this point in the history
solar wattage is calculated from voltage and current. this seems to be
the case for the official software. voltage and current extracted via usb
sniffer matched the wattage displayed in the official gui, so we should
be quite save.
  • Loading branch information
BenediktSeidl committed Oct 14, 2021
1 parent e2a7ec8 commit 78c2fea
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
1 change: 1 addition & 0 deletions prpd_usb/faker.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
h("5a0070020000e1b7a5"), {
"PR37SB": h("5aff7002001649dd0000024248450000024af0430882021c0226052404b3a5"),
"PR50SB": h("5aff7002001671d4000001a971b6000001aaf04309b0020801d60522150ea5")}

), (
h("5a00710200001db6a5"), {
"PR37SB": h("5aff7102000c009b278c00a10c63013c33ef84f9a5"),
Expand Down
33 changes: 28 additions & 5 deletions prpd_usb/output/mqtt_openwb.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

Direct = namedtuple('Direct', ['key'])
Map = namedtuple('Map', ['keys', 'function'])
MultiMap = namedtuple('Map', ['keys', 'functions'])
MultiMap = namedtuple('MultiMap', ['keys', 'functions'])
FunctionCall = namedtuple('FunctionCall', ['keys', 'function'])

def _neg(value):
return value * -1
Expand All @@ -18,12 +19,17 @@ def _sum(*values):
def _m_sum(*values):
return [sum(values)]

MAPPING = {
def _calc_pv_power_pr37sb(current_1, current_2, voltage_1, voltage_2):
return current_1 * voltage_1 + current_2 * voltage_2

DEFAULT_MAPPING = {
"openWB/set/evu/W": Map(keys=(('grid', 'power_w_phase_1'), ('grid', 'power_w_phase_2'), ('grid', 'power_w_phase_3')), function=_sum),
"openWB/set/evu/APhase1": Direct(('grid', 'current_phase_1')),
"openWB/set/evu/APhase2": Direct(('grid', 'current_phase_2')),
"openWB/set/evu/APhase3": Direct(('grid', 'current_phase_3')),
"openWB/set/evu/WhImported": Map(keys=(('grid', 'total_phase_1'), ('grid', 'total_phase_2'), ('grid', 'total_phase_3')), function=_sum),
# TODO: WhExported should be more complicated:
# this should be (at least) the total_solar - total_battery_consumed
"openWB/set/evu/WhExported": Map(keys=(('solar', 'total_phase_1'), ('solar', 'total_phase_2'), ('solar', 'total_phase_3')), function=_sum),
"openWB/set/evu/VPhase1": Direct(('grid', 'voltage_phase_1')),
"openWB/set/evu/VPhase2": Direct(('grid', 'voltage_phase_2')),
Expand All @@ -39,17 +45,34 @@ def _m_sum(*values):
"openWB/set/houseBattery/%Soc": Direct(('battery', 'soc')),
}

MAPPING_BY_MODEL = {
"PR37SB": {
"openWB/set/evu/WhExported": Direct(('solar', 'total')),
"openWB/set/pv/1/W": FunctionCall(keys=(('solar', 'current_string_1'), ('solar', 'current_string_2'), ('solar', 'voltage_string_1'), ('solar', 'voltage_string_2'),), function=_calc_pv_power_pr37sb),
"openWB/set/pv/1/WhCounter": Direct(('solar', 'total'))
}
}

def transform_to_openwb(prpd_data):
def transform_to_openwb(prpd_data, model):
messages = []
data = {}

for command, field, _time, value in prpd_data:
data[(command.name, field.name)] = value

for topic, mapping in MAPPING.items():
from pprint import pprint
pprint(data)

mapping = DEFAULT_MAPPING.copy()
if model in MAPPING_BY_MODEL:
mapping.update(MAPPING_BY_MODEL[model])

for topic, mapping in mapping.items():
if isinstance(mapping, Direct):
payload = data[mapping.key]
elif isinstance(mapping, FunctionCall):
values = [data[k] for k in mapping.keys]
payload = mapping.function(*values)
elif isinstance(mapping, MultiMap):
values = [data[k] for k in mapping.keys]
for function in mapping.functions:
Expand All @@ -74,7 +97,7 @@ def main(prpd_reader, args):
while True:

data = prpd_reader.read()
messages = transform_to_openwb(data)
messages = transform_to_openwb(data, prpd_reader.model)

publish.multiple(messages, hostname=args.mqtt_hostname, port=args.mqtt_port, auth=auth)
time.sleep(args.mqtt_interval)
4 changes: 4 additions & 0 deletions prpd_usb/prpd.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def init(self, model=None):
self._model = MODELS[model]
logger.info(f"Identified model {self._model}")

@property
def model(self):
return self._model

def read(self):
with self.lock:
for command in self._get_commands():
Expand Down
26 changes: 25 additions & 1 deletion tests/test_openwb.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def test_openwb_37bi():
prpd = _PrPd(SerialFaker("PR37Bi"))
prpd.init()
data = prpd.read()
messages = transform_to_openwb(data)
messages = transform_to_openwb(data, "PR37Bi")
assert messages == [
{"payload": "18", "topic": "openWB/set/evu/W"},
{"payload": "1.17", "topic": "openWB/set/evu/APhase1"},
Expand All @@ -28,3 +28,27 @@ def test_openwb_37bi():
{"payload": "5545710", "topic": "openWB/set/houseBattery/WhExported"},
{"payload": "76", "topic": "openWB/set/houseBattery/%Soc"},
]

def test_openwb_37sb():
prpd = _PrPd(SerialFaker("PR37SB"))
prpd.init()
data = prpd.read()
messages = transform_to_openwb(data, "PR37SB")
assert messages == [
{'payload': '-16', 'topic': 'openWB/set/evu/W'},
{'payload': '1.06', 'topic': 'openWB/set/evu/APhase1'},
{'payload': '2.9', 'topic': 'openWB/set/evu/APhase2'},
{'payload': '3.79', 'topic': 'openWB/set/evu/APhase3'},
{'payload': '17090500', 'topic': 'openWB/set/evu/WhImported'},
{'payload': '20722671', 'topic': 'openWB/set/evu/WhExported'},
{'payload': '227.20000000000002', 'topic': 'openWB/set/evu/VPhase1'},
{'payload': '227.0', 'topic': 'openWB/set/evu/VPhase2'},
{'payload': '227.4', 'topic': 'openWB/set/evu/VPhase3'},
{'payload': '50.01', 'topic': 'openWB/set/evu/HzFrequenz'},
{'payload': '2177.0987999999998', 'topic': 'openWB/set/pv/1/W'},
{'payload': '20722671', 'topic': 'openWB/set/pv/1/WhCounter'},
{'payload': '502', 'topic': 'openWB/set/houseBattery/W'},
{'payload': '5806854', 'topic': 'openWB/set/houseBattery/WhImported'},
{'payload': '4497664', 'topic': 'openWB/set/houseBattery/WhExported'},
{'payload': '78', 'topic': 'openWB/set/houseBattery/%Soc'},
]

0 comments on commit 78c2fea

Please sign in to comment.