summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/inverter_bot.py91
1 files changed, 91 insertions, 0 deletions
diff --git a/src/inverter_bot.py b/src/inverter_bot.py
index 0807b23..d4749d2 100755
--- a/src/inverter_bot.py
+++ b/src/inverter_bot.py
@@ -4,6 +4,7 @@ import re
import datetime
import json
+from enum import Enum
from inverterd import Format, InverterError
from html import escape
from typing import Optional, Tuple, Union
@@ -51,7 +52,14 @@ flags_map = {
'fault_code_record': 'FTCR',
}
logger = logging.getLogger(__name__)
+
SETACMODE_STARTED, = range(1)
+SETOSP_STARTED, = range(1)
+
+
+class OutputSourcePriority(Enum):
+ SolarUtilityBattery = 'SUB'
+ SolarBatteryUtility = 'SBU'
def monitor_charging(event: ChargingEvent, **kwargs) -> None:
@@ -283,6 +291,14 @@ def setacmode(mode: ACMode):
inverter.exec('set-max-ac-charge-current', (0, a))
+def setosp(sp: OutputSourcePriority):
+ logger.debug(f'setosp: sp={sp}')
+ inverter.exec('set-output-charge-priority', (sp,))
+
+
+# /setacmode
+# ----------
+
def setacmode_start(ctx: Context) -> None:
if monitor.active_current is not None:
raise RuntimeError('generator charging program is active')
@@ -338,6 +354,60 @@ def setacmode_cancel(ctx: Context):
return ConversationHandler.END
+# /setosp
+# ------
+
+def setosp_start(ctx: Context) -> None:
+ buttons = []
+ for sp in OutputSourcePriority:
+ buttons.append(ctx.lang(f'setosp_{sp.value.lower()}'))
+ markup = ReplyKeyboardMarkup([buttons, [ctx.lang('cancel')]], one_time_keyboard=False)
+
+ ctx.reply(ctx.lang('select_ac_mode'), markup=markup)
+ return SETOSP_STARTED
+
+
+def setosp_input(ctx: Context):
+ selected_sp = None
+ for sp in OutputSourcePriority:
+ if ctx.text == ctx.lang(f'setosp_{sp.value.lower()}'):
+ selected_sp = sp
+ break
+
+ if selected_sp is None:
+ raise ValueError('invalid sp')
+
+ # apply the mode
+ setosp(selected_sp)
+
+ # reply to user
+ ctx.reply(ctx.lang('saved'), markup=IgnoreMarkup())
+
+ # notify other users
+ bot.notify_all(
+ lambda lang: bot.lang.get('osp_changed_notification', lang,
+ ctx.user.id, ctx.user.name,
+ bot.lang.get(str(selected_sp.value), lang)),
+ exclude=(ctx.user_id,)
+ )
+
+ bot.start(ctx)
+ return ConversationHandler.END
+
+
+def setosp_invalid(ctx: Context):
+ ctx.reply(ctx.lang('invalid_mode'), markup=IgnoreMarkup())
+ return SETOSP_STARTED
+
+
+def setosp_cancel(ctx: Context):
+ bot.start(ctx)
+ return ConversationHandler.END
+
+
+# other
+# -----
+
def setbatuv(ctx: Context) -> None:
try:
v = float(ctx.args[0])
@@ -423,6 +493,7 @@ class InverterBot(Wrapper):
done="Готово",
unexpected_callback_data="Ошибка: неверные данные",
select_ac_mode="Выберите режим:",
+ select_priortiy="Установите приоритет:",
invalid_input="Неверное значение",
flags_press_button='Нажмите кнопку для переключения настройки',
@@ -457,6 +528,9 @@ class InverterBot(Wrapper):
setgenct_dv=f'напряжение отключения заряда, 48 {LT} DV {LT} 58',
setgencc_a='максимальный ток заряда, допустимые значения: %s',
+ setosp_sub='Solar-Utility-Battery',
+ setosp_sbu='Solar-Battery-Utility',
+
# monitor
chrg_evt_started='✅ Начали заряжать от генератора.',
chrg_evt_finished='✅ Зарядили. Генератор пора выключать.',
@@ -477,6 +551,7 @@ class InverterBot(Wrapper):
# other notifications
ac_mode_changed_notification='Пользователь <a href="tg://user?id=%d">%s</a> установил режим AC: <b>%s</b>.',
+ osp_changed_notification='Пользователь <a href="tg://user?id=%d">%s</a> установил приоритет источника питания нагрузки: <b>%s</b>.',
bat_state_normal='Нормальный',
bat_state_low='Низкий',
@@ -493,6 +568,7 @@ class InverterBot(Wrapper):
done="Done",
unexpected_callback_data="Unexpected callback data",
select_ac_mode="Select AC input mode:",
+ select_priortiy="Select priority:",
invalid_input="Invalid input",
flags_press_button='Press a button to toggle a flag.',
@@ -527,6 +603,9 @@ class InverterBot(Wrapper):
setgenct_dv=f'discharging voltage, 48 {LT} DV {LT} 58',
setgencc_a='max charging current, allowed values: %s',
+ setosp_sub='Solar-Utility-Battery',
+ setosp_sbu='Solar-Battery-Utility',
+
# monitor
chrg_evt_started='✅ Started charging from AC.',
chrg_evt_finished='✅ Finished charging, it\'s time to stop the generator.',
@@ -547,6 +626,7 @@ class InverterBot(Wrapper):
# other notifications
ac_mode_changed_notification='User <a href="tg://user?id=%d">%s</a> set AC mode to <b>%s</b>.',
+ osp_changed_notification='Пользователь <a href="tg://user?id=%d">%s</a> set output source priority: <b>%s</b>.',
bat_state_normal='Normal',
bat_state_low='Low',
@@ -585,6 +665,17 @@ class InverterBot(Wrapper):
fallbacks=[MessageHandler(self.user_filter & cancel_filter, self.wrap(setacmode_cancel))]
))
+ self.add_handler(ConversationHandler(
+ entry_points=[CommandHandler('setosp', self.wrap(setosp_start), self.user_filter)],
+ states={
+ SETOSP_STARTED: [
+ *[MessageHandler(text_filter(self.lang.all(f'setosp_{sp.value.lower()}')), self.wrap(setosp_input)) for sp in OutputSourcePriority],
+ MessageHandler(self.user_filter & ~cancel_filter, self.wrap(setosp_invalid))
+ ]
+ },
+ fallbacks=[MessageHandler(self.user_filter & cancel_filter, self.wrap(setosp_cancel))]
+ ))
+
super().run()
def markup(self, ctx: Optional[Context]) -> Optional[ReplyKeyboardMarkup]: