#!/usr/bin/env python3 """Sonda di sola lettura sui dati statistici del cloud Aira (v2). NON invia comandi all'impianto. Obiettivo: capire cosa si puo' mostrare in una pagina "Dati" come quella dell'app ufficiale (calore prodotto, elettricita', efficienza/COP, risparmi). """ import json import os import sys from datetime import datetime, timedelta from pathlib import Path CFG = Path(os.environ.get("AIRA_CONFIG_DIR", str(Path.home() / ".hermes/profiles/carlo"))) sys.path.insert(0, str(CFG)) from pyairahome import AiraHome from pyairahome.device.heat_pump.statistics.v1 import service_pb2 as S def section(t): print("\n" + "=" * 72) print(t) print("=" * 72) section("messaggi annidati e risposte") for name in ("Uuid", "YearMonth", "LocalDateTime", "CopEntry", "GetCopResponse", "MonthlySavings", "GetSavingsResponse", "RollingMonthOptimisation", "GetOptimisationSavingsResponse", "InsightEntry", "GetHeatPumpInsightsResponse"): cls = getattr(S, name, None) if cls is None: print(f"{name}: assente") continue try: fs = cls.DESCRIPTOR.fields print(f"{name}: " + ", ".join( f"{f.name}(type={f.type}, msg={f.message_type and f.message_type.name}, " f"enum={f.enum_type and f.enum_type.name})" for f in fs)) except Exception as exc: # noqa: BLE001 print(f"{name}: introspezione fallita ({type(exc).__name__}: {exc})") # --- login ----------------------------------------------------------------- # tokens = json.loads((CFG / "aira_tokens.json").read_text()) state = json.loads(Path("/tmp/aira_state.json").read_text())["state"] hp = state["heat_pump_id"]["value"] aira = AiraHome() aira.cloud.login_with_tokens(tokens["id_token"], tokens["access_token"], tokens["refresh_token"]) stub = aira.cloud._stats_service_stub # noqa: SLF001 call = aira.cloud.call_service print(f"\nheat_pump_id: {hp}") now = datetime.now() def show(label, method, req): section(label) try: out = call(stub, method, req, timeout=25, raw=True) print(str(out).replace("\n", " | ")[:1500] or "(risposta vuota)") except Exception as exc: # noqa: BLE001 print(f"ERRORE {type(exc).__name__}: {str(exc)[:400]}") # COP mensile, ultimi 6 mesi req = S.GetCopRequest() req.heat_pump_id.value = hp req.granularity = S.COP_GRANULARITY_MONTHLY start = now - timedelta(days=180) req.start_date.year, req.start_date.month = start.year, start.month req.end_date_exclusive.year, req.end_date_exclusive.month = now.year, now.month + 1 if now.month < 12 else 1 if now.month == 12: req.end_date_exclusive.year = now.year + 1 show("GetCop mensile (6 mesi) -> efficienza", "GetCop", req) # Risparmi: periodo 180 giorni from google.protobuf.timestamp_pb2 import Timestamp req = S.GetSavingsRequest() req.heat_pump_id.value = hp ts = Timestamp(); ts.FromDatetime(start); req.start_time.CopyFrom(ts) te = Timestamp(); te.FromDatetime(now); req.end_time.CopyFrom(te) show("GetSavings (180 giorni) -> risparmi", "GetSavings", req) # Risparmi Smart Tariff Control (per nucleo familiare) household = None try: devs = aira.cloud.get_devices() print("\nget_devices ->", str(devs)[:400]) def find_hh(o): if isinstance(o, dict): for k, v in o.items(): if k == "household_id" and v: return v if isinstance(v, str) else v.get("value") r = find_hh(v) if r: return r elif isinstance(o, list): for v in o: r = find_hh(v) if r: return r return None household = find_hh(devs) print("household_id:", household) except Exception as exc: # noqa: BLE001 print("get_devices fallita:", type(exc).__name__, str(exc)[:200]) if household: req = S.GetOptimisationSavingsRequest() req.household_id.value = household show("GetOptimisationSavings -> risparmio Smart Tariff Control", "GetOptimisationSavings", req) # Insight giornalieri, ultimi 7 giorni (LocalDateTime) req = S.GetHeatPumpInsightsRequest() req.heat_pump_id.value = hp req.granularity = S.GRANULARITY_DAILY s = now - timedelta(days=7) for m in (req.start_time, req.end_time_exclusive): pass req.start_time.year, req.start_time.month, req.start_time.day = s.year, s.month, s.day req.end_time_exclusive.year, req.end_time_exclusive.month, req.end_time_exclusive.day = now.year, now.month, now.day show("GetHeatPumpInsights giornaliero (7 giorni)", "GetHeatPumpInsights", req) aira.cloud.close() print("\nsonda conclusa: nessun comando inviato all'impianto.")