mirror of https://github.com/lumapu/ahoy.git
				
				
			
							committed by
							
								 GitHub
								GitHub
							
						
					
				
				 6 changed files with 791 additions and 253 deletions
			
			
		| @ -1,212 +0,0 @@ | |||||
| #!/usr/bin/env python3 |  | ||||
| # -*- coding: utf-8 -*- |  | ||||
| 
 |  | ||||
| import sys |  | ||||
| import struct |  | ||||
| import re |  | ||||
| import time |  | ||||
| from datetime import datetime |  | ||||
| import argparse |  | ||||
| import hoymiles |  | ||||
| from RF24 import RF24, RF24_PA_LOW, RF24_PA_MAX, RF24_250KBPS, RF24_CRC_DISABLED, RF24_CRC_8, RF24_CRC_16 |  | ||||
| import paho.mqtt.client |  | ||||
| import yaml |  | ||||
| from yaml.loader import SafeLoader |  | ||||
| 
 |  | ||||
| parser = argparse.ArgumentParser(description='Ahoy - Hoymiles solar inverter gateway') |  | ||||
| parser.add_argument("-c", "--config-file", nargs="?", |  | ||||
|     help="configuration file") |  | ||||
| global_config = parser.parse_args() |  | ||||
| 
 |  | ||||
| if global_config.config_file: |  | ||||
|     with open(global_config.config_file) as yf: |  | ||||
|         cfg = yaml.load(yf, Loader=SafeLoader) |  | ||||
| else: |  | ||||
|     with open(global_config.config_file) as yf: |  | ||||
|         cfg = yaml.load('ahoy.yml', Loader=SafeLoader) |  | ||||
| 
 |  | ||||
| radio = RF24(22, 0, 1000000) |  | ||||
| hmradio = hoymiles.HoymilesNRF(device=radio) |  | ||||
| mqtt_client = None |  | ||||
| 
 |  | ||||
| command_queue = {} |  | ||||
| mqtt_command_topic_subs = [] |  | ||||
| 
 |  | ||||
| hoymiles.HOYMILES_TRANSACTION_LOGGING=True |  | ||||
| hoymiles.HOYMILES_DEBUG_LOGGING=True |  | ||||
| 
 |  | ||||
| def main_loop(): |  | ||||
|     inverters = [ |  | ||||
|             inverter for inverter in ahoy_config.get('inverters', []) |  | ||||
|             if not inverter.get('disabled', False)] |  | ||||
| 
 |  | ||||
|     for inverter in inverters: |  | ||||
|         if hoymiles.HOYMILES_DEBUG_LOGGING: |  | ||||
|             print(f'Poll inverter {inverter["serial"]}') |  | ||||
|         poll_inverter(inverter) |  | ||||
| 
 |  | ||||
| def poll_inverter(inverter): |  | ||||
|     inverter_ser = inverter.get('serial') |  | ||||
|     dtu_ser = ahoy_config.get('dtu', {}).get('serial') |  | ||||
| 
 |  | ||||
|     if len(command_queue[str(inverter_ser)]) > 0: |  | ||||
|         payload = command_queue[str(inverter_ser)].pop(0) |  | ||||
|     else: |  | ||||
|         payload = hoymiles.compose_set_time_payload() |  | ||||
| 
 |  | ||||
|     payload_ttl = 4 |  | ||||
|     while payload_ttl > 0: |  | ||||
|         payload_ttl = payload_ttl - 1 |  | ||||
|         com = hoymiles.InverterTransaction( |  | ||||
|                 radio=hmradio, |  | ||||
|                 dtu_ser=dtu_ser, |  | ||||
|                 inverter_ser=inverter_ser, |  | ||||
|                 request=next(hoymiles.compose_esb_packet( |  | ||||
|                     payload, |  | ||||
|                     seq=b'\x80', |  | ||||
|                     src=dtu_ser, |  | ||||
|                     dst=inverter_ser |  | ||||
|                     ))) |  | ||||
|         response = None |  | ||||
|         while com.rxtx(): |  | ||||
|             try: |  | ||||
|                 response = com.get_payload() |  | ||||
|                 payload_ttl = 0 |  | ||||
|             except Exception as e: |  | ||||
|                 print(f'Error while retrieving data: {e}') |  | ||||
|                 pass |  | ||||
| 
 |  | ||||
|     if response: |  | ||||
|         dt = datetime.now() |  | ||||
|         print(f'{dt} Payload: ' + hoymiles.hexify_payload(response)) |  | ||||
|         decoder = hoymiles.ResponseDecoder(response, |  | ||||
|                 request=com.request, |  | ||||
|                 inverter_ser=inverter_ser |  | ||||
|                 ) |  | ||||
|         result = decoder.decode() |  | ||||
|         if isinstance(result, hoymiles.decoders.StatusResponse): |  | ||||
|             data = result.__dict__() |  | ||||
|             if hoymiles.HOYMILES_DEBUG_LOGGING: |  | ||||
|                 print(f'{dt} Decoded: {data["temperature"]}', end='') |  | ||||
|                 phase_id = 0 |  | ||||
|                 for phase in data['phases']: |  | ||||
|                     print(f' phase{phase_id}=voltage:{phase["voltage"]}, current:{phase["current"]}, power:{phase["power"]}, frequency:{data["frequency"]}', end='') |  | ||||
|                     phase_id = phase_id + 1 |  | ||||
|                 string_id = 0 |  | ||||
|                 for string in data['strings']: |  | ||||
|                     print(f' string{string_id}=voltage:{string["voltage"]}, current:{string["current"]}, power:{string["power"]}, total:{string["energy_total"]/1000}, daily:{string["energy_daily"]}', end='') |  | ||||
|                     string_id = string_id + 1 |  | ||||
|                 print() |  | ||||
| 
 |  | ||||
|             if mqtt_client: |  | ||||
|                 mqtt_send_status(mqtt_client, inverter_ser, data, |  | ||||
|                         topic=inverter.get('mqtt', {}).get('topic', None)) |  | ||||
| 
 |  | ||||
| def mqtt_send_status(broker, inverter_ser, data, topic=None): |  | ||||
|     """ Publish StatusResponse object """ |  | ||||
| 
 |  | ||||
|     if not topic: |  | ||||
|         topic = f'hoymiles/{inverter_ser}' |  | ||||
| 
 |  | ||||
|     # AC Data |  | ||||
|     phase_id = 0 |  | ||||
|     for phase in data['phases']: |  | ||||
|         broker.publish(f'{topic}/emeter/{phase_id}/power', phase['power']) |  | ||||
|         broker.publish(f'{topic}/emeter/{phase_id}/voltage', phase['voltage']) |  | ||||
|         broker.publish(f'{topic}/emeter/{phase_id}/current', phase['current']) |  | ||||
|         phase_id = phase_id + 1 |  | ||||
| 
 |  | ||||
|     # DC Data |  | ||||
|     string_id = 0 |  | ||||
|     for string in data['strings']: |  | ||||
|         broker.publish(f'{topic}/emeter-dc/{string_id}/total', string['energy_total']/1000) |  | ||||
|         broker.publish(f'{topic}/emeter-dc/{string_id}/power', string['power']) |  | ||||
|         broker.publish(f'{topic}/emeter-dc/{string_id}/voltage', string['voltage']) |  | ||||
|         broker.publish(f'{topic}/emeter-dc/{string_id}/current', string['current']) |  | ||||
|         string_id = string_id + 1 |  | ||||
|     # Global |  | ||||
|     broker.publish(f'{topic}/frequency', data['frequency']) |  | ||||
|     broker.publish(f'{topic}/temperature', data['temperature']) |  | ||||
| 
 |  | ||||
| def mqtt_on_command(client, userdata, message): |  | ||||
|     """ |  | ||||
|     Handle commands to topic |  | ||||
|         hoymiles/{inverter_ser}/command |  | ||||
|     frame a payload and put onto command_queue |  | ||||
| 
 |  | ||||
|     Inverters must have mqtt.send_raw_enabled: true configured |  | ||||
| 
 |  | ||||
|     This can be used to inject debug payloads |  | ||||
|     The message must be in hexlified format |  | ||||
| 
 |  | ||||
|     Use of variables: |  | ||||
|     tttttttt gets expanded to a current int(time) |  | ||||
| 
 |  | ||||
|     Example injects exactly the same as we normally use to poll data: |  | ||||
|       mosquitto -h broker -t inverter_topic/command -m 800b00tttttttt0000000500000000 |  | ||||
| 
 |  | ||||
|     This allows for even faster hacking during runtime |  | ||||
|     """ |  | ||||
|     try: |  | ||||
|         inverter_ser = next( |  | ||||
|                 item[0] for item in mqtt_command_topic_subs if item[1] == message.topic) |  | ||||
|     except StopIteration: |  | ||||
|         print('Unexpedtedly received mqtt message for {message.topic}') |  | ||||
| 
 |  | ||||
|     if inverter_ser: |  | ||||
|         p_message = message.payload.decode('utf-8').lower() |  | ||||
| 
 |  | ||||
|         # Expand tttttttt to current time for use in hexlified payload |  | ||||
|         expand_time = ''.join(f'{b:02x}' for b in struct.pack('>L', int(time.time()))) |  | ||||
|         p_message = p_message.replace('tttttttt', expand_time) |  | ||||
| 
 |  | ||||
|         if (len(p_message) < 2048 \ |  | ||||
|             and len(p_message) % 2 == 0 \ |  | ||||
|             and re.match(r'^[a-f0-9]+$', p_message)): |  | ||||
|             payload = bytes.fromhex(p_message) |  | ||||
|             # commands must start with \x80 |  | ||||
|             if payload[0] == 0x80: |  | ||||
|                 command_queue[str(inverter_ser)].append( |  | ||||
|                     hoymiles.frame_payload(payload[1:])) |  | ||||
| 
 |  | ||||
| if __name__ == '__main__': |  | ||||
|     ahoy_config = dict(cfg.get('ahoy', {})) |  | ||||
| 
 |  | ||||
|     mqtt_config = ahoy_config.get('mqtt', []) |  | ||||
|     if not mqtt_config.get('disabled', False): |  | ||||
|         mqtt_client = paho.mqtt.client.Client() |  | ||||
|         mqtt_client.username_pw_set(mqtt_config.get('user', None), mqtt_config.get('password', None)) |  | ||||
|         mqtt_client.connect(mqtt_config.get('host', '127.0.0.1'), mqtt_config.get('port', 1883)) |  | ||||
|         mqtt_client.loop_start() |  | ||||
|         mqtt_client.on_message = mqtt_on_command |  | ||||
| 
 |  | ||||
|     if not radio.begin(): |  | ||||
|         raise RuntimeError('Can\'t open radio') |  | ||||
| 
 |  | ||||
|     inverters = [inverter.get('serial') for inverter in ahoy_config.get('inverters', [])] |  | ||||
|     for inverter in ahoy_config.get('inverters', []): |  | ||||
|         inverter_ser = inverter.get('serial') |  | ||||
|         command_queue[str(inverter_ser)] = [] |  | ||||
| 
 |  | ||||
|         # |  | ||||
|         # Enables and subscribe inverter to mqtt /command-Topic |  | ||||
|         # |  | ||||
|         if inverter.get('mqtt', {}).get('send_raw_enabled', False): |  | ||||
|             topic_item = ( |  | ||||
|                     str(inverter_ser), |  | ||||
|                     inverter.get('mqtt', {}).get('topic', f'hoymiles/{inverter_ser}') + '/command' |  | ||||
|                     ) |  | ||||
|             mqtt_client.subscribe(topic_item[1]) |  | ||||
|             mqtt_command_topic_subs.append(topic_item) |  | ||||
| 
 |  | ||||
