Skip to content

Commit

Permalink
Merge pull request #587 from PaeserBastelstube/main
Browse files Browse the repository at this point in the history
RPi-calculate and print irradiation (Bestrahlung)
  • Loading branch information
lumapu authored Jan 14, 2023
2 parents a09b9c2 + 17c1fec commit c8b1b0a
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 13 deletions.
16 changes: 13 additions & 3 deletions tools/rpi/ahoy.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,17 @@ ahoy:
inverters:
- name: 'balkon'
serial: 114172220003
txpower: 'low' # txpower per inverter (min,low,high,max)
txpower: 'low' # txpower per inverter (min,low,high,max)
mqtt:
send_raw_enabled: false # allow inject debug data via mqtt
topic: 'hoymiles/114172221234' # defaults to 'hoymiles/{serial}'
send_raw_enabled: false # allow inject debug data via mqtt
topic: 'hoymiles/114172221234' # defaults to '{inverter-name}/{serial}'
strings: # list all available strings
- s_name: 'String 1 left' # String 1 name
s_maxpower: 395 # String 1 max power in Wp
- s_name: 'String 2 right' # String 2 name
s_maxpower: 400 # String 2 max power in Wp
- s_name: 'String 3 up' # String 3 name
s_maxpower: 405 # String 3 max power in Wp
- s_name: 'String 4 down' # String 4 name
s_maxpower: 410 # String 4 max power in Wp

63 changes: 56 additions & 7 deletions tools/rpi/hoymiles/decoders/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ def __init__(self, *args, **params):
self.inverter_ser = params.get('inverter_ser', None)
self.inverter_name = params.get('inverter_name', None)
self.dtu_ser = params.get('dtu_ser', None)

self.response = args[0]

strings = params.get('strings', None)
self.inv_strings = strings

if isinstance(params.get('time_rx', None), datetime):
self.time_rx = params['time_rx']
else:
Expand All @@ -91,7 +93,7 @@ def __dict__(self):

class StatusResponse(Response):
"""Inverter StatusResponse object"""
e_keys = ['voltage','current','power','energy_total','energy_daily','powerfactor', 'reactive_power']
e_keys = ['voltage','current','power','energy_total','energy_daily','powerfactor', 'reactive_power', 'irradiation']
temperature = None
frequency = None
powerfactor = None
Expand Down Expand Up @@ -333,24 +335,29 @@ def __init__(self, *args, **params):
{ FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 },
{ FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 },
{ FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 },
{ FLD_unknown, UNIT_NONE, CH0, 6, 2, 1 },
{ FLD_FW_Build_Hour_Minute, UNIT_NONE, CH0, 6, 2, 1 },
{ FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 },
{ FLD_unknown, UNIT_NONE, CH0, 10, 2, 1 },
{ FLD_unknown, UNIT_NONE, CH0, 12, 2, 1 },
{ FLD_CRC-M, UNIT_NONE, CH0, 14, 2, 1 }
};
self.response = bytes('\x27\x1a\x07\xe5\x04\x4d\x03\x4a\x00\x68\x00\x00\x00\x00\xe6\xfb', 'latin1')
"""
fw_version, fw_build_yyyy, fw_build_mmdd, unknown, hw_id = struct.unpack('>HHHHH', self.response[0:10])
fw_version, fw_build_yyyy, fw_build_mmdd, fw_build_hhmm, hw_id = struct.unpack('>HHHHH', self.response[0:10])

responce_info = self.response
logging.debug(f'HardwareInfoResponse: {struct.unpack(">HHHHHHHH", responce_info)}')

fw_version_maj = int((fw_version / 10000))
fw_version_min = int((fw_version % 10000) / 100)
fw_version_pat = int((fw_version % 100))
fw_build_mm = int(fw_build_mmdd / 100)
fw_build_dd = int(fw_build_mmdd % 100)
logging.debug(f'Firmware: {fw_version_maj}.{fw_version_min}.{fw_version_pat} build at {fw_build_dd}/{fw_build_mm}/{fw_build_yyyy}, HW revision {hw_id}')
responce_info = self.response
logging.debug(f'HardwareInfoResponse: {struct.unpack(">HHHHHHHH", responce_info)}')
fw_build_HH = int(fw_build_hhmm / 100)
fw_build_MM = int(fw_build_hhmm % 100)
logging.debug(f'Firmware: {fw_version_maj}.{fw_version_min}.{fw_version_pat} '\
f'build at {fw_build_dd:>02}/{fw_build_mm:>02}/{fw_build_yyyy}T{fw_build_HH:>02}:{fw_build_MM:>02}, '\
f'HW revision {hw_id}')

class DebugDecodeAny(UnknownResponse):
"""Default decoder"""
Expand Down Expand Up @@ -426,6 +433,12 @@ def dc_energy_total_0(self):
def dc_energy_daily_0(self):
""" String 1 daily energy in Wh """
return self.unpack('>H', 12)[0]
@property
def dc_irradiation_0(self):
""" String 1 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 6)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3)

@property
def ac_voltage_0(self):
Expand Down Expand Up @@ -492,6 +505,12 @@ def dc_energy_total_0(self):
def dc_energy_daily_0(self):
""" String 1 daily energy in Wh """
return self.unpack('>H', 22)[0]
@property
def dc_irradiation_0(self):
""" String 1 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 6)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3)

@property
def dc_voltage_1(self):
Expand All @@ -513,6 +532,12 @@ def dc_energy_total_1(self):
def dc_energy_daily_1(self):
""" String 2 daily energy in Wh """
return self.unpack('>H', 24)[0]
@property
def dc_irradiation_1(self):
""" String 2 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 12)[0]/10/self.inv_strings[1]['s_maxpower']*100, 3)

