// airtria-ha-read.js [ …] — lecture Home Assistant fiable, UNE vérité. // ----------------------------------------------------------------------------- // Airtria doit LIRE l'état via ce script (exec), jamais raisonner sur ce qu'une valeur // « devrait » être, jamais fabriquer une erreur. Pour chaque entité, imprime : état, unité, // et `last_changed` CONVERTI en heure de Paris + âge (marqué FIGÉ au-delà de 15 min). En cas // d'échec, imprime le VRAI code HTTP / la vraie erreur — pour que la panne rapportée soit // réelle, pas inventée (le 16/09 Airtria a affirmé un 401 alors que le jeton renvoyait 200). // Rappel EVCS 16/09 : les horodatages /api/states sont en UTC → toujours convertir. // ----------------------------------------------------------------------------- 'use strict'; const fs = require('fs'); const path = require('path'); const HA_BASE = process.env.HA_BASE || 'http://10.10.10.17:8123'; const token = () => fs.readFileSync( process.env.HA_TOKEN_FILE || path.join(__dirname, '.ha-token'), 'utf8').trim(); function parisAge(iso) { if (!iso) return '?'; const d = new Date(iso); const t = d.toLocaleString('fr-FR', { timeZone: 'Europe/Paris', dateStyle: 'short', timeStyle: 'medium' }); const ageMin = Math.round((Date.now() - d.getTime()) / 60000); const stale = ageMin > 15 ? ' ⚠️ FIGÉ (>15 min, PAS une mesure actuelle)' : ''; return `${t} (Paris, il y a ${ageMin} min)${stale}`; } async function readOne(entity) { const ac = new AbortController(); const to = setTimeout(() => ac.abort(), 10000); let r; try { r = await fetch(`${HA_BASE}/api/states/${entity}`, { headers: { Authorization: `Bearer ${token()}` }, signal: ac.signal }); } catch (e) { clearTimeout(to); console.log(`${entity} : ERREUR réseau (${e.name}) — ne rien inventer`); return; } clearTimeout(to); if (r.status === 404) { console.log(`${entity} : INEXISTANT (HTTP 404) — cette entité n'existe pas, ne pas substituer`); return; } if (!r.ok) { console.log(`${entity} : ERREUR HTTP ${r.status} — rapporter ce code, ne rien inventer`); return; } const j = await r.json(); const unit = j.attributes && j.attributes.unit_of_measurement ? ` ${j.attributes.unit_of_measurement}` : ''; console.log(`${entity} = ${j.state}${unit} | maj ${parisAge(j.last_changed)}`); } (async () => { const entities = process.argv.slice(2); if (!entities.length) { console.error('usage: airtria-ha-read.js [entity_id ...]'); process.exit(2); } for (const e of entities) await readOne(e); })().catch(e => { console.error('[ha-read]', e.message); process.exit(1); });