This commit is contained in:
Victor Alexandrovich Tsyrenschikov
2026-03-30 20:25:42 +05:00
parent 139f9f1bd2
commit 373ed28445
2449 changed files with 53602 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
import json
import os
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_INCLUDE
from homeassistant.core import HomeAssistant
from ..climate import INCLUDE_TYPES as CLIMATE
from ..core.const import DATA_CONFIG, DOMAIN
from ..core.entity import extract_instance
from ..core.yandex_quasar import YandexQuasar
from ..cover import INCLUDE_TYPES as COVER
from ..humidifier import INCLUDE_TYPES as HUMIDIFIER
from ..light import INCLUDE_TYPES as LIGHT
from ..media_player import INCLUDE_TYPES as MEDIA_PLAYER
from ..vacuum import INCLUDE_TYPES as VACUUM
from ..water_heater import INCLUDE_TYPES as WATER_HEATER
INCLUDE_KEYS = ("id", "name", "type", "room_name", "skill_id", "house_name")
INCLUDE_TYPES_UNKNOWN = (
"devices.types.camera",
"devices.types.cooking",
"devices.types.cooking.coffee_maker",
"devices.types.cooking.multicooker",
"devices.types.dishwasher",
"devices.types.iron",
"devices.types.openable",
"devices.types.other",
"devices.types.pet_drinking_fountain",
"devices.types.pet_feeder",
"devices.types.washing_machine",
)
INCLUDE_SKIP_INSTANCES = {
CLIMATE: [
"on",
"thermostat",
"program",
"heat",
"work_speed",
"temperature",
"humidity",
"fan_speed",
],
COVER: ["on", "open", "pause"],
HUMIDIFIER: ["on", "fan_speed", "work_speed", "humidity"],
LIGHT: ["on", "brightness", "color"],
MEDIA_PLAYER: ["on", "pause", "volume", "mute", "channel", "input_source"],
VACUUM: ["on", "pause", "work_speed", "battery_level"],
WATER_HEATER: ["on", "tea_mode", "temperature"],
INCLUDE_TYPES_UNKNOWN: [],
}
def incluce_devices(
hass: HomeAssistant, config_entry: ConfigEntry
) -> list[tuple[YandexQuasar, dict, dict]]:
quasar: YandexQuasar = hass.data[DOMAIN][config_entry.unique_id]
config: dict = hass.data[DOMAIN][DATA_CONFIG]
# config_entry has more priority
includes = config_entry.options.get(CONF_INCLUDE, []) + config.get(CONF_INCLUDE, [])
devices = []
# первый цикл по devices, второй по include, чтоб одинаковые include работали на
# разные devices
for device in quasar.devices:
for conf in includes:
if isinstance(conf, str):
if conf == device["id"] or conf == device["name"]:
conf = build_include_config(device)
devices.append((quasar, device, conf))
break
elif isinstance(conf, dict):
if all(conf[k] == device.get(k) for k in INCLUDE_KEYS if k in conf):
devices.append((quasar, device, conf))
break
return devices
def build_include_config(device: dict) -> dict:
for include_types, include_skip in INCLUDE_SKIP_INSTANCES.items():
if device["type"] in include_types:
break
else:
return {}
caps = [extract_instance(i) for i in device["capabilities"]]
props = [i["parameters"]["instance"] for i in device["properties"]]
return {
"capabilities": [i for i in caps if i not in include_skip],
"properties": [i for i in props if i not in include_skip],
}
async def load_fake_devies(hass: HomeAssistant, quasar: YandexQuasar):
path = hass.config.path(DOMAIN + ".json")
if not os.path.isfile(path):
return
def job():
with open(path, "rb") as f:
quasar.devices = json.load(f)
await hass.async_add_executor_job(job)

View File

@@ -0,0 +1,97 @@
import logging
import re
import uuid
from homeassistant.components.shopping_list import ShoppingData
from homeassistant.core import HomeAssistant
from ..core.yandex_glagol import YandexGlagol
try:
from homeassistant.const import EVENT_SHOPPING_LIST_UPDATED
except ImportError:
EVENT_SHOPPING_LIST_UPDATED = "shopping_list_updated"
_LOGGER = logging.getLogger(__package__)
RE_SHOPPING = re.compile(r"^\d+\) (.+)$", re.MULTILINE)
def shopping_for_remove(hass: HomeAssistant, alice_data: str) -> list[str]:
alice_items = RE_SHOPPING.findall(alice_data)
shopping_data: ShoppingData = hass.data["shopping_list"]
for_remove = [
alice_items.index(item["name"])
for item in shopping_data.items
if item["complete"] and item["name"] in alice_items
]
return [str(i + 1) for i in sorted(for_remove)]
def shopping_for_add(hass: HomeAssistant, alice_data: str) -> list[str]:
shopping_data: ShoppingData = hass.data["shopping_list"]
alice_items = RE_SHOPPING.findall(alice_data)
return [
item["name"]
for item in shopping_data.items
if not item["complete"]
and item["name"] not in alice_items
and not item["id"].startswith("alice")
]
def shopping_save(hass: HomeAssistant, alice_data: str):
alice_items = RE_SHOPPING.findall(alice_data)
shopping_data: ShoppingData = hass.data["shopping_list"]
new_items = {
name: {"name": name, "id": f"alice{uuid.uuid4().hex}", "complete": False}
for name in alice_items
}
old_items = {i["name"]: i for i in shopping_data.items}
shopping_data.items = list(new_items.values())
hass.async_add_executor_job(shopping_data.save)
# noinspection PyProtectedMember
shopping_data._async_notify()
for name, item in old_items.items():
if name not in new_items:
hass.bus.async_fire(
EVENT_SHOPPING_LIST_UPDATED, {"action": "remove", "item": item}
)
for name, item in new_items.items():
if name not in old_items:
hass.bus.async_fire(
EVENT_SHOPPING_LIST_UPDATED, {"action": "add", "item": item}
)
async def shopping_sync(hass: HomeAssistant, glagol: YandexGlagol):
if "shopping_list" not in hass.data:
return
try:
payload = {"command": "sendText", "text": "Что в списке покупок"}
card = await glagol.send(payload)
while for_remove := shopping_for_remove(hass, card["text"]):
# не удаляет больше 5 элементов за раз
text = "Удали " + ", ".join(for_remove[:5])
await glagol.send({"command": "sendText", "text": text})
# обновим после изменений
card = await glagol.send(payload)
if for_add := shopping_for_add(hass, card["text"]):
for item in for_add:
# плохо работает, если добавлять всё сразу через запятую
text = f"Добавь в список покупок {item}"
await glagol.send({"command": "sendText", "text": text})
# обновим после изменений
card = await glagol.send(payload)
shopping_save(hass, card["text"])
except Exception as e:
_LOGGER.error("shopping_sync", exc_info=e)