361 files

This commit is contained in:
Home Assistant Version Control
2026-10-06 17:11:43 +00:00
parent d2c5af43e3
commit bf886c9347
362 changed files with 22060 additions and 1285 deletions
@@ -52,6 +52,7 @@ from .notification_ids import (
budget_tag,
bundle_tag,
panel_url,
place_tag,
task_tag,
)
from .notify_hooks import (
@@ -59,6 +60,7 @@ from .notify_hooks import (
KIND_BUNDLE,
KIND_DIGEST,
KIND_LEAD_TIME,
KIND_PLACE_ARRIVAL,
KIND_QUIET_END,
KIND_STATUS,
KIND_WARRANTY,
@@ -116,6 +118,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Später",
"bundled_title": "Wartung: {count} Aufgaben",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Wartung vor Ort: {place}",
"place_arrival_message": "Hier fällig: {task_list}",
"quiet_end_title": "{count} Erinnerungen aus der Ruhezeit",
"digest_title": "Wöchentliche Wartungsübersicht",
"digest_message": "{overdue} überfällig, {due_soon} diese Woche fällig.",
@@ -156,6 +160,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Later",
"bundled_title": "Onderhoud: {count} taken",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Onderhoud ter plaatse: {place}",
"place_arrival_message": "Hier te doen: {task_list}",
"quiet_end_title": "{count} herinneringen uit de stille uren",
"digest_title": "Wekelijks onderhoudsoverzicht",
"digest_message": "{overdue} achterstallig, {due_soon} deze week.",
@@ -196,6 +202,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Reporter",
"bundled_title": "Maintenance : {count} tâches",
"bundled_message": "{object} : {task_list}",
"place_arrival_title": "Entretien sur place : {place}",
"place_arrival_message": "À faire ici : {task_list}",
"quiet_end_title": "{count} rappels des heures calmes",
"digest_title": "Récapitulatif hebdomadaire d'entretien",
"digest_message": "{overdue} en retard, {due_soon} cette semaine.",
@@ -236,6 +244,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Posticipa",
"bundled_title": "Manutenzione: {count} attività",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Manutenzione sul posto: {place}",
"place_arrival_message": "Da fare qui: {task_list}",
"quiet_end_title": "{count} promemoria dalle ore di silenzio",
"digest_title": "Riepilogo settimanale manutenzione",
"digest_message": "{overdue} scadute, {due_soon} questa settimana.",
@@ -276,6 +286,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Posponer",
"bundled_title": "Mantenimiento: {count} tareas",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Mantenimiento en el lugar: {place}",
"place_arrival_message": "Pendiente aquí: {task_list}",
"quiet_end_title": "{count} recordatorios de las horas de silencio",
"digest_title": "Resumen semanal de mantenimiento",
"digest_message": "{overdue} vencidas, {due_soon} esta semana.",
@@ -316,6 +328,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Snooze",
"bundled_title": "Maintenance: {count} tasks",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Maintenance at {place}",
"place_arrival_message": "Due here: {task_list}",
"quiet_end_title": "{count} reminders held during quiet hours",
"digest_title": "Weekly maintenance digest",
"digest_message": "{overdue} overdue, {due_soon} due this week.",
@@ -356,6 +370,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Senere",
"bundled_title": "Vedligeholdelse: {count} opgaver",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Vedligeholdelse på stedet: {place}",
"place_arrival_message": "Skal gøres her: {task_list}",
"quiet_end_title": "{count} påmindelser fra de stille timer",
"digest_title": "Ugentlig vedligeholdelsesoversigt",
"digest_message": "{overdue} forfaldne, {due_soon} denne uge.",
@@ -396,6 +412,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Myöhemmin",
"bundled_title": "Huolto: {count} tehtävää",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Huolto paikan päällä: {place}",
"place_arrival_message": "Tehtävänä täällä: {task_list}",
"quiet_end_title": "{count} muistutusta hiljaisilta tunneilta",
"digest_title": "Viikoittainen huoltokooste",
"digest_message": "{overdue} myöhässä, {due_soon} tällä viikolla.",
@@ -436,6 +454,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Senere",
"bundled_title": "Vedlikehold: {count} oppgaver",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Vedlikehold på stedet: {place}",
"place_arrival_message": "Skal gjøres her: {task_list}",
"quiet_end_title": "{count} påminnelser fra de stille timene",
"digest_title": "Ukentlig vedlikeholdsoversikt",
"digest_message": "{overdue} forfalt, {due_soon} denne uken.",
@@ -476,6 +496,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "後で",
"bundled_title": "メンテナンス: {count} 件のタスク",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "現地のメンテナンス: {place}",
"place_arrival_message": "ここでの作業: {task_list}",
"quiet_end_title": "静音時間中の{count}件のリマインダー",
"digest_title": "週間メンテナンスまとめ",
"digest_message": "期限切れ {overdue} 件、今週 {due_soon} 件。",
@@ -516,6 +538,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "बाद में",
"bundled_title": "रखरखाव: {count} कार्य",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "मौके पर रखरखाव: {place}",
"place_arrival_message": "यहाँ करने के काम: {task_list}",
"quiet_end_title": "शांत घंटों के {count} अनुस्मारक",
"digest_title": "साप्ताहिक रखरखाव सारांश",
"digest_message": "{overdue} अतिदेय, {due_soon} इस सप्ताह।",
@@ -556,6 +580,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "稍后提醒",
"bundled_title": "维护:共有 {count} 项任务",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "现场维护:{place}",
"place_arrival_message": "此处待办:{task_list}",
"quiet_end_title": "静音时段积累的 {count} 条提醒",
"digest_title": "每周维护摘要",
"digest_message": "逾期 {overdue} 项,本周 {due_soon} 项。",
@@ -596,6 +622,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Отложить",
"bundled_title": "Обслуживание: {count} задач",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Обслуживание на месте: {place}",
"place_arrival_message": "Здесь нужно сделать: {task_list}",
"quiet_end_title": "{count} напоминаний за тихие часы",
"digest_title": "Еженедельная сводка обслуживания",
"digest_message": "{overdue} просрочено, {due_soon} на этой неделе.",
@@ -636,6 +664,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Відкласти",
"bundled_title": "Обслуговування: {count} завдань",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Обслуговування на місці: {place}",
"place_arrival_message": "Тут потрібно зробити: {task_list}",
"quiet_end_title": "{count} нагадувань за тихі години",
"digest_title": "Щотижневий огляд обслуговування",
"digest_message": "{overdue} прострочено, {due_soon} цього тижня.",
@@ -676,6 +706,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Adiar",
"bundled_title": "Manutenção: {count} tarefas",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Manutenção no local: {place}",
"place_arrival_message": "A fazer aqui: {task_list}",
"quiet_end_title": "{count} lembretes das horas de silêncio",
"digest_title": "Resumo semanal de manutenção",
"digest_message": "{overdue} atrasadas, {due_soon} esta semana.",
@@ -718,6 +750,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Drzemka",
"bundled_title": "Konserwacja: {count} zadań",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Konserwacja na miejscu: {place}",
"place_arrival_message": "Do zrobienia tutaj: {task_list}",
"quiet_end_title": "{count} przypomnień z godzin ciszy",
"digest_title": "Cotygodniowe podsumowanie konserwacji",
"digest_message": "{overdue} zaległych, {due_soon} w tym tygodniu.",
@@ -760,6 +794,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Odložit",
"bundled_title": "Údržba: {count} úkolů",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Údržba na místě: {place}",
"place_arrival_message": "Zde je potřeba udělat: {task_list}",
"quiet_end_title": "{count} připomínek z tichých hodin",
"digest_title": "Týdenní přehled údržby",
"digest_message": "{overdue} po termínu, {due_soon} tento týden.",
@@ -801,6 +837,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Snooza",
"bundled_title": "Underhåll: {count} uppgifter",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Underhåll på plats: {place}",
"place_arrival_message": "Att göra här: {task_list}",
"quiet_end_title": "{count} påminnelser från de tysta timmarna",
"digest_title": "Veckovis underhållssammanfattning",
"digest_message": "{overdue} försenade, {due_soon} denna vecka.",
@@ -841,6 +879,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Adiar",
"bundled_title": "Manutenção: {count} tarefas",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Manutenção no local: {place}",
"place_arrival_message": "Pendente aqui: {task_list}",
"quiet_end_title": "{count} lembretes das horas de silêncio",
"digest_title": "Resumo semanal de manutenção",
"digest_message": "{overdue} atrasadas, {due_soon} vencem nesta semana.",
@@ -881,6 +921,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Halasztás",
"bundled_title": "Karbantartás: {count} feladat",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Karbantartás a helyszínen: {place}",
"place_arrival_message": "Itt esedékes: {task_list}",
"quiet_end_title": "{count} emlékeztető a csendes órákból",
"digest_title": "Heti karbantartási összefoglaló",
"digest_message": "{overdue} lejárt, {due_soon} esedékes ezen a héten.",
@@ -921,6 +963,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "미루기",
"bundled_title": "유지보수: 작업 {count}개",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "현장 유지보수: {place}",
"place_arrival_message": "여기서 할 일: {task_list}",
"quiet_end_title": "방해 금지 시간 동안 쌓인 알림 {count}건",
"digest_title": "주간 유지보수 요약",
"digest_message": "기한 초과 {overdue}건, 이번 주 예정 {due_soon}건.",
@@ -961,6 +1005,8 @@ _NOTIFICATION_STRINGS: dict[str, dict[str, str]] = {
"action_snooze": "Ertele",
"bundled_title": "Bakım: {count} görev",
"bundled_message": "{object}: {task_list}",
"place_arrival_title": "Yerinde bakım: {place}",
"place_arrival_message": "Burada yapılacaklar: {task_list}",
"quiet_end_title": "Sessiz saatlerden {count} hatırlatma",
"digest_title": "Haftalık bakım özeti",
"digest_message": "{overdue} gecikmiş, {due_soon} bu hafta yapılacak.",
@@ -2062,6 +2108,82 @@ class NotificationManager:
_LOGGER.exception("Failed to send notification to %s", service)
return False
async def async_place_arrival(
self,
*,
user_id: str,
zone_id: str,
place_name: str,
tasks: list[dict[str, Any]],
) -> bool:
"""2026-10 places: what is due at ``place_name``, to the person who
just arrived there (helpers/places.PlaceArrivals). Only that person's
own phones, never the household service: nobody else is there. Not
held through quiet hours (the place's reminders follow once they
end). Each task passes the kind's per-task gates (mute, snooze).
True when it went out."""
self.async_verify_configured_service()
if not self.enabled or self._is_quiet_hours():
return False
due = [
t
for t in tasks
if task_may_notify(
self.hass, t["entry_id"], t["task_id"], str(t["status"]), t.get("task_data") or {}, kind=KIND_PLACE_ARRIVAL, manager=self
)
]
if not due:
return False
targets: list[str] = await get_user_notify_services(self.hass, user_id)
if not targets:
if not self.event_only:
_LOGGER.debug("Place arrival at %s: user %s has no phone to tell", zone_id, user_id)
return False
targets = [""] # #173: the event IS the delivery
lang = self._lang
by_object: dict[str, list[str]] = {}
for t in due:
by_object.setdefault(str(t["object_name"]), []).append(_bundled_line(t["status"], lang, str(t["task_name"])))
task_list = "; ".join(f"{name}: {', '.join(lines)}" for name, lines in by_object.items())
entry_ids = sorted({str(t["entry_id"]) for t in due})
single = entry_ids[0] if len(entry_ids) == 1 else None
service_data = _service_payload(
_notif_t("place_arrival_title", lang, place=place_name),
_notif_t("place_arrival_message", lang, task_list=task_list),
tag=place_tag(zone_id),
url=panel_url(entry_id=single),
)
context = notification_context(
self.hass,
KIND_PLACE_ARRIVAL,
entry_id=single,
responsible_user_id=user_id,
tasks=[
{"entry_id": t["entry_id"], "task_id": t["task_id"], "task_name": t["task_name"], "status": str(t["status"])}
for t in due
],
place=zone_id,
place_name=place_name,
)
sent = False
for target in targets:
try:
if await async_emit_and_dispatch(self.hass, target, service_data, context):
sent = True
except Exception: # noqa: BLE001 — one phone failing must not stop the others
_LOGGER.warning("Place arrival message to %s failed", target or "the event", exc_info=True)
if sent:
from .places import reminds_on_site
# For an object whose reminders wait for somebody on site this
# message IS the visit's reminder: unstamped, the held reminders
# followed on the next refresh, to everybody (at home too).
for t in due:
if reminds_on_site(self.hass, t["entry_id"]):
status = str(t["status"])
self._stamp_status_sent(notification_key(t["entry_id"], t["task_id"], status), self._get_interval_hours(status))
return sent
async def async_send_bundled(
self,
entry_id: str,