diff options
author | Evgeny Zinoviev <me@ch1p.io> | 2022-10-19 05:07:09 +0300 |
---|---|---|
committer | Evgeny Zinoviev <me@ch1p.io> | 2022-10-19 05:07:12 +0300 |
commit | 809b1eacf8700d7527ce59bc40c0cf8071fcbe7c (patch) | |
tree | 4982b07a288a9afe9993e16132f6542a10b0430b | |
parent | e6d8f08732d5fc7e2d54846a06f8abe20630fd00 (diff) |
inverter: utilities-related notifications (not tested yet)
-rw-r--r-- | src/home/inverter/__init__.py | 3 | ||||
-rw-r--r-- | src/home/inverter/monitor.py | 45 | ||||
-rwxr-xr-x | src/inverter_bot.py | 42 |
3 files changed, 88 insertions, 2 deletions
diff --git a/src/home/inverter/__init__.py b/src/home/inverter/__init__.py index 374bc7b..967ddff 100644 --- a/src/home/inverter/__init__.py +++ b/src/home/inverter/__init__.py @@ -3,7 +3,8 @@ from .monitor import ( InverterMonitor, BatteryState, BatteryPowerDirection, - ACMode + ACMode, + ACPresentEvent ) from .inverter_wrapper import wrapper_instance from .util import beautify_table diff --git a/src/home/inverter/monitor.py b/src/home/inverter/monitor.py index 87e07be..edfd8f7 100644 --- a/src/home/inverter/monitor.py +++ b/src/home/inverter/monitor.py @@ -27,6 +27,15 @@ class ChargingEvent(Enum): AC_MOSTLY_CHARGED = auto() AC_CHARGING_FINISHED = auto() + UTIL_CHARGING_STARTED = auto() + UTIL_CHARGING_STOPPED = auto() + UTIL_CHARGING_STOPPED_SOLAR = auto() + + +class ACPresentEvent(Enum): + CONNECTED = auto() + DISCONNECTED = auto() + class ChargingState(Enum): NOT_CHARGING = auto() @@ -83,6 +92,7 @@ TODO: class InverterMonitor(Thread): charging_event_handler: Optional[Callable] battery_event_handler: Optional[Callable] + util_event_handler: Optional[Callable] error_handler: Optional[Callable] def __init__(self): @@ -96,6 +106,7 @@ class InverterMonitor(Thread): # Event handlers for the bot. self.charging_event_handler = None self.battery_event_handler = None + self.util_event_handler = None self.error_handler = None # Currents list, defined in the bot config. @@ -120,6 +131,11 @@ class InverterMonitor(Thread): # We don't want to damage our batteries, right? self.floating_stopwatch = Stopwatch() + # State variables for utilities charging program + self.util_ac_present = None + self.util_pd = None + self.util_solar = None + @property def active_current(self) -> Optional[int]: try: @@ -159,6 +175,8 @@ class InverterMonitor(Thread): if self.ac_mode == ACMode.GENERATOR: self.gen_charging_program(ac, solar, v, pd) + elif self.ac_mode == ACMode.UTILITIES: + self.utilities_monitoring_program(ac, solar, pd) if not ac or pd != BatteryPowerDirection.CHARGING: # if AC is disconnected or not charging, run the low voltage checking program @@ -173,6 +191,30 @@ class InverterMonitor(Thread): time.sleep(2) + def utilities_monitoring_program(self, + ac: bool, # whether AC is connected + solar: bool, # whether MPPT is active + pd: BatteryPowerDirection # current power direction + ): + pd_event_send = False + if self.util_solar is None or solar != self.util_solar: + self.util_solar = solar + if solar and self.util_ac_present and self.util_pd == BatteryPowerDirection.CHARGING: + self.charging_event_handler(ChargingEvent.UTIL_CHARGING_STOPPED_SOLAR) + pd_event_send = True + + if self.util_ac_present is None or ac != self.util_ac_present: + self.util_event_handler(ACPresentEvent.CONNECTED if ac else ACPresentEvent.DISCONNECTED) + self.util_ac_present = ac + + if self.util_pd is None or self.util_pd != pd: + if not pd_event_send: + if pd == BatteryPowerDirection.CHARGING: + self.charging_event_handler(ChargingEvent.UTIL_CHARGING_STARTED) + else: + self.charging_event_handler(ChargingEvent.UTIL_CHARGING_STOPPED) + self.util_pd = pd + def gen_charging_program(self, ac: bool, # whether AC is connected solar: bool, # whether MPPT is active @@ -444,6 +486,9 @@ class InverterMonitor(Thread): def set_battery_event_handler(self, handler: Callable): self.battery_event_handler = handler + def set_util_event_handler(self, handler: Callable): + self.util_event_handler = handler + def set_error_handler(self, handler: Callable): self.error_handler = handler diff --git a/src/inverter_bot.py b/src/inverter_bot.py index 54b17c8..c647115 100755 --- a/src/inverter_bot.py +++ b/src/inverter_bot.py @@ -22,6 +22,7 @@ from home.inverter import ( InverterMonitor, ChargingEvent, + ACPresentEvent, BatteryState, ACMode ) @@ -55,6 +56,7 @@ SETACMODE_STARTED, = range(1) def monitor_charging(event: ChargingEvent, **kwargs) -> None: args = [] + is_util = False if event == ChargingEvent.AC_CHARGING_STARTED: key = 'started' elif event == ChargingEvent.AC_CHARGING_FINISHED: @@ -70,12 +72,24 @@ def monitor_charging(event: ChargingEvent, **kwargs) -> None: key = 'na_solar' elif event == ChargingEvent.AC_MOSTLY_CHARGED: key = 'mostly_charged' + elif event == ChargingEvent.UTIL_CHARGING_STOPPED: + key = 'started' + is_util = True + elif event == ChargingEvent.UTIL_CHARGING_STOPPED: + key = 'stopped' + is_util = True + elif event == ChargingEvent.UTIL_CHARGING_STOPPED_SOLAR: + key = 'stopped_solar' + is_util = True else: logger.error('unknown charging event:', event) return + key = f'chrg_evt_{key}' + if is_util: + key = f'util_{key}' bot.notify_all( - lambda lang: bot.lang.get(f'chrg_evt_{key}', lang, *args) + lambda lang: bot.lang.get(key, lang, *args) ) @@ -96,6 +110,17 @@ def monitor_battery(state: BatteryState, v: float, load_watts: int) -> None: ) +def monitor_util(event: ACPresentEvent): + if event == ACPresentEvent.CONNECTED: + key = 'connected' + else: + key = 'disconnected' + key = f'util_{key}' + bot.notify_all( + lambda lang: bot.lang.get(key, lang) + ) + + def monitor_error(error: str) -> None: bot.notify_all( lambda lang: bot.lang.get('error_message', lang, error) @@ -443,6 +468,13 @@ class InverterBot(Wrapper): battery_level_changed='Уровень заряда АКБ: <b>%s %s</b> (<b>%0.1f V</b> при нагрузке <b>%d W</b>)', error_message='<b>Ошибка:</b> %s.', + util_chrg_evt_started='✅ Начали заряжать от столба.', + util_chrg_evt_stopped='ℹ️ Перестали заряжать от столба.', + util_chrg_evt_stopped_solar='ℹ️ Перестали заряжать от столба из-за подключения панелей.', + + util_connected='✅️ Столб подключен.', + util_disconnected='‼️ Столб отключён.', + # other notifications ac_mode_changed_notification='Пользователь <a href="tg://user?id=%d">%s</a> установил режим AC: <b>%s</b>.', @@ -506,6 +538,13 @@ class InverterBot(Wrapper): battery_level_changed='Battery level: <b>%s</b> (<b>%0.1f V</b> under <b>%d W</b> load)', error_message='<b>Error:</b> %s.', + util_chrg_evt_started='✅ Started charging from utilities.', + util_chrg_evt_stopped='ℹ️ Stopped charging from utilities.', + util_chrg_evt_stopped_solar='ℹ️ Stopped charging from utilities because solar panels were connected.', + + util_connected='✅️ Utilities connected.', + util_disconnected='‼️ Utilities disconected.', + # other notifications ac_mode_changed_notification='User <a href="tg://user?id=%d">%s</a> set AC mode to <b>%s</b>.', @@ -603,6 +642,7 @@ if __name__ == '__main__': monitor = InverterMonitor() monitor.set_charging_event_handler(monitor_charging) monitor.set_battery_event_handler(monitor_battery) + monitor.set_util_event_handler(monitor_util) monitor.set_error_handler(monitor_error) monitor.start() |