Files

91 lines
3.0 KiB
Python
Raw Permalink Normal View History

2026-08-23 08:16:15 +02:00
"""Send controller events to the cloud event logger."""
import logging
from datetime import datetime, timezone
2026-08-26 18:17:03 +02:00
from pprint import pprint
2026-08-23 08:16:15 +02:00
import requests
LOG = logging.getLogger("home_control.cloud_logger")
def _filter_values(config: dict, mode: str, field: str) -> set[str]:
value = config.get("filter", {}).get(mode, {}).get(field, [])
if not isinstance(value, list) or any(not isinstance(item, str) for item in value):
raise ValueError(
f"cloud_logger.filter.{mode}.{field} must be a list of strings"
)
return set(value)
def accepts_event(config: dict, message: dict) -> bool:
"""Return whether an event passes configured event and ID filters."""
accepted_events = _filter_values(config, "accept", "events")
accepted_ids = _filter_values(config, "accept", "ids")
ignored_events = _filter_values(config, "ignore", "events")
ignored_ids = _filter_values(config, "ignore", "ids")
if message["event"] in ignored_events or message["id"] in ignored_ids:
return False
if accepted_events and message["event"] not in accepted_events:
return False
if accepted_ids and message["id"] not in accepted_ids:
return False
return True
def send_event(message: dict, event_url: str, timeout: float = 10) -> None:
"""POST an event dictionary as JSON to the configured logger endpoint."""
if not isinstance(message, dict):
raise TypeError("message must be a dictionary")
if not event_url:
raise ValueError("event_url is required")
2026-08-26 18:43:12 +02:00
response = requests.post(
event_url,
json=message,
timeout=timeout,
allow_redirects=False,
)
if response.is_redirect:
raise requests.HTTPError(
f"event endpoint redirected to {response.headers.get('Location', '')}",
response=response,
)
2026-08-23 08:16:15 +02:00
response.raise_for_status()
def on_event(config: dict, message: dict) -> None:
"""Controller action that forwards event data to the cloud logger."""
if not config.get("enabled", True):
return
try:
if not accepts_event(config, message):
LOG.debug(
"cloud event ignored by filter: event=%s id=%s",
message["event"],
message["id"],
)
return
timestamp = datetime.now(timezone.utc).isoformat()
values = {**message, "datetime": timestamp}
messages = config.get("messages", {})
2026-08-26 18:17:03 +02:00
template = config.get(
2026-08-23 08:16:15 +02:00
message["event"],
config.get("message", "{datetime} {sender}: {event} ({id})"),
)
payload = {
**message,
"datetime": timestamp,
"text": message.get("text") or str(template).format(**values),
}
send_event(
payload,
event_url=str(config.get("event_url", "")),
timeout=float(config.get("timeout", 10)),
)
except (TypeError, ValueError, requests.RequestException) as error:
LOG.error("cloud event logging failed: %s", error)