@property
def ac_voltage_0(self):
Expand Down Expand Up @@ -587,6 +612,12 @@ def dc_energy_total_0(self):
def dc_energy_daily_0(self):
""" String 1 daily energy in Wh """
return self.unpack('>H', 20)[0]
@property
def dc_irradiation_0(self):
""" String 1 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 8)[0]/10/self.inv_strings[0]['s_maxpower']*100, 3)

@property
def dc_voltage_1(self):
Expand All @@ -608,6 +639,12 @@ def dc_energy_total_1(self):
def dc_energy_daily_1(self):
""" String 2 daily energy in Wh """
return self.unpack('>H', 22)[0]
@property
def dc_irradiation_0(self):
""" String 2 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 10)[0]/10/self.inv_strings[1]['s_maxpower']*100, 3)

@property
def dc_voltage_2(self):
Expand All @@ -629,6 +666,12 @@ def dc_energy_total_2(self):
def dc_energy_daily_2(self):
""" String 3 daily energy in Wh """
return self.unpack('>H', 42)[0]
@property
def dc_irradiation_0(self):
""" String 3 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 30)[0]/10/self.inv_strings[2]['s_maxpower']*100, 3)

@property
def dc_voltage_3(self):
Expand All @@ -650,6 +693,12 @@ def dc_energy_total_3(self):
def dc_energy_daily_3(self):
""" String 4 daily energy in Wh """
return self.unpack('>H', 44)[0]
@property
def dc_irradiation_0(self):
""" String 4 irratiation in percent """
if self.inv_strings is None:
return None
return round(self.unpack('>H', 32)[0]/10/self.inv_strings[3]['s_maxpower']*100, 3)

@property
def ac_voltage_0(self):
Expand Down
17 changes: 14 additions & 3 deletions tools/rpi/hoymiles/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,18 @@ def store_status(self, response, **params):
data_stack.append(f'{measurement},string={string_id},type=power value={string["power"]:.2f} {ctime}')
data_stack.append(f'{measurement},string={string_id},type=YieldDay value={string["energy_daily"]:.2f} {ctime}')
data_stack.append(f'{measurement},string={string_id},type=YieldTotal value={string["energy_total"]/1000:.4f} {ctime}')
if 'irradiation' in string:
data_stack.append(f'{measurement},string={string_id},type=Irradiation value={string["irradiation"]:.2f} {ctime}')
string_id = string_id + 1

# Global
if data['event_count'] is not None:
data_stack.append(f'{measurement},type=total_events value={data["event_count"]} {ctime}')
if data['powerfactor'] is not None:
data_stack.append(f'{measurement},type=pf value={data["powerfactor"]:f} {ctime}')
data_stack.append(f'{measurement},type=frequency value={data["frequency"]:.3f} {ctime}')
data_stack.append(f'{measurement},type=temperature value={data["temperature"]:.2f} {ctime}')

data_stack.append(f'{measurement},type=Temp value={data["temperature"]:.2f} {ctime}')
if data['energy_total'] is not None:
data_stack.append(f'{measurement},type=total value={data["energy_total"]/1000:.3f} {ctime}')

Expand Down Expand Up @@ -205,15 +209,19 @@ def store_status(self, response, **params):
for string in data['strings']:
self.client.publish(f'{topic}/emeter-dc/{string_id}/voltage', string['voltage'])
self.client.publish(f'{topic}/emeter-dc/{string_id}/current', string['current'])
self.client.publish(f'{topic}/emeter-dc/{string_id}/power', string['power'])
self.client.publish(f'{topic}/emeter-dc/{string_id}/YieldDay', string['energy_daily'])
self.client.publish(f'{topic}/emeter-dc/{string_id}/YieldTotal', string['energy_total']/1000)
if 'irradiation' in string:
self.client.publish(f'{topic}/emeter-dc/{string_id}/Irradiation', string['irradiation'])
string_id = string_id + 1

# Global
if data['powerfactor'] is not None:
self.client.publish(f'{topic}/pf', data['powerfactor'])
self.client.publish(f'{topic}/frequency', data['frequency'])
self.client.publish(f'{topic}/temperature', data['temperature'])

self.client.publish(f'{topic}/Temp', data['temperature'])
if data['energy_total'] is not None:
self.client.publish(f'{topic}/total', data['energy_total']/1000)

Expand Down Expand Up @@ -265,13 +273,16 @@ def store_status(self, data, session):
self.try_publish(ts, f'dc_power{string_id}', string['power'])
self.try_publish(ts, f'dc_YieldDay{string_id}', string['energy_daily'])
self.try_publish(ts, f'dc_YieldTotal{string_id}', string['energy_total'])
if 'irradiation' in string:
self.try_publish(ts, f'dc_Irradiation{string_id}', string['irradiation'])
string_id = string_id + 1

# Global
if data['powerfactor'] is not None:
self.try_publish(ts, f'powerfactor', data['powerfactor'])
self.try_publish(ts, f'frequency', data['frequency'])
self.try_publish(ts, f'temperature', data['temperature'])

self.try_publish(ts, f'Temp', data['temperature'])
if data['energy_total'] is not None:
self.try_publish(ts, f'total', data['energy_total'])

Expand Down

0 comments on commit c8b1b0a

Please sign in to comment.