|     loop_interval = ahoy_config.get('interval', 1) |  | ||||
|     try: |  | ||||
|         while True: |  | ||||
|             main_loop() |  | ||||
| 
 |  | ||||
|             if loop_interval: |  | ||||
|                 time.sleep(time.time() % loop_interval) |  | ||||
| 
 |  | ||||
|     except KeyboardInterrupt: |  | ||||
|         radio.powerDown() |  | ||||
|         sys.exit() |  | ||||
| @ -0,0 +1,261 @@ | |||||
|  | #!/usr/bin/env python3 | ||||
|  | # -*- coding: utf-8 -*- | ||||
|  | 
 | ||||
|  | import sys | ||||
|  | import struct | ||||
|  | import re | ||||
|  | import time | ||||
|  | from datetime import datetime | ||||
|  | import argparse | ||||
|  | import hoymiles | ||||
|  | from RF24 import RF24, RF24_PA_LOW, RF24_PA_MAX, RF24_250KBPS, RF24_CRC_DISABLED, RF24_CRC_8, RF24_CRC_16 | ||||
|  | import paho.mqtt.client | ||||
|  | import yaml | ||||
|  | from yaml.loader import SafeLoader | ||||
|  | 
 | ||||
|  | def main_loop(): | ||||
|  |     """Main loop""" | ||||
|  |     inverters = [ | ||||
|  |             inverter for inverter in ahoy_config.get('inverters', []) | ||||
|  |             if not inverter.get('disabled', False)] | ||||
|  | 
 | ||||
|  |     for inverter in inverters: | ||||
|  |         if hoymiles.HOYMILES_DEBUG_LOGGING: | ||||
|  |             print(f'Poll inverter {inverter["serial"]}') | ||||
|  |         poll_inverter(inverter) | ||||
|  | 
 | ||||
|  | def poll_inverter(inverter, retries=4): | ||||
|  |     """ | ||||
|  |     Send/Receive command_queue, initiate status poll on inverter | ||||
|  | 
 | ||||
|  |     :param str inverter: inverter serial | ||||
|  |     :param retries: tx retry count if no inverter contact | ||||
|  |     :type retries: int | ||||
|  |     """ | ||||
|  |     inverter_ser = inverter.get('serial') | ||||
|  |     dtu_ser = ahoy_config.get('dtu', {}).get('serial') | ||||
|  | 
 | ||||
|  |     # Queue at least status data request | ||||
|  |     command_queue[str(inverter_ser)].append(hoymiles.compose_set_time_payload()) | ||||
|  | 
 | ||||
|  |     # Putt all queued commands for current inverter on air | ||||
|  |     while len(command_queue[str(inverter_ser)]) > 0: | ||||
|  |         payload = command_queue[str(inverter_ser)].pop(0) | ||||
|  | 
 | ||||
|  |         # Send payload {ttl}-times until we get at least one reponse | ||||
|  |         payload_ttl = retries | ||||
|  |         while payload_ttl > 0: | ||||
|  |             payload_ttl = payload_ttl - 1 | ||||
|  |             com = hoymiles.InverterTransaction( | ||||
|  |                     radio=hmradio, | ||||
|  |                     dtu_ser=dtu_ser, | ||||
|  |                     inverter_ser=inverter_ser, | ||||
|  |                     request=next(hoymiles.compose_esb_packet( | ||||
|  |                         payload, | ||||
|  |                         seq=b'\x80', | ||||
|  |                         src=dtu_ser, | ||||
|  |                         dst=inverter_ser | ||||
|  |                         ))) | ||||
|  |             response = None | ||||
|  |             while com.rxtx(): | ||||
|  |                 try: | ||||
|  |                     response = com.get_payload() | ||||
|  |                     payload_ttl = 0 | ||||
|  |                 except Exception as e: | ||||
|  |                     print(f'Error while retrieving data: {e}') | ||||
|  |                     pass | ||||
|  | 
 | ||||
|  |         # Handle the response data if any | ||||
|  |         if response: | ||||
|  |             dt = datetime.now() | ||||
|  |             print(f'{dt} Payload: ' + hoymiles.hexify_payload(response)) | ||||
|  |             decoder = hoymiles.ResponseDecoder(response, | ||||
|  |                     request=com.request, | ||||
|  |                     inverter_ser=inverter_ser | ||||
|  |                     ) | ||||
|  |             result = decoder.decode() | ||||
|  |             if isinstance(result, hoymiles.decoders.StatusResponse): | ||||
|  |                 data = result.__dict__() | ||||
|  |                 if hoymiles.HOYMILES_DEBUG_LOGGING: | ||||
|  |                     print(f'{dt} Decoded: {data["temperature"]}', end='') | ||||
|  |                     phase_id = 0 | ||||
|  |                     for phase in data['phases']: | ||||
|  |                         print(f' phase{phase_id}=voltage:{phase["voltage"]}, current:{phase["current"]}, power:{phase["power"]}, frequency:{data["frequency"]}', end='') | ||||
|  |                         phase_id = phase_id + 1 | ||||
|  |                     string_id = 0 | ||||
|  |                     for string in data['strings']: | ||||
|  |                         print(f' string{string_id}=voltage:{string["voltage"]}, current:{string["current"]}, power:{string["power"]}, total:{string["energy_total"]/1000}, daily:{string["energy_daily"]}', end='') | ||||
|  |                         string_id = string_id + 1 | ||||
|  |                     print() | ||||
|  | 
 | ||||
|  |                 if mqtt_client: | ||||
|  |                     mqtt_send_status(mqtt_client, inverter_ser, data, | ||||
|  |                             topic=inverter.get('mqtt', {}).get('topic', None)) | ||||
|  | 
 | ||||
|  | def mqtt_send_status(broker, inverter_ser, data, topic=None): | ||||
|  |     """ | ||||
|  |     Publish StatusResponse object | ||||
|  | 
 | ||||
|  |     :param paho.mqtt.client.Client broker: mqtt-client instance | ||||
|  |     :param str inverter_ser: inverter serial | ||||
|  |     :param hoymiles.StatusResponse data: decoded inverter StatusResponse | ||||
|  |     :param topic: custom mqtt topic prefix (default: hoymiles/{inverter_ser}) | ||||
|  |     :type topic: str | ||||
|  |     """ | ||||
|  | 
 | ||||
|  |     if not topic: | ||||
|  |         topic = f'hoymiles/{inverter_ser}' | ||||
|  | 
 | ||||
|  |     # AC Data | ||||
|  |     phase_id = 0 | ||||
|  |     for phase in data['phases']: | ||||
|  |         broker.publish(f'{topic}/emeter/{phase_id}/power', phase['power']) | ||||
|  |         broker.publish(f'{topic}/emeter/{phase_id}/voltage', phase['voltage']) | ||||
|  |         broker.publish(f'{topic}/emeter/{phase_id}/current', phase['current']) | ||||
|  |         phase_id = phase_id + 1 | ||||
|  | 
 | ||||
|  |     # DC Data | ||||
|  |     string_id = 0 | ||||
|  |     for string in data['strings']: | ||||
|  |         broker.publish(f'{topic}/emeter-dc/{string_id}/total', string['energy_total']/1000) | ||||
|  |         broker.publish(f'{topic}/emeter-dc/{string_id}/power', string['power']) | ||||
|  |         broker.publish(f'{topic}/emeter-dc/{string_id}/voltage', string['voltage']) | ||||
|  |         broker.publish(f'{topic}/emeter-dc/{string_id}/current', string['current']) | ||||
|  |         string_id = string_id + 1 | ||||
|  |     # Global | ||||
|  |     broker.publish(f'{topic}/frequency', data['frequency']) | ||||
|  |     broker.publish(f'{topic}/temperature', data['temperature']) | ||||
|  | 
 | ||||
|  | def mqtt_on_command(client, userdata, message): | ||||
|  |     """ | ||||
|  |     Handle commands to topic | ||||
|  |         hoymiles/{inverter_ser}/command | ||||
|  |     frame a payload and put onto command_queue | ||||
|  | 
 | ||||
|  |     Inverters must have mqtt.send_raw_enabled: true configured | ||||
|  | 
 | ||||
|  |     This can be used to inject debug payloads | ||||
|  |     The message must be in hexlified format | ||||
|  | 
 | ||||
|  |     Use of variables: | ||||
|  |     tttttttt gets expanded to a current int(time) | ||||
|  | 
 | ||||
|  |     Example injects exactly the same as we normally use to poll data: | ||||
|  |       mosquitto -h broker -t inverter_topic/command -m 800b00tttttttt0000000500000000 | ||||
|  | 
 | ||||
|  |     This allows for even faster hacking during runtime | ||||
|  | 
 | ||||
|  |     :param paho.mqtt.client.Client client: mqtt-client instance | ||||
|  |     :param dict userdata: Userdata | ||||
|  |     :param dict message: mqtt-client message object | ||||
|  |     """ | ||||
|  |     try: | ||||
|  |         inverter_ser = next( | ||||
|  |                 item[0] for item in mqtt_command_topic_subs if item[1] == message.topic) | ||||
|  |     except StopIteration: | ||||
|  |         print('Unexpedtedly received mqtt message for {message.topic}') | ||||
|  | 
 | ||||
|  |     if inverter_ser: | ||||
|  |         p_message = message.payload.decode('utf-8').lower() | ||||
|  | 
 | ||||
|  |         # Expand tttttttt to current time for use in hexlified payload | ||||
|  |         expand_time = ''.join(f'{b:02x}' for b in struct.pack('>L', int(time.time()))) | ||||
|  |         p_message = p_message.replace('tttttttt', expand_time) | ||||
|  | 
 | ||||
|  |         if (len(p_message) < 2048 \ | ||||
|  |             and len(p_message) % 2 == 0 \ | ||||
|  |             and re.match(r'^[a-f0-9]+$', p_message)): | ||||
|  |             payload = bytes.fromhex(p_message) | ||||
|  |             # commands must start with \x80 | ||||
|  |             if payload[0] == 0x80: | ||||
|  |                 command_queue[str(inverter_ser)].append( | ||||
|  |                     hoymiles.frame_payload(payload[1:])) | ||||
|  | 
 | ||||
|  | if __name__ == '__main__': | ||||
|  |     parser = argparse.ArgumentParser(description='Ahoy - Hoymiles solar inverter gateway', prog="hoymiles") | ||||
|  |     parser.add_argument("-c", "--config-file", nargs="?", required=True, | ||||
|  |         help="configuration file") | ||||
|  |     parser.add_argument("--log-transactions", action="store_true", default=False, | ||||
|  |         help="Enable transaction logging output") | ||||
|  |     parser.add_argument("--verbose", action="store_true", default=False, | ||||
|  |         help="Enable debug output") | ||||
|  |     global_config = parser.parse_args() | ||||
|  | 
 | ||||
|  |     # Load ahoy.yml config file | ||||
|  |     try: | ||||
|  |         if isinstance(global_config.config_file, str) == True: | ||||
|  |             with open(global_config.config_file, 'r') as yf: | ||||
|  |                 cfg = yaml.load(yf, Loader=SafeLoader) | ||||
|  |         else: | ||||
|  |             with open('ahoy.yml', 'r') as yf: | ||||
|  |                 cfg = yaml.load(yf, Loader=SafeLoader) | ||||
|  |     except FileNotFoundError: | ||||
|  |         print("Could not load config file. Try --help") | ||||
|  |         sys.exit(2) | ||||
|  |     except yaml.YAMLError as ye: | ||||
|  |         print('Failed to load config frile {global_config.config_file}: {ye}') | ||||
|  |         sys.exit(1) | ||||
|  | 
 | ||||
|  |     ahoy_config = dict(cfg.get('ahoy', {})) | ||||
|  | 
 | ||||
|  |     # Prepare for multiple transceivers, makes them configurable (currently | ||||
|  |     # only one supported) | ||||
|  |     for radio_config in ahoy_config.get('nrf', [{}]): | ||||
|  |         radio = RF24( | ||||
|  |                 radio_config.get('ce_pin', 22), | ||||
|  |                 radio_config.get('cs_pin', 0), | ||||
|  |                 radio_config.get('spispeed', 1000000)) | ||||
|  |         hmradio = hoymiles.HoymilesNRF(device=radio) | ||||
|  | 
 | ||||
|  |     mqtt_client = None | ||||
|  | 
 | ||||
|  |     command_queue = {} | ||||
|  |     mqtt_command_topic_subs = [] | ||||
|  | 
 | ||||
|  |     if global_config.log_transactions: | ||||
|  |         hoymiles.HOYMILES_TRANSACTION_LOGGING=True | ||||
|  |     if global_config.verbose: | ||||
|  |         hoymiles.HOYMILES_DEBUG_LOGGING=True | ||||
|  | 
 | ||||
|  |     mqtt_config = ahoy_config.get('mqtt', []) | ||||
|  |     if not mqtt_config.get('disabled', False): | ||||
|  |         mqtt_client = paho.mqtt.client.Client() | ||||
|  |         mqtt_client.username_pw_set(mqtt_config.get('user', None), mqtt_config.get('password', None)) | ||||
|  |         mqtt_client.connect(mqtt_config.get('host', '127.0.0.1'), mqtt_config.get('port', 1883)) | ||||
|  |         mqtt_client.loop_start() | ||||
|  |         mqtt_client.on_message = mqtt_on_command | ||||
|  | 
 | ||||
|  |     if not radio.begin(): | ||||
|  |         raise RuntimeError('Can\'t open radio') | ||||
|  | 
 | ||||
|  |     inverters = [inverter.get('serial') for inverter in ahoy_config.get('inverters', [])] | ||||
|  |     for inverter in ahoy_config.get('inverters', []): | ||||
|  |         inverter_ser = inverter.get('serial') | ||||
|  |         command_queue[str(inverter_ser)] = [] | ||||
|  | 
 | ||||
|  |         # | ||||
|  |         # Enables and subscribe inverter to mqtt /command-Topic | ||||
|  |         # | ||||
|  |         if inverter.get('mqtt', {}).get('send_raw_enabled', False): | ||||
|  |             topic_item = ( | ||||
|  |                     str(inverter_ser), | ||||
|  |                     inverter.get('mqtt', {}).get('topic', f'hoymiles/{inverter_ser}') + '/command' | ||||
|  |                     ) | ||||
|  |             mqtt_client.subscribe(topic_item[1]) | ||||
|  |             mqtt_command_topic_subs.append(topic_item) | ||||
|  | 
 | ||||
|  |     loop_interval = ahoy_config.get('interval', 1) | ||||
|  |     try: | ||||
|  |         while True: | ||||
|  |             t_loop_start = time.time() | ||||
|  | 
 | ||||
|  |             main_loop() | ||||
|  | 
 | ||||
|  |             print('', end='', flush=True) | ||||
|  | 
 | ||||
|  |             if loop_interval > 0 and (time.time() - t_loop_start) < loop_interval: | ||||
|  |                 time.sleep(time.time() % loop_interval) | ||||
|  | 
 | ||||
|  |     except KeyboardInterrupt: | ||||
|  |         radio.powerDown() | ||||
|  |         sys.exit() | ||||
					Loading…
					
					
				
		Reference in new issue