updating configuration
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import os
|
import os
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# App to send notification when doorbell is ringing
|
# App to send notification when doorbell is ringing
|
||||||
@@ -26,10 +27,9 @@ class Doorbell(hass.Hass):
|
|||||||
def ha_event(self, event_name, data, kwargs):
|
def ha_event(self, event_name, data, kwargs):
|
||||||
self.log('{}:{}'.format(event_name, data))
|
self.log('{}:{}'.format(event_name, data))
|
||||||
|
|
||||||
self.notify("Звонок в дверь!!!", name = self.args['notify'])
|
globals.send_telegram(self, "Звонок в дверь!!!", target = self.args['notify'])
|
||||||
if 'doorbell_pic' in data:
|
if 'doorbell_pic' in data:
|
||||||
extra_data = {'photo': {'url':data['doorbell_pic']}}
|
globals.send_telegram_photo(self, data['doorbell_pic'], target = self.args['notify'], caption = "Фото звонившего")
|
||||||
self.notify("Фото звонившего", name = self.args['notify'], data=extra_data)
|
|
||||||
|
|
||||||
self.say('Звонок в дверь')
|
self.say('Звонок в дверь')
|
||||||
|
|
||||||
|
|||||||
@@ -2,22 +2,59 @@ import importlib
|
|||||||
import subprocess
|
import subprocess
|
||||||
from typing import Any, Tuple, Union
|
from typing import Any, Tuple, Union
|
||||||
|
|
||||||
#
|
|
||||||
# Global module
|
|
||||||
# contain global functions
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
#
|
|
||||||
# None
|
|
||||||
#
|
|
||||||
# Release Notes
|
|
||||||
#
|
|
||||||
# Version 1.0:
|
|
||||||
# Initial Version
|
|
||||||
|
|
||||||
"""Define various constants."""
|
"""Define various constants."""
|
||||||
CONF_PEOPLE = 'people'
|
CONF_PEOPLE = 'people'
|
||||||
|
|
||||||
|
# --- Telegram notifications -------------------------------------------------
|
||||||
|
#
|
||||||
|
# HA 2026.2 deprecated the per-platform notify.telegram* services in favour
|
||||||
|
# of entity-based targeting (see repairs.issue_registry: telegram/migrate_notify).
|
||||||
|
# The generic notify.send_message service only supports message/title, so it
|
||||||
|
# can't carry parse_mode/photo/keyboard payloads our apps rely on - instead we
|
||||||
|
# target the telegram_bot integration's own (non-deprecated) domain services
|
||||||
|
# (telegram_bot.send_message / telegram_bot.send_photo) with entity_id, which
|
||||||
|
# is the current 1:1 replacement for the old chat_id-based notify.telegram*.
|
||||||
|
#
|
||||||
|
# Entity ids come from .storage/core.entity_registry (platform: telegram_bot),
|
||||||
|
# mapped from the friendly names ('telegram', 'telegram_monster',
|
||||||
|
# 'telegram_sveta') used throughout apps.yaml configs.
|
||||||
|
TELEGRAM_TARGETS = {
|
||||||
|
'telegram': 'notify.home_assistant_fonvizina_fonvizina_18_1001567589226',
|
||||||
|
'telegram_monster': 'notify.home_assistant_fonvizina_monster_123622180',
|
||||||
|
'telegram_sveta': 'notify.home_assistant_fonvizina_svetlana_205225134',
|
||||||
|
}
|
||||||
|
|
||||||
|
def send_telegram(self, message, target='telegram', parse_mode='html', **kwargs):
|
||||||
|
"""Send a Telegram text message via telegram_bot.send_message.
|
||||||
|
|
||||||
|
Replacement for the deprecated `self.notify(message, name=target)`.
|
||||||
|
`target` is a friendly name from TELEGRAM_TARGETS (falls back to the
|
||||||
|
default group chat if unknown). Extra kwargs (title, keyboard, etc.) are
|
||||||
|
passed straight through to the service call.
|
||||||
|
"""
|
||||||
|
entity_id = TELEGRAM_TARGETS.get(target, TELEGRAM_TARGETS['telegram'])
|
||||||
|
service_data = {'entity_id': entity_id, 'message': message}
|
||||||
|
if parse_mode:
|
||||||
|
service_data['parse_mode'] = parse_mode
|
||||||
|
service_data.update(kwargs)
|
||||||
|
self.call_service('telegram_bot/send_message', **service_data)
|
||||||
|
|
||||||
|
def send_telegram_photo(self, url, target='telegram', caption=None, parse_mode='html', **kwargs):
|
||||||
|
"""Send a photo via telegram_bot.send_photo.
|
||||||
|
|
||||||
|
Replacement for the deprecated `self.notify(msg, name=target,
|
||||||
|
data={'photo': {'url': url}})`.
|
||||||
|
"""
|
||||||
|
entity_id = TELEGRAM_TARGETS.get(target, TELEGRAM_TARGETS['telegram'])
|
||||||
|
service_data = {'entity_id': entity_id, 'url': url}
|
||||||
|
if caption:
|
||||||
|
service_data['caption'] = caption
|
||||||
|
if parse_mode:
|
||||||
|
service_data['parse_mode'] = parse_mode
|
||||||
|
service_data.update(kwargs)
|
||||||
|
self.call_service('telegram_bot/send_photo', **service_data)
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
def most_common(the_list: list) -> Any:
|
def most_common(the_list: list) -> Any:
|
||||||
"""Return the most common element in a list."""
|
"""Return the most common element in a list."""
|
||||||
return max(set(the_list), key=the_list.count)
|
return max(set(the_list), key=the_list.count)
|
||||||
@@ -57,12 +94,8 @@ def get_group_entities(self, group):
|
|||||||
return []
|
return []
|
||||||
if 'attributes' in attributes:
|
if 'attributes' in attributes:
|
||||||
attributes = attributes['attributes']
|
attributes = attributes['attributes']
|
||||||
|
|
||||||
#group
|
|
||||||
if "entity_id" in attributes:
|
if "entity_id" in attributes:
|
||||||
return attributes["entity_id"]
|
return attributes["entity_id"]
|
||||||
|
|
||||||
#simple item
|
|
||||||
return [group]
|
return [group]
|
||||||
|
|
||||||
def turn_on(self, entity_id, state):
|
def turn_on(self, entity_id, state):
|
||||||
@@ -78,14 +111,12 @@ def turn_off(self, entity_id, state):
|
|||||||
self.turn_off(entity_id, state)
|
self.turn_off(entity_id, state)
|
||||||
|
|
||||||
def notification(self, to, message):
|
def notification(self, to, message):
|
||||||
self.notify(message, name = "telegram")
|
send_telegram(self, message, target = "telegram")
|
||||||
|
|
||||||
|
|
||||||
def get_arg(args, key):
|
def get_arg(args, key):
|
||||||
key = args[key]
|
key = args[key]
|
||||||
return key
|
return key
|
||||||
|
|
||||||
|
|
||||||
def get_arg_list(args, key):
|
def get_arg_list(args, key):
|
||||||
arg_list = []
|
arg_list = []
|
||||||
if isinstance(args[key], list):
|
if isinstance(args[key], list):
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Aqara lock notifications
|
# Aqara lock notifications
|
||||||
@@ -51,5 +52,4 @@ class AqaraLock(hass.Hass):
|
|||||||
self.notify_tg("Неизвестное событие замка: {}".format(eventname))
|
self.notify_tg("Неизвестное событие замка: {}".format(eventname))
|
||||||
|
|
||||||
def notify_tg(self, msg):
|
def notify_tg(self, msg):
|
||||||
extra_data = {'parse_mode': 'html'}
|
globals.send_telegram(self, msg, target = self.args['notify'])
|
||||||
self.notify(msg, name = self.args['notify'], data=extra_data)
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
from automation import Automation, Base # type: ignore
|
from automation import Automation, Base # type: ignore
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -61,5 +62,4 @@ class Balance(Base):
|
|||||||
def notify_tg(self, msg):
|
def notify_tg(self, msg):
|
||||||
if not 'notify' in self.args:
|
if not 'notify' in self.args:
|
||||||
return
|
return
|
||||||
extra_data = {'parse_mode': 'html'}
|
globals.send_telegram(self, msg, target = self.args['notify'])
|
||||||
self.notify(msg, name = self.args['notify'], data=extra_data)
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# App to send email report for devices running low on battery
|
# App to send email report for devices running low on battery
|
||||||
@@ -62,4 +63,4 @@ class Battery(hass.Hass):
|
|||||||
|
|
||||||
if low: # or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
if low: # or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
||||||
if message != "":
|
if message != "":
|
||||||
self.notify(message, name = "telegram")
|
globals.send_telegram(self, message)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
|
|
||||||
class BMSMonitor(hass.Hass):
|
class BMSMonitor(hass.Hass):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
@@ -159,7 +160,6 @@ class BMSMonitor(hass.Hass):
|
|||||||
|
|
||||||
def send_telegram(self, message, parse_mode="html"):
|
def send_telegram(self, message, parse_mode="html"):
|
||||||
try:
|
try:
|
||||||
extra_data = {'parse_mode': parse_mode}
|
globals.send_telegram(self, message, target = self.notification_target, parse_mode = parse_mode)
|
||||||
self.notify(message, name = self.notification_target, data=extra_data)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Ошибка отправки Telegram: {e}")
|
self.log(f"Ошибка отправки Telegram: {e}")
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
from datetime import timedelta
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# App to show dishwasher state
|
# App to show dishwasher state
|
||||||
@@ -18,58 +16,75 @@ import datetime
|
|||||||
|
|
||||||
class Dishwasher(hass.Hass):
|
class Dishwasher(hass.Hass):
|
||||||
listen_event_handle_list = []
|
listen_event_handle_list = []
|
||||||
run_state = ""
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if 'run_state' not in self.args or 'door_sensor' not in self.args or 'counter' not in self.args:
|
if 'run_state' not in self.args or 'door_sensor' not in self.args or 'counter' not in self.args or 'state_extended' not in self.args:
|
||||||
self.log("Please define all args")
|
self.log("Please define all args")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.listen_event_handle_list.append(self.listen_state(self.door_state_change, self.args['door_sensor'])) #, attribute='action'
|
self.listen_event_handle_list.append(self.listen_state(self.door_state_change, self.args['door_sensor']))
|
||||||
self.listen_event_handle_list.append(self.listen_state(self.run_state_change, self.args['run_state'])) #, attribute='action'
|
self.listen_event_handle_list.append(self.listen_state(self.run_state_change, self.args['run_state']))
|
||||||
|
|
||||||
|
|
||||||
|
def get_extended_state(self):
|
||||||
|
return self.get_state(self.args['state_extended'])
|
||||||
|
|
||||||
|
def set_extended_state(self, state):
|
||||||
|
self.call_service("input_select/select_option", entity_id = self.args['state_extended'], option = state)
|
||||||
|
|
||||||
def door_state_change(self, entity, attribute, old, new, kwargs):
|
def door_state_change(self, entity, attribute, old, new, kwargs):
|
||||||
if (new == "on"):
|
if new != "on":
|
||||||
self.call_service("counter/increment", entity_id = self.args['counter'])
|
return
|
||||||
if (self.run_state == "finished"):
|
|
||||||
self.run_state = "collecting"
|
self.call_service("counter/increment", entity_id = self.args['counter'])
|
||||||
self.set_light_state_by_counter()
|
extended_state = self.get_extended_state()
|
||||||
|
open_count = int(self.get_state(self.args['counter']))
|
||||||
|
|
||||||
|
if extended_state == "Washed":
|
||||||
|
self.set_extended_state("Empty")
|
||||||
|
elif extended_state == "Empty":
|
||||||
|
if open_count < 10:
|
||||||
|
self.set_extended_state("Collecting Dishes")
|
||||||
|
elif open_count > 10:
|
||||||
|
self.set_extended_state("Ready to wash")
|
||||||
|
elif extended_state == "Collecting Dishes" and open_count > 10:
|
||||||
|
self.set_extended_state("Ready to wash")
|
||||||
|
|
||||||
|
self.set_light_state_by_counter()
|
||||||
|
|
||||||
def run_state_change(self, entity, attribute, old, new, kwargs):
|
def run_state_change(self, entity, attribute, old, new, kwargs):
|
||||||
self.log("event: {}: {}->{}".format(attribute,old,new))
|
self.log("event: {}: {}->{}".format(attribute, old, new))
|
||||||
if (new == "Run"):
|
if new == "Run":
|
||||||
self.log('resetting counter')
|
self.log('resetting counter')
|
||||||
self.call_service("counter/reset", entity_id = self.args['counter'])
|
self.call_service("counter/reset", entity_id = self.args['counter'])
|
||||||
self.run_state = "washing"
|
self.set_extended_state("Washing")
|
||||||
if (new == "Finished"):
|
elif new == "Finished":
|
||||||
self.log('resetting counter')
|
self.log('resetting counter')
|
||||||
self.call_service("counter/reset", entity_id = self.args['counter'])
|
self.call_service("counter/reset", entity_id = self.args['counter'])
|
||||||
self.run_state = "finished"
|
self.set_extended_state("Washed")
|
||||||
|
|
||||||
self.log('Current state is: {}'.format(self.run_state))
|
self.log('Current state is: {}'.format(self.get_extended_state()))
|
||||||
self.set_light_state_by_counter()
|
self.set_light_state_by_counter()
|
||||||
|
|
||||||
def set_light_state_by_counter(self):
|
def set_light_state_by_counter(self):
|
||||||
state = self.get_state(self.args['counter'])
|
open_count = self.get_state(self.args['counter'])
|
||||||
open_count = int(state)
|
extended_state = self.get_extended_state()
|
||||||
self.log('counter state={}, machine state = {}'.format(state, self.run_state))
|
self.log('counter state={}, machine state = {}'.format(open_count, extended_state))
|
||||||
|
|
||||||
if (self.run_state == "finished"):
|
if extended_state == "Washed":
|
||||||
# Есть посуда, которую нужно разобрать
|
|
||||||
# red color
|
|
||||||
self.log('Time to take dishes out.')
|
self.log('Time to take dishes out.')
|
||||||
if 'lamp' in self.args:
|
if 'lamp' in self.args:
|
||||||
self.call_service("light/turn_on", entity_id = self.args['lamp'], rgb_color=[255, 0, 0]) #red
|
self.call_service("light/turn_on", entity_id = self.args['lamp'], rgb_color=[255, 0, 0])
|
||||||
|
|
||||||
elif (self.run_state == "washing"):
|
elif extended_state == "Washing":
|
||||||
self.log('washing in progress')
|
self.log('washing in progress')
|
||||||
self.call_service("light/turn_off", entity_id = self.args['lamp'])
|
if 'lamp' in self.args:
|
||||||
|
self.call_service("light/turn_off", entity_id = self.args['lamp'])
|
||||||
|
|
||||||
elif (open_count > 10):
|
elif extended_state == "Ready to wash":
|
||||||
self.log('Time to run dishwasher.')
|
self.log('Time to run dishwasher.')
|
||||||
if 'lamp' in self.args:
|
if 'lamp' in self.args:
|
||||||
self.call_service("light/turn_on", entity_id = self.args['lamp'], rgb_color=[245, 236, 0]) #yellow
|
self.call_service("light/turn_on", entity_id = self.args['lamp'], rgb_color=[245, 236, 0])
|
||||||
|
|
||||||
else:
|
elif 'lamp' in self.args:
|
||||||
self.call_service("light/turn_off", entity_id = self.args['lamp'])
|
self.call_service("light/turn_off", entity_id = self.args['lamp'])
|
||||||
@@ -5,9 +5,10 @@ dishwasher:
|
|||||||
class: Dishwasher
|
class: Dishwasher
|
||||||
module: dishwasher
|
module: dishwasher
|
||||||
constraint: input_boolean.dishwasher_state_light
|
constraint: input_boolean.dishwasher_state_light
|
||||||
counter: counter.dishwasher_door_open_count
|
counter: counter.bosch_dishwasher_door_open_count
|
||||||
door_sensor: binary_sensor.hc_dishwasher_door
|
door_sensor: binary_sensor.bosch_dishwasher_door
|
||||||
run_state: sensor.hc_dishwasher_state
|
run_state: sensor.bosch_dishwasher_operation_state
|
||||||
|
state_extended: input_select.bosch_dishwasher_state_extended
|
||||||
lamp: light.espresense_kitchen_led_1
|
lamp: light.espresense_kitchen_led_1
|
||||||
global_dependencies:
|
global_dependencies:
|
||||||
- globals
|
- globals
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
import random
|
||||||
|
|
||||||
|
#
|
||||||
|
# App to remind about dishwasher when someone enters the kitchen
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
#
|
||||||
|
# state_extended = input_select with extended dishwasher state
|
||||||
|
# motion_sensors = list of motion sensors to watch
|
||||||
|
# alice = Yandex Station media_player entity
|
||||||
|
# cooldown (optional) = seconds between reminders, default 1800
|
||||||
|
# constraint (optional) = input_boolean to enable/disable the app
|
||||||
|
#
|
||||||
|
# Release Notes
|
||||||
|
#
|
||||||
|
# Version 1.0:
|
||||||
|
# Initial Version
|
||||||
|
# Version 1.1:
|
||||||
|
# Added "Ready to wash" reminders
|
||||||
|
|
||||||
|
class DishwasherReminder(hass.Hass):
|
||||||
|
PHRASES_WASHED = [
|
||||||
|
"Посудомойка готова! Пора разобрать посуду.",
|
||||||
|
"Чистая посуда сидит в посудомойке как в Open Space — пора выпустить на волю.",
|
||||||
|
"Посудомойка отработала, теперь твоя очередь — разгрузить.",
|
||||||
|
"Тарелки уже высохли и скучают, спаси их из посудомойки.",
|
||||||
|
"Посудомойка не склад для чистого, разгрузи уже.",
|
||||||
|
"Грязной посуды нет, а чистая застряла внутри — спасательная операция!",
|
||||||
|
"Посудомойка помыла всё, осталось только разобрать. Ну же!",
|
||||||
|
"Чистые тарелки устроили вечеринку в посудомойке — пора их разогнать.",
|
||||||
|
"Не забудь разобрать посудомойку, иначе завтра некуда будет класть грязное.",
|
||||||
|
"Посудомойка ждёт разгрузки — всё помыто, высушено и нетерпеливо дребезжит.",
|
||||||
|
]
|
||||||
|
|
||||||
|
PHRASES_READY_TO_WASH = [
|
||||||
|
"Посудомойка скучает без работы — пора её запустить.",
|
||||||
|
"Гора посуды накопилась, посудомойка просит смелости нажать пуск.",
|
||||||
|
"Тарелки в посудомойке собрались на митинг — жми старт и отпусти их мыться.",
|
||||||
|
"Посудомойка готова к бою, осталось только нажать кнопку.",
|
||||||
|
"Хватит кормить посудомойку тарелками — пора включить и отдохнуть.",
|
||||||
|
"Посудомойка смотрит на тебя с надеждой — запускай программу.",
|
||||||
|
"Грязная посуда накопилась как снежный ком — время пустить посудомойку в ход.",
|
||||||
|
"Твои тарелки ждут водных процедур — включай посудомойку!",
|
||||||
|
"Посудомойка обидится, если её ещё раз оставят без дела — жми пуск.",
|
||||||
|
"Посуда застряла в посудомойке без мытья — самое время нажать старт и уйти пить чай.",
|
||||||
|
]
|
||||||
|
|
||||||
|
STATE_PHRASES = {
|
||||||
|
"Washed": PHRASES_WASHED,
|
||||||
|
"Ready to wash": PHRASES_READY_TO_WASH,
|
||||||
|
}
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
if 'state_extended' not in self.args or 'motion_sensors' not in self.args or 'alice' not in self.args:
|
||||||
|
self.log("Please define state_extended, motion_sensors and alice")
|
||||||
|
return
|
||||||
|
|
||||||
|
self.cooldown = self.args.get('cooldown', 1800)
|
||||||
|
self.last_announced = {}
|
||||||
|
|
||||||
|
for sensor in self.args['motion_sensors']:
|
||||||
|
self.listen_state(self.motion_detected, sensor)
|
||||||
|
|
||||||
|
def motion_detected(self, entity, attribute, old, new, kwargs):
|
||||||
|
if new != "on" or old == "on":
|
||||||
|
return
|
||||||
|
|
||||||
|
# if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||||
|
# self.log('disabled by constraint')
|
||||||
|
# return
|
||||||
|
|
||||||
|
state = self.get_state(self.args['state_extended'])
|
||||||
|
phrases = self.STATE_PHRASES.get(state)
|
||||||
|
if phrases is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
last = self.last_announced.get(state)
|
||||||
|
if last is not None:
|
||||||
|
elapsed = (self.datetime() - last).total_seconds()
|
||||||
|
if elapsed < self.cooldown:
|
||||||
|
self.log('cooldown active for {}, skipping'.format(state))
|
||||||
|
return
|
||||||
|
|
||||||
|
self.say(random.choice(phrases))
|
||||||
|
self.last_announced[state] = self.datetime()
|
||||||
|
|
||||||
|
def say(self, command):
|
||||||
|
self.log('command = {}'.format(command))
|
||||||
|
self.call_service('media_player/play_media', entity_id=self.args['alice'], media_content_type='text', media_content_id=command)
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#################################
|
||||||
|
# DISHWASHER REMINDER #
|
||||||
|
#################################
|
||||||
|
dishwasher_reminder:
|
||||||
|
class: DishwasherReminder
|
||||||
|
module: dishwasher_reminder
|
||||||
|
# constraint: input_boolean.dishwasher_reminder
|
||||||
|
state_extended: input_select.bosch_dishwasher_state_extended
|
||||||
|
motion_sensors:
|
||||||
|
- binary_sensor.motion_kitchenset_left_occupancy
|
||||||
|
- binary_sensor.motion_kitchenset_right_occupancy
|
||||||
|
alice: media_player.yandex_station_m00r46000m53db
|
||||||
|
cooldown: 3600
|
||||||
|
global_dependencies:
|
||||||
|
- globals
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# App to send reports about unsuccessfull auths
|
# App to send reports about unsuccessfull auths
|
||||||
@@ -24,5 +25,5 @@ class Security(hass.Hass):
|
|||||||
|
|
||||||
def state_change(self, entity, attribute, old, new, kwargs):
|
def state_change(self, entity, attribute, old, new, kwargs):
|
||||||
notifier = self.args.get('notify', 'telegram')
|
notifier = self.args.get('notify', 'telegram')
|
||||||
self.notify(new, name = notifier)
|
globals.send_telegram(self, new, target = notifier)
|
||||||
self.log(new)
|
self.log(new)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# App to send email report for devices running low on battery
|
# App to send email report for devices running low on battery
|
||||||
@@ -78,5 +79,4 @@ class Teeth(hass.Hass):
|
|||||||
notify = self.args["notify"]
|
notify = self.args["notify"]
|
||||||
now = datetime.datetime.now()+timedelta(hours=3)
|
now = datetime.datetime.now()+timedelta(hours=3)
|
||||||
message="Уже {}, а ты еще не почистил зубы. Самое время =)".format(now.strftime("%H:%M"))
|
message="Уже {}, а ты еще не почистил зубы. Самое время =)".format(now.strftime("%H:%M"))
|
||||||
self.notify(message, name = notify)
|
globals.send_telegram(self, message, target = notify)
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class WaterCountersAlarm(hass.Hass):
|
|||||||
|
|
||||||
if send_devices or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
if send_devices or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
||||||
if message != "":
|
if message != "":
|
||||||
self.notify(message, name = "telegram")
|
globals.send_telegram(self, message)
|
||||||
|
|
||||||
def check_checkup_dates(self, kwargs):
|
def check_checkup_dates(self, kwargs):
|
||||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||||
@@ -106,4 +106,4 @@ class WaterCountersAlarm(hass.Hass):
|
|||||||
|
|
||||||
if checkup_devices or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
if checkup_devices or ("always_send" in self.args and self.args["always_send"] == 1) or ("force" in kwargs and kwargs["force"] == 1):
|
||||||
if message != "":
|
if message != "":
|
||||||
self.notify(message, name = "telegram")
|
globals.send_telegram(self, message)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Notification system
|
# Notification system
|
||||||
@@ -42,7 +43,7 @@ class TelegramNotifyTarget(BaseNotifyTarget):
|
|||||||
target = self.target_sveta
|
target = self.target_sveta
|
||||||
|
|
||||||
hass.log('notifying over telegram person {} with message: {}'.format(target, message))
|
hass.log('notifying over telegram person {} with message: {}'.format(target, message))
|
||||||
hass.notify(message, name=target)
|
globals.send_telegram(hass, message, target=target)
|
||||||
|
|
||||||
class Notification(hass.Hass):
|
class Notification(hass.Hass):
|
||||||
home_targets = [AliceNotifyTarget()]
|
home_targets = [AliceNotifyTarget()]
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class ReportByPresence(hass.Hass):
|
|||||||
def return_home_mode(self, event_id, event_args, kwargs):
|
def return_home_mode(self, event_id, event_args, kwargs):
|
||||||
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
if 'constraint' in self.args and not self.constrain_input_boolean(self.args['constraint']):
|
||||||
return
|
return
|
||||||
self.notify("Добро пожаловать домой!", name = self.args['notify'])
|
globals.send_telegram(self, "Добро пожаловать домой!", target = self.args['notify'])
|
||||||
|
|
||||||
############# AWAY REPORT ##########################
|
############# AWAY REPORT ##########################
|
||||||
def send_report(self, kwargs):
|
def send_report(self, kwargs):
|
||||||
@@ -46,6 +46,6 @@ class ReportByPresence(hass.Hass):
|
|||||||
message += '{} ({}) = {}\n'.format(self.friendly_name(entity), entity, self.get_state(entity))
|
message += '{} ({}) = {}\n'.format(self.friendly_name(entity), entity, self.get_state(entity))
|
||||||
if any:
|
if any:
|
||||||
message = "В доме остались работать следующие устройства:\n" + message
|
message = "В доме остались работать следующие устройства:\n" + message
|
||||||
self.notify(message, name = self.args['notify'])
|
globals.send_telegram(self, message, target = self.args['notify'])
|
||||||
else:
|
else:
|
||||||
self.notify("Все устройства в доме выключены.", name = self.args['notify'])
|
globals.send_telegram(self, "Все устройства в доме выключены.", target = self.args['notify'])
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import datetime
|
import datetime
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Water control application.
|
# Water control application.
|
||||||
@@ -56,11 +57,11 @@ class WaterValveControl(hass.Hass):
|
|||||||
if name is None:
|
if name is None:
|
||||||
name = device
|
name = device
|
||||||
device_names += name
|
device_names += name
|
||||||
self.notify('В доме остались требующие воды устройства ({}), подача воды не будет отключена.'.format(device_names), name = self.args['notify'])
|
globals.send_telegram(self, 'В доме остались требующие воды устройства ({}), подача воды не будет отключена.'.format(device_names), target = self.args['notify'])
|
||||||
self.cancel_current_timer()
|
self.cancel_current_timer()
|
||||||
self.timers.append(self.run_every(self.wait_when_device_is_done, self.datetime()+datetime.timedelta(seconds=5), 5*60))
|
self.timers.append(self.run_every(self.wait_when_device_is_done, self.datetime()+datetime.timedelta(seconds=5), 5*60))
|
||||||
else:
|
else:
|
||||||
self.notify('Отключаю подачу воды.', name = self.args['notify'])
|
globals.send_telegram(self, 'Отключаю подачу воды.', target = self.args['notify'])
|
||||||
self.turn_off(self.args['water_valve'])
|
self.turn_off(self.args['water_valve'])
|
||||||
# for device in self.args['water_devices']:
|
# for device in self.args['water_devices']:
|
||||||
# self.turn_off(device)
|
# self.turn_off(device)
|
||||||
@@ -77,7 +78,7 @@ class WaterValveControl(hass.Hass):
|
|||||||
self.current_wait_cycle = self.current_wait_cycle+1
|
self.current_wait_cycle = self.current_wait_cycle+1
|
||||||
elif len(powered_on) == 0 and self.current_wait_cycle>=self.wait_cycles:
|
elif len(powered_on) == 0 and self.current_wait_cycle>=self.wait_cycles:
|
||||||
self.current_wait_cycle = 0
|
self.current_wait_cycle = 0
|
||||||
self.notify('Устройства требующие воды закончили свою работу, отключаю подачу воды.', name = self.args['notify'])
|
globals.send_telegram(self, 'Устройства требующие воды закончили свою работу, отключаю подачу воды.', target = self.args['notify'])
|
||||||
self.turn_off_water_devices()
|
self.turn_off_water_devices()
|
||||||
self.cancel_current_timer()
|
self.cancel_current_timer()
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ water_action:
|
|||||||
constraint: input_boolean.water_control
|
constraint: input_boolean.water_control
|
||||||
water_devices:
|
water_devices:
|
||||||
- binary_sensor.washer_running # стиралка
|
- binary_sensor.washer_running # стиралка
|
||||||
- binary_sensor.hc_dishwasher_running # посудомойка
|
- binary_sensor.bosch_dishwasher_running # посудомойка
|
||||||
global_dependencies:
|
global_dependencies:
|
||||||
- globals
|
- globals
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import requests
|
import requests
|
||||||
|
import globals
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class TelegramInternetControl(hass.Hass):
|
class TelegramInternetControl(hass.Hass):
|
||||||
@@ -39,8 +40,8 @@ class TelegramInternetControl(hass.Hass):
|
|||||||
"event.home_assistant_fonvizina_update_event"
|
"event.home_assistant_fonvizina_update_event"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Сервис для отправки ответов в Telegram
|
# Цель (friendly name из globals.TELEGRAM_TARGETS) для отправки ответов в Telegram
|
||||||
self.notify_service = self.args.get("notify_service", "notify/telegram")
|
self.notify_target = self.args.get("notify_target", "telegram")
|
||||||
|
|
||||||
# Сохраняем последнее обработанное время (для пропуска дублей)
|
# Сохраняем последнее обработанное время (для пропуска дублей)
|
||||||
self.last_processed_time = None
|
self.last_processed_time = None
|
||||||
@@ -257,10 +258,7 @@ class TelegramInternetControl(hass.Hass):
|
|||||||
Отправка ответа в Telegram.
|
Отправка ответа в Telegram.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
self.call_service(
|
globals.send_telegram(self, message, target = self.notify_target)
|
||||||
self.notify_service,
|
|
||||||
message=message
|
|
||||||
)
|
|
||||||
self.log(f"Telegram message sent: {message}")
|
self.log(f"Telegram message sent: {message}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log(f"Error sending Telegram message: {str(e)}")
|
self.log(f"Error sending Telegram message: {str(e)}")
|
||||||
@@ -23,5 +23,7 @@ keenetic:
|
|||||||
# Entity для прослушивания событий
|
# Entity для прослушивания событий
|
||||||
telegram_event_entity: "event.home_assistant_fonvizina_update_event"
|
telegram_event_entity: "event.home_assistant_fonvizina_update_event"
|
||||||
|
|
||||||
# Сервис для отправки уведомлений в Telegram
|
# Цель отправки уведомлений (friendly name из globals.TELEGRAM_TARGETS,
|
||||||
notify_service: "notify/telegram"
|
# см. appdaemon/settings/apps/globals.py). Раньше здесь был deprecated
|
||||||
|
# notify_service: "notify/telegram".
|
||||||
|
notify_target: "telegram"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Fire sensors alarm notification
|
# Fire sensors alarm notification
|
||||||
@@ -45,4 +46,4 @@ class FireSensorsReport(hass.Hass):
|
|||||||
friendly_name = self.friendly_name(entity)
|
friendly_name = self.friendly_name(entity)
|
||||||
entity = entity.replace('_', '-')
|
entity = entity.replace('_', '-')
|
||||||
message = "Сработал датчик пожарной сигнализации {} ({}) = {}-{}!".format(friendly_name, entity, old, new)
|
message = "Сработал датчик пожарной сигнализации {} ({}) = {}-{}!".format(friendly_name, entity, old, new)
|
||||||
self.notify(message, name = self.args['notify'])
|
globals.send_telegram(self, message, target = self.args['notify'])
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Security sensors alarm notification
|
# Security sensors alarm notification
|
||||||
@@ -56,4 +57,4 @@ class SecuritySensorsReport(hass.Hass):
|
|||||||
friendly_name = self.friendly_name(entity)
|
friendly_name = self.friendly_name(entity)
|
||||||
entity = entity.replace('_', '-')
|
entity = entity.replace('_', '-')
|
||||||
message = "В ваше отсутствие сработал датчик безопастности {} ({}) = {}->{}!".format(friendly_name, entity, old, new)
|
message = "В ваше отсутствие сработал датчик безопастности {} ({}) = {}->{}!".format(friendly_name, entity, old, new)
|
||||||
self.notify(message, name = self.args['notify'])
|
globals.send_telegram(self, message, target = self.args['notify'])
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
import globals
|
||||||
|
|
||||||
#
|
#
|
||||||
# Water leak detector
|
# Water leak detector
|
||||||
@@ -54,9 +55,9 @@ class WaterLeak(hass.Hass):
|
|||||||
self.call_service("mqtt/publish", topic = 'home/watercontrol/bath/valve/set', payload = 'close')
|
self.call_service("mqtt/publish", topic = 'home/watercontrol/bath/valve/set', payload = 'close')
|
||||||
|
|
||||||
message = "ВНИМАНИЕ! В ваше отстутствие сработал датчик протечки воды ({})!!! Выключаю подачу воды.".format(self.friendly_name(entity_id))
|
message = "ВНИМАНИЕ! В ваше отстутствие сработал датчик протечки воды ({})!!! Выключаю подачу воды.".format(self.friendly_name(entity_id))
|
||||||
self.notify(message, name = self.args['notify'])
|
globals.send_telegram(self, message, target = self.args['notify'])
|
||||||
|
|
||||||
message = "Состояние датчиков протечки:\n"
|
message = "Состояние датчиков протечки:\n"
|
||||||
for entity_id in self.sensors:
|
for entity_id in self.sensors:
|
||||||
message += '{} ({}) = {}\n'.format(self.friendly_name(entity_id), entity_id, self.get_state(entity_id))
|
message += '{} ({}) = {}\n'.format(self.friendly_name(entity_id), entity_id, self.get_state(entity_id))
|
||||||
self.notify(message, name = self.args['notify'])
|
globals.send_telegram(self, message, target = self.args['notify'])
|
||||||
|
|||||||
@@ -167,5 +167,4 @@ class EpdBalanceSensor(hass.Hass):
|
|||||||
def notify_tg(self, msg):
|
def notify_tg(self, msg):
|
||||||
if not 'notify' in self.args:
|
if not 'notify' in self.args:
|
||||||
return
|
return
|
||||||
extra_data = {'parse_mode': 'html'}
|
globals.send_telegram(self, msg, target = self.args['notify'])
|
||||||
self.notify(msg, name = self.args['notify'], data=extra_data)
|
|
||||||
|
|||||||
@@ -7,14 +7,17 @@ Arguments:
|
|||||||
- events: List of events to monitor
|
- events: List of events to monitor
|
||||||
"""
|
"""
|
||||||
class Test(hass.Hass):
|
class Test(hass.Hass):
|
||||||
notify = None
|
# notify = None
|
||||||
|
|
||||||
def initialize(self) -> None:
|
def initialize(self) -> None:
|
||||||
self.listen_state(self.sensor_trigger, 'sensor.0x00158d0003a361d8_action')
|
self.log("hello")
|
||||||
self.listen_state(self.sensor_trigger, 'binary_sensor.0x00158d0003f26d61_occupancy')
|
# notifier = self.args.get("notify", "telegram")
|
||||||
# self.listen_state(self.sensor_trigger, 'sensor.remote20_action')
|
# self.notify("hello world", name = "telegram")
|
||||||
|
# self.listen_state(self.sensor_trigger, "sensor.0x00158d0003a361d8_action")
|
||||||
|
# self.listen_state(self.sensor_trigger, "binary_sensor.0x00158d0003f26d61_occupancy")
|
||||||
|
# self.listen_state(self.sensor_trigger, "sensor.remote20_action")
|
||||||
|
|
||||||
def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
# def sensor_trigger(self, entity, attribute, old, new, kwargs):
|
||||||
if new != "" and new != "unknown":
|
# if new != "" and new != "unknown":
|
||||||
self.log("doorbell call")
|
# self.log("doorbell call")
|
||||||
self.toggle("switch.0x00158d00020f3a29_switch")
|
# self.toggle("switch.0x00158d00020f3a29_switch")
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ services:
|
|||||||
max-size: 50m
|
max-size: 50m
|
||||||
|
|
||||||
hass:
|
hass:
|
||||||
image: "homeassistant/home-assistant:stable" #stable
|
image: "homeassistant/home-assistant:stable" #2026.4.2
|
||||||
#image: ghcr.io/home-assistant/home-assistant:stable
|
#image: ghcr.io/home-assistant/home-assistant:stable
|
||||||
container_name: hass
|
container_name: hass
|
||||||
volumes:
|
volumes:
|
||||||
@@ -121,10 +121,12 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./zigbee2mqtt/settings:/app/data
|
- ./zigbee2mqtt/settings:/app/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080"]
|
# в образе нет curl (Alpine), используем wget --spider
|
||||||
|
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 6
|
retries: 6
|
||||||
|
start_period: 60s
|
||||||
restart: always
|
restart: always
|
||||||
logging:
|
logging:
|
||||||
driver: json-file
|
driver: json-file
|
||||||
@@ -184,22 +186,22 @@ services:
|
|||||||
max-size: "10m"
|
max-size: "10m"
|
||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
homeconnect2mqtt:
|
#homeconnect2mqtt:
|
||||||
build:
|
# build:
|
||||||
context: ./homeconnect2mqtt/docker
|
# context: ./homeconnect2mqtt/docker
|
||||||
dockerfile: Dockerfile
|
# dockerfile: Dockerfile
|
||||||
restart: always
|
# restart: always
|
||||||
container_name: homeconnect2mqtt
|
# container_name: homeconnect2mqtt
|
||||||
ports:
|
# ports:
|
||||||
- "5001:5000"
|
# - "5001:5000"
|
||||||
env_file: ./homeconnect2mqtt/settings/homeconnect2mqtt.env
|
# env_file: ./homeconnect2mqtt/settings/homeconnect2mqtt.env
|
||||||
volumes:
|
# volumes:
|
||||||
- ./homeconnect2mqtt/settings/config.json:/app/config.json:ro
|
# - ./homeconnect2mqtt/settings/config.json:/app/config.json:ro
|
||||||
logging:
|
# logging:
|
||||||
driver: json-file
|
# driver: json-file
|
||||||
options:
|
# options:
|
||||||
max-size: "10m"
|
# max-size: "10m"
|
||||||
max-file: "5"
|
# max-file: "5"
|
||||||
|
|
||||||
matter-bridge:
|
matter-bridge:
|
||||||
image: ghcr.io/t0bst4r/home-assistant-matter-hub:latest
|
image: ghcr.io/t0bst4r/home-assistant-matter-hub:latest
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026.4.2
|
2026.7.2
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 924 B |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
@@ -1 +1 @@
|
|||||||
{"pid": 238780, "version": 1, "ha_version": "2026.4.2", "start_ts": 1781684834.86627}
|
{"pid": 71, "version": 1, "ha_version": "2026.7.2", "start_ts": 1784034083.5601983}
|
||||||
@@ -21,55 +21,65 @@
|
|||||||
# {{ states('sensor.dishwasher_program_progress') + "%" }}
|
# {{ states('sensor.dishwasher_program_progress') + "%" }}
|
||||||
# {% endif %}
|
# {% endif %}
|
||||||
|
|
||||||
mqtt:
|
# mqtt:
|
||||||
sensor:
|
# sensor:
|
||||||
- name: hc_dishwasher_state
|
# - name: hc_dishwasher_state
|
||||||
unique_id: hc_dishwasher_state
|
# unique_id: hc_dishwasher_state
|
||||||
state_topic: "homeconnect/dishwasher/state"
|
# state_topic: "homeconnect/dishwasher/state"
|
||||||
value_template: "{{ value_json.state }}"
|
# value_template: "{{ value_json.state }}"
|
||||||
json_attributes_topic: "homeconnect/dishwasher/state"
|
# json_attributes_topic: "homeconnect/dishwasher/state"
|
||||||
- name: hc_dishwasher_remaining
|
# - name: hc_dishwasher_remaining
|
||||||
unique_id: hc_dishwasher_remaining
|
# unique_id: hc_dishwasher_remaining
|
||||||
state_topic: "homeconnect/dishwasher/state"
|
# state_topic: "homeconnect/dishwasher/state"
|
||||||
value_template: "{{ value_json.remaining }}"
|
# value_template: "{{ value_json.remaining }}"
|
||||||
json_attributes_topic: "homeconnect/dishwasher/state"
|
# json_attributes_topic: "homeconnect/dishwasher/state"
|
||||||
binary_sensor:
|
# binary_sensor:
|
||||||
- state_topic: "homeconnect/dishwasher/state"
|
# - state_topic: "homeconnect/dishwasher/state"
|
||||||
name: hc_dishwasher_door
|
# name: hc_dishwasher_door
|
||||||
unique_id: hc_dishwasher_door
|
# unique_id: hc_dishwasher_door
|
||||||
device_class: opening
|
# device_class: opening
|
||||||
payload_on: "Open"
|
# payload_on: "Open"
|
||||||
payload_off: "Closed"
|
# payload_off: "Closed"
|
||||||
value_template: "{{ value_json.door }}"
|
# value_template: "{{ value_json.door }}"
|
||||||
json_attributes_topic: "homeconnect/dishwasher/state"
|
# json_attributes_topic: "homeconnect/dishwasher/state"
|
||||||
- state_topic: "homeconnect/dishwasher/state"
|
# - state_topic: "homeconnect/dishwasher/state"
|
||||||
name: hc_dishwasher_power
|
# name: hc_dishwasher_power
|
||||||
unique_id: hc_dishwasher_power
|
# unique_id: hc_dishwasher_power
|
||||||
payload_on: true
|
# payload_on: true
|
||||||
payload_off: false
|
# payload_off: false
|
||||||
value_template: "{{ value_json.power }}"
|
# value_template: "{{ value_json.power }}"
|
||||||
json_attributes_topic: "homeconnect/dishwasher/state"
|
# json_attributes_topic: "homeconnect/dishwasher/state"
|
||||||
template:
|
template:
|
||||||
binary_sensor:
|
binary_sensor:
|
||||||
- name: hc_dishwasher_running
|
- name: bosch_dishwasher_running
|
||||||
unique_id: hc_dishwasher_running
|
unique_id: bosch_dishwasher_running
|
||||||
state: "{{ is_state('sensor.hc_dishwasher_state', 'Run') }}"
|
state: "{{ is_state('sensor.bosch_dishwasher_operation_state', 'Run') }}"
|
||||||
|
|
||||||
counter:
|
counter:
|
||||||
dishwasher_door_open_count:
|
bosch_dishwasher_door_open_count:
|
||||||
name: dishwasher_door_open_count
|
name: bosch_dishwasher_door_open_count
|
||||||
|
|
||||||
|
input_select:
|
||||||
|
bosch_dishwasher_state_extended:
|
||||||
|
name: bosch_dishwasher_state_extended
|
||||||
|
options:
|
||||||
|
- 'Empty'
|
||||||
|
- 'Washing'
|
||||||
|
- 'Washed'
|
||||||
|
- 'Collecting Dishes'
|
||||||
|
- 'Ready to wash'
|
||||||
|
|
||||||
homeassistant:
|
homeassistant:
|
||||||
customize:
|
customize:
|
||||||
sensor.hc_dishwasher_state:
|
sensor.bosch_dishwasher_state:
|
||||||
friendly_name: Посудомойка Статус
|
friendly_name: Посудомойка Статус
|
||||||
binary_sensor.hc_dishwasher_door:
|
binary_sensor.bosch_dishwasher_door:
|
||||||
friendly_name: Посудомойка Дверца
|
friendly_name: Посудомойка Дверца
|
||||||
binary_sensor.hc_dishwasher_remaining:
|
binary_sensor.bosch_dishwasher_remaining:
|
||||||
friendly_name: Посудомойка До конца программы
|
friendly_name: Посудомойка До конца программы
|
||||||
sensor.hc_dishwasher_running:
|
sensor.bosch_dishwasher_running:
|
||||||
friendly_name: Посудомоечная машина
|
friendly_name: Посудомоечная машина
|
||||||
binary_sensor.hc_dishwasher_power:
|
binary_sensor.bosch_dishwasher_power:
|
||||||
friendly_name: Посудомойка Питание
|
friendly_name: Посудомойка Питание
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
telegram_bot:
|
# telegram_bot: секция удалена — интеграция уже настроена через config entry
|
||||||
- platform: polling
|
# (UI, импортирован 2025-12-28), YAML-платформа с ней конфликтовала:
|
||||||
api_key: !secret telegram_key
|
# ERROR integration telegram_bot cannot be merged, expected a dict
|
||||||
allowed_chat_ids:
|
#
|
||||||
- !secret telegram_group_chat
|
# notify: платформы (legacy, deprecated) тоже убраны — все appdaemon-скрипты
|
||||||
- !secret telegram_monster_chat
|
# мигрированы на entity-based telegram_bot.send_message/send_photo (см.
|
||||||
- !secret telegram_sveta_chat
|
# appdaemon/settings/apps/globals.py: TELEGRAM_TARGETS, send_telegram(),
|
||||||
|
# send_telegram_photo()). Проверено: тестовые сообщения через новый механизм
|
||||||
notify:
|
# успешно доставлены во все 3 чата (группа, Monster, Svetlana) 2026-07-14.
|
||||||
- platform: telegram
|
#
|
||||||
name: telegram
|
# Telegram bot notify-сущности теперь берутся из config entry:
|
||||||
chat_id: !secret telegram_group_chat
|
# notify.home_assistant_fonvizina_fonvizina_18_1001567589226
|
||||||
parse_mode: html
|
# notify.home_assistant_fonvizina_monster_123622180
|
||||||
- platform: telegram
|
# notify.home_assistant_fonvizina_svetlana_205225134
|
||||||
name: telegram_monster
|
|
||||||
chat_id: !secret telegram_monster_chat
|
|
||||||
parse_mode: html
|
|
||||||
- platform: telegram
|
|
||||||
name: telegram_sveta
|
|
||||||
chat_id: !secret telegram_sveta_chat
|
|
||||||
parse_mode: html
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
telegram_bot:
|
||||||
|
- platform: polling
|
||||||
|
api_key: !secret telegram_key
|
||||||
|
allowed_chat_ids:
|
||||||
|
- !secret telegram_group_chat
|
||||||
|
- !secret telegram_monster_chat
|
||||||
|
- !secret telegram_sveta_chat
|
||||||
|
|
||||||
|
notify:
|
||||||
|
- platform: telegram
|
||||||
|
name: telegram
|
||||||
|
chat_id: !secret telegram_group_chat
|
||||||
|
parse_mode: html
|
||||||
|
- platform: telegram
|
||||||
|
name: telegram_monster
|
||||||
|
chat_id: !secret telegram_monster_chat
|
||||||
|
parse_mode: html
|
||||||
|
- platform: telegram
|
||||||
|
name: telegram_sveta
|
||||||
|
chat_id: !secret telegram_sveta_chat
|
||||||
|
parse_mode: html
|
||||||