From ed205fba47a0e72103e81e8aaaf4f565d0d6bd00 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 4 Nov 2022 20:20:35 +0100 Subject: [PATCH 1/5] RPI: refactor: move more stuff into main_loop --- tools/rpi/hoymiles/__main__.py | 66 +++++++++++++++++----------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/tools/rpi/hoymiles/__main__.py b/tools/rpi/hoymiles/__main__.py index 0b558073..2b3ee5d6 100644 --- a/tools/rpi/hoymiles/__main__.py +++ b/tools/rpi/hoymiles/__main__.py @@ -17,17 +17,6 @@ from yaml.loader import SafeLoader import paho.mqtt.client import hoymiles -def main_loop(do_init): - """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, do_init) - class InfoCommands(IntEnum): InverterDevInform_Simple = 0 # 0x00 InverterDevInform_All = 1 # 0x01 @@ -48,6 +37,38 @@ class InfoCommands(IntEnum): GetSelfCheckState = 30 # 0x1e InitDataState = 0xff +def main_loop(ahoy_config): + """Main loop""" + inverters = [ + inverter for inverter in ahoy_config.get('inverters', []) + if not inverter.get('disabled', False)] + + loop_interval = ahoy_config.get('interval', 1) + try: + do_init = True + while True: + t_loop_start = time.time() + + for inverter in inverters: + if hoymiles.HOYMILES_DEBUG_LOGGING: + print(f'Poll inverter {inverter["serial"]}') + poll_inverter(inverter, do_init) + do_init = False + + print('', end='', flush=True) + + if loop_interval > 0: + time_to_sleep = loop_interval - (time.time() - t_loop_start) + if time_to_sleep > 0: + time.sleep(time_to_sleep) + + except KeyboardInterrupt: + sys.exit() + except Exception as e: + print ('Exception catched: %s' % e) + raise + + def poll_inverter(inverter, do_init, retries=4): """ Send/Receive command_queue, initiate status poll on inverter @@ -310,25 +331,4 @@ if __name__ == '__main__': mqtt_client.subscribe(topic_item[1]) mqtt_command_topic_subs.append(topic_item) - loop_interval = ahoy_config.get('interval', 1) - try: - do_init = True - while True: - t_loop_start = time.time() - - main_loop(do_init) - - do_init = False - - print('', end='', flush=True) - - time_to_sleep = loop_interval - (time.time() - t_loop_start) - - if loop_interval > 0 and time_to_sleep > 0: - time.sleep(time_to_sleep) - - except KeyboardInterrupt: - sys.exit() - except Exception as e: - print ('Exception catched: %s' % e) - raise + main_loop(ahoy_config) From ac45ff71084609460df03d60a4b82c52ba3db587 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Fri, 4 Nov 2022 21:19:51 +0100 Subject: [PATCH 2/5] RPI: don't try to reach inverter after sunset, will not work for polar day or night but should be easy to add if really needed --- tools/rpi/README.md | 2 +- tools/rpi/ahoy.yml.example | 8 ++++++-- tools/rpi/hoymiles/__main__.py | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/tools/rpi/README.md b/tools/rpi/README.md index 1027ccb0..bc8b23c0 100644 --- a/tools/rpi/README.md +++ b/tools/rpi/README.md @@ -86,7 +86,7 @@ Required python modules Some modules are not installed by default on a RaspberryPi, therefore add them manually: ``` -pip install crcmod pyyaml paho-mqtt +pip install crcmod pyyaml paho-mqtt SunTimes ``` Configuration diff --git a/tools/rpi/ahoy.yml.example b/tools/rpi/ahoy.yml.example index 644508e5..58866816 100644 --- a/tools/rpi/ahoy.yml.example +++ b/tools/rpi/ahoy.yml.example @@ -1,8 +1,12 @@ --- ahoy: - interval: 0 - sunset: true + interval: 5 + sunset: + disabled: false + latitude: 51.799118 + longitude: 10.615523 + altitude: 1142 # List of available NRF24 transceivers nrf: diff --git a/tools/rpi/hoymiles/__main__.py b/tools/rpi/hoymiles/__main__.py index 2b3ee5d6..181dfd0b 100644 --- a/tools/rpi/hoymiles/__main__.py +++ b/tools/rpi/hoymiles/__main__.py @@ -11,6 +11,8 @@ from enum import IntEnum import re import time from datetime import datetime +from datetime import timedelta +from suntimes import SunTimes import argparse import yaml from yaml.loader import SafeLoader @@ -37,16 +39,49 @@ class InfoCommands(IntEnum): GetSelfCheckState = 30 # 0x1e InitDataState = 0xff +class SunsetHandler: + def __init__(self, sunset_config): + self.sunset = None + if sunset_config and sunset_config.get('disabled', True) == False: + latitude = sunset_config.get('latitude') + longitude = sunset_config.get('longitude') + altitude = sunset_config.get('altitude') + self.suntimes = SunTimes(longitude=longitude, latitude=latitude, altitude=altitude) + now = datetime.now() + self.nextSunset = self.suntimes.setutc(now) + print (f'Todays sunset is at {self.nextSunset}') + + def checkWaitForSunrise(self): + if not self.suntimes: + return + # if the sunset already happened for today + now = datetime.now() + if self.nextSunset < now: + # wait until the sun rises tomorrow + nextSunrise = self.suntimes.riseutc(now + timedelta(days=1)) + self.nextSunset = self.suntimes.setutc(now + timedelta(days=1)) + time_to_sleep = (nextSunrise - datetime.now()).total_seconds() + print (f'Waiting for sunrise at {nextSunrise} ({time_to_sleep} seconds)') + if time_to_sleep > 0: + time.sleep(time_to_sleep) + now = datetime.now() + print (f'Woke up... next sunset is at {self.nextSunset}') + return + def main_loop(ahoy_config): """Main loop""" inverters = [ inverter for inverter in ahoy_config.get('inverters', []) if not inverter.get('disabled', False)] + sunset = SunsetHandler(ahoy_config.get('sunset')) + loop_interval = ahoy_config.get('interval', 1) try: do_init = True while True: + sunset.checkWaitForSunrise() + t_loop_start = time.time() for inverter in inverters: From 5beed9d8e076e58de04c64c60349efc33a2b3bc5 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 6 Nov 2022 10:23:37 +0100 Subject: [PATCH 3/5] RPI: print backtrace for unhandled exception --- tools/rpi/hoymiles/__main__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/rpi/hoymiles/__main__.py b/tools/rpi/hoymiles/__main__.py index 181dfd0b..6e3b2c2c 100644 --- a/tools/rpi/hoymiles/__main__.py +++ b/tools/rpi/hoymiles/__main__.py @@ -10,6 +10,7 @@ import struct from enum import IntEnum import re import time +import traceback from datetime import datetime from datetime import timedelta from suntimes import SunTimes @@ -101,6 +102,7 @@ def main_loop(ahoy_config): sys.exit() except Exception as e: print ('Exception catched: %s' % e) + traceback.print_exc() raise From 4c52f078897d87cb4eae2259f89d954242061a3b Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Sun, 6 Nov 2022 20:02:12 +0100 Subject: [PATCH 4/5] RPI: cleanup SunsetHandler --- tools/rpi/hoymiles/__main__.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/rpi/hoymiles/__main__.py b/tools/rpi/hoymiles/__main__.py index 6e3b2c2c..5f783ac4 100644 --- a/tools/rpi/hoymiles/__main__.py +++ b/tools/rpi/hoymiles/__main__.py @@ -42,14 +42,13 @@ class InfoCommands(IntEnum): class SunsetHandler: def __init__(self, sunset_config): - self.sunset = None + self.suntimes = None if sunset_config and sunset_config.get('disabled', True) == False: latitude = sunset_config.get('latitude') longitude = sunset_config.get('longitude') altitude = sunset_config.get('altitude') self.suntimes = SunTimes(longitude=longitude, latitude=latitude, altitude=altitude) - now = datetime.now() - self.nextSunset = self.suntimes.setutc(now) + self.nextSunset = self.suntimes.setutc(datetime.now()) print (f'Todays sunset is at {self.nextSunset}') def checkWaitForSunrise(self): @@ -59,14 +58,14 @@ class SunsetHandler: now = datetime.now() if self.nextSunset < now: # wait until the sun rises tomorrow - nextSunrise = self.suntimes.riseutc(now + timedelta(days=1)) - self.nextSunset = self.suntimes.setutc(now + timedelta(days=1)) + tomorrow = now + timedelta(days=1) + nextSunrise = self.suntimes.riseutc(tomorrow) + self.nextSunset = self.suntimes.setutc(tomorrow) time_to_sleep = (nextSunrise - datetime.now()).total_seconds() print (f'Waiting for sunrise at {nextSunrise} ({time_to_sleep} seconds)') if time_to_sleep > 0: time.sleep(time_to_sleep) - now = datetime.now() - print (f'Woke up... next sunset is at {self.nextSunset}') + print (f'Woke up... next sunset is at {self.nextSunset}') return def main_loop(ahoy_config): From 78d63b816eadfdf2ddbdcd1381c61dcf665309a5 Mon Sep 17 00:00:00 2001 From: stefan123t Date: Mon, 7 Nov 2022 19:23:32 +0100 Subject: [PATCH 5/5] Update README.md added hints for MI- and ESP32 versions in OpenDTU and DTUsimMI1x00-Hoymiles --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 45066d88..b61d1fe0 100644 --- a/README.md +++ b/README.md @@ -32,4 +32,6 @@ Please try to describe your issues as precise as possible and think about if thi ### Related Projects - [OpenDTU](https://github.com/tbnobody/OpenDTU) -- [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles) + <- Our sister project ✨ for Hoymiles HM-300, HM-600, HM-1200 (for ESP32 only!) +- [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles) + <- Go here ✨ for Hoymiles MI-300, MI-600, MI-1200 Software