Index des specs Sowel¶
Ce fichier sert d'aide à la navigation sur specs/. Chaque spec sous specs/XXX-name/ contient typiquement trois fichiers : spec.md (exigences + critères d'acceptation), architecture.md (design technique), plan.md (étapes d'implémentation).
Utilisez cet index pour récupérer rapidement le contexte : parcourez les descriptions, trouvez la spec pertinente, puis lisez le dossier complet pour les détails.
Les specs sont regroupées par thème et annotées d'un statut :
- ✅ active : implémentée et en production
- 🔁 superseded : remplacée par une spec ultérieure (suivez la flèche)
- 🟡 partial : implémentée, mais le périmètre a évolué
Fondations (V0.x) : moteur central¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 001 | V0.1 MQTT devices | ✅ | Première intégration avec le bridge Zigbee2MQTT. Auto-découverte de devices brute via MQTT. |
| 002 | V0.1 UI scaffolding devices | ✅ | Frontend React initial avec liste de devices. |
| 003 | V0.2 Zones | ✅ | Zones imbriquables hiérarchiquement. Structure parent-enfant en arbre. |
| 004 | V0.3 Equipments | ✅ | Équipements user-facing qui se lient aux devices via des clés de données. |
| 005 | V0.5 UI restructuring | ✅ | Refonte de la navigation (home, zones, équipements, devices, admin). |
| 006 | V0.6 Sensor equipments | ✅ | Types de capteurs température, humidité, mouvement, luminance. |
| 007 | V0.7 Zone aggregation | ✅ | Calcul auto des métriques de zone depuis les données d'équipement (motion=OR, temp=AVG, etc.). |
| 008 | Shutter equipments | ✅ | Position + état + ordres de cover (ouvrir/fermer/stop). |
| 009 | V0.8 Recipes | ✅ | Moteur d'automatisation avec slots typés. Premières recettes intégrées. |
| 010 | V0.9 Modes | ✅ | États nommés au niveau zone (Day/Night/Away) avec impacts. |
| 011 | V0.10a Integration plugin architecture | 🔁 superseded by 040, 053 | Interface plugin initiale pour les intégrations. |
V0.10 : intégrations natives (la plupart sont maintenant 🔁 externalisées en plugins)¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 012 | V0.10b Panasonic Comfort Cloud | 🔁 → 050 | Polling de l'API cloud des climatiseurs Panasonic (maintenant un plugin). |
| 013 | V0.10c MCZ Maestro | 🔁 → 049 | Intégration Socket.IO du poêle à granulés MCZ (maintenant un plugin). |
| 014 | V0.10d Netatmo Home+Control | 🔁 → 048a, 048b, 048c | Intégration Netatmo HC (séparée maintenant en 3 plugins : weather, control, energy). |
V0.11 : logging, backup, UX volets¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 015 | V0.11 Logging system | ✅ | Logging structuré pino, ring buffer, tagging par module, viewer de logs UI. |
| 016 | V0.8b Motion Light enhancements | ✅ | Affinements de la recette motion-light (créneaux horaires, override, fallback). |
| 017 | V0.11b Backup hardening | 🔁 → 046, 058, 060 | Premier système de backup (export/import). |
| 018 | Recipes roadmap | ✅ (meta) | Document roadmap pour les recettes prévues. |
| 019 | V0.8c Switch light | ✅ | Recette switch-light (bascule à l'appui sur bouton). |
| 020 | V0.8e Presence thermostat | ✅ | Logique de consigne thermostat basée sur la présence avec cocoon. |
| 021 | V0.8f Zone commands | ✅ | Batching d'ordres au niveau zone (allShuttersOpen/Close, allLightsOn/Off). |
UX et tableau de bord¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 022 | Dark mode | ✅ | Dark mode basé sur la classe Tailwind avec préférence utilisateur. |
| 023 | Sunrise / sunset | ✅ | Sunlight manager basé sur SunCalc avec réglages d'offset. |
| 024 | Motion light split | ✅ | Séparation de motion-light en variantes basique et dimmable. |
| 025 | V0.13 History (InfluxDB) | ✅ | Historique en série temporelle pour les données numériques de devices. |
| 026 | V0.8 Cocoon thermostat | ✅ | Logique cocoon au coucher pour le thermostat de présence. |
| 027 | V0.8 Presence heater | ✅ | Recette de radiateur basée sur la présence (éco/confort). |
| 028 | MQTT publishers | ✅ | Manager de publisher MQTT sortant (mappings d'événements vers topics). v1.2.6 : option onChangeOnly, publication seulement au changement de valeur pour ne pas inonder les afficheurs externes. |
| 029 | MQTT brokers | ✅ | Support multi-broker pour les publishers MQTT. |
| 030 | Logging audit | ✅ | Stratégie consolidée des niveaux de log et taxonomie des modules. |
| 031 | Notification publishers | ✅ | Canaux de notification Telegram / webhook / FCM / ntfy. |
| 032 | State watch recipe | ✅ | Surveillance générique de clé de donnée avec recette d'alarme. |
| 033 | Dashboard widgets | ✅ | Widgets de zone personnalisables sur le tableau de bord. |
| 034 | Progressive Web App | ✅ | Manifest PWA, service worker (NetworkOnly pour /api/), bandeau offline. |
| 035 | Energy dashboard | ✅ | Ventilation jour/semaine/mois/année avec classification HP/HC. |
| 036 | Order dispatch error handling | ✅ | Fallback gracieux quand la publication d'un ordre échoue. |
| 037 | Panasonic CC connection resilience | 🔁 → 050 | Logique de reconnexion pour Panasonic Comfort Cloud. |
| 038 | MCZ connection resilience | 🔁 → 049 | Logique de reconnexion pour MCZ Maestro. |
| 039 | Integrations page redesign | ✅ | Page intégrations unifiée (liste, configuration, statut). |
Système de plugins V2 (crucial, architecture actuelle)¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 040 | Plugin engine | 🟡 superseded by 053 | Première génération de moteur de plugins (install depuis zip local). |
| 041 | Weather forecast plugin | ✅ | Plugin de prévisions météo basé sur Open-Meteo (exemple de référence). |
| 042 | Weather forecast equipment | ✅ | Type d'équipement pour l'affichage des données de prévision. |
| 043 | Plugin update | ✅ | Mise à jour de plugin in-place depuis une release GitHub. |
| 044 | Plugin SmartThings | ✅ | Plugin Samsung SmartThings (polling + ordres). |
| 045 | Plugin SmartThings OAuth | ✅ | Flux OAuth2 pour l'authentification SmartThings. |
| 046 | Backup v2 | 🔁 → 058, 060 | Format de backup révisé (inclut le line protocol InfluxDB). |
| 047 | Prebuilt plugins | ✅ | Distribution de plugins via les releases GitHub (tarball). |
V1.0 : externalisation de toutes les intégrations en plugins¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 048a | Plugin Netatmo Weather | ✅ | Intégration Netatmo Weather Station externalisée. |
| 048b | Plugin Legrand Control | ✅ | Legrand Home+Control externalisé (lumières/volets/prises). |
| 048c | Plugin Legrand Energy | ✅ | Suivi énergétique Legrand externalisé (compteurs NLPC). |
| 049 | Plugin MCZ Maestro | ✅ | Intégration MCZ Maestro externalisée. |
| 050 | Plugin Panasonic CC | ✅ | Intégration Panasonic Comfort Cloud externalisée. |
| 051 | Plugin LoRa2MQTT | ✅ | Bridge LoRa2MQTT en tant que plugin. |
| 052 | Plugin Zigbee2MQTT | ✅ | Zigbee2MQTT en tant que plugin (la dernière intégration native à être externalisée). |
| 053 | Package manager | ✅ | Refactor majeur : le service PackageManager gère tous les paquets (intégrations + recettes). Distribution basée sur GitHub avec plugins/registry.json. |
| 054 | Recipe packages | ✅ | Recettes externalisées en tant que paquets (même modèle de distribution que les plugins). |
| 055 | Versioning + CI/CD + Docker | ✅ | Workflow de release GitHub Actions, scripts/release.sh, image ghcr.io, tags semver. Introduit en v1.0.0. |
V1.0+ : auto-update et déploiement¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 049 | Externalize MCZ Maestro as Plugin | ✅ | Livrée. Voir specs/049-plugin-mcz-maestro/. |
| 050 | Externalize Panasonic CC as Plugin | ✅ | Livrée. Voir specs/050-plugin-panasonic-cc/. |
| 051 | Externalize LoRa2MQTT as Plugin | ✅ | Livrée. Voir specs/051-plugin-lora2mqtt/. |
| 052 | Externalize Zigbee2MQTT as Plugin | ✅ | Livrée. Voir specs/052-plugin-zigbee2mqtt/. |
| 053 | PackageManager Extraction + Plugin Adaptation | ✅ | Livrée. Voir specs/053-package-manager/. |
| 054 | Recipe Packages | ✅ | Livrée. Voir specs/054-recipe-packages/. |
| 055 | Versioning 1.0.0, CI/CD & Docker | ✅ | Livrée en v1.0.0. Voir specs/055-versioning-cicd-docker/. |
| 057 | Self-update UI | 🔁 → 060 | Premier auto-update via l'UI (avait une race condition). |
| 058 | Backup completeness | ✅ | Auto-téléchargement des plugins manquants au démarrage ; scan dynamique des fichiers de données ; restauration FK-safe. |
| 059 | Remote registry + backup fix | ✅ | Récupération de plugins/registry.json à distance avec cache + fallback local. InfluxDB ensureBuckets avant restauration. |
| 060 | Self-update helper + detection improvements | ✅ | Architecture actuelle d'auto-update : pattern de container helper (spawn docker:25-cli qui survit à la mort de sowel), backup pré-update auto dans data/backups/ (rotation, conserve 3), poll de version 1 h, push WebSocket de update.available, bouton "Check for updates", détection composeManaged. |
| 061 | Timezone from home location | ✅ | Auto-dérivation de process.env.TZ depuis home.latitude/home.longitude via tz-lookup au boot (s'exécute avant createLogger() pour éviter le caching TZ V8). Endpoints GET /system/timezone + POST /system/restart (container helper). UI : TZ dans Réglages, CurrentTimePill dans le header, RestartToast au changement de localisation. |
| 062 | Water valve equipment | ✅ | Nouveau type d'équipement water_valve avec icône custom de vanne, famille de widget water, agrégation de zone (open/total + somme de débit), pastille de zone, widget tableau de bord (close-all), et carte de détail avec toggle + arrosage minuté. Cible les SONOFF SWV et vannes connectées similaires. Base pour une future recette d'auto-arrosage (spec 063). |
Refactoring du dispatch d'ordre (migration progressive)¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 063 | Auto-watering recipe plugin | ✅ | Livrée en v1.1.0. Voir specs/063-auto-watering-recipe/. |
| 064 | Weather computed rain data + cumulative bar charts | ✅ | Livrée en v1.1.0. Voir specs/064-weather-computed-rain/. |
| 065 | Freecooling recipe plugin | ✅ | Livrée en v1.1.2. Voir specs/065-freecooling-recipe/. |
| 066 | Registry independence from Sowel releases | ✅ | Livrée en v1.2.0. Voir specs/066-registry-independence/. |
| 067 | Order dispatch — core + lora2mqtt | ✅ | Nouvelle signature executeOrder(device, orderKey, value) avec rétro-compat v1. Première migration : lora2mqtt v2.0.0. Résolution d'enum insensible à la casse. |
| 068 | Order dispatch — zigbee2mqtt | ✅ | Migration du plugin z2m vers v2.0.0 (apiVersion 2). Support des payloads composites préservé. |
| 069 | Order dispatch — legrand-control | Planned | Migration de legrand-control (IDs API cloud stockés en mémoire du plugin). |
| 070 | Order dispatch — panasonic-cc | Planned | Migration de panasonic-cc (guid/param stockés en mémoire du plugin). |
| 071 | Order dispatch — mcz-maestro | Planned | Migration de mcz-maestro (commandId stocké en mémoire du plugin). |
| 072 | Order dispatch — netatmo-security | Planned | Migration de netatmo-security (paramètre unique : monitoring). |
| 073 | Order dispatch — smartthings | Planned | Migration de smartthings (noms de commande stockés en mémoire du plugin). |
| 074 | Order dispatch — cleanup | Planned | Suppression de la rétro-compat v1. Suppression de la colonne dispatch_config de device_orders. |
Équipements piscine¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 075 | Order Dispatch: Legrand Energy Migration | ✅ | Livrée. Voir specs/075-order-dispatch-legrand-energy/. |
| 076 | Order Dispatch: Netatmo Weather Migration | ✅ | Livrée en v1.2.12. Voir specs/076-order-dispatch-netatmo-weather/. |
| 077 | Order Categories | ✅ | Livrée en v1.2.12. Voir specs/077-order-category/. |
| 078 | Button Zone Orders & Zone-First Equipment Selection | ✅ | Livrée en v1.2.14. Voir specs/078-button-zone-orders/. |
| 079 | Device Data Enum Values | ✅ | Livrée en v1.2.14. Voir specs/079-data-enum-values/. |
| 080 | Tasmota Plugin Integration | ✅ | Livrée en v1.2.15. Voir specs/080-tasmota-plugin/. |
| 081 | Pool equipments | ✅ | Types pool_pump, pool_cover avec liaison basée sur des candidats pour les relais multi-canaux |
| 082 | Pool pump schedule | ✅ | Plugin de recette avec 3 créneaux on/off journaliers |
| 083 | Pool heat pump (Polytropic) | ✅ | Type pool_heat_pump + plugin d'intégration Modbus (Polytropic Master Inverter) |
Refactor énergétique Shelly (multi-itérations)¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 084 | Shelly energy — overview | Planned | Principes directeurs pour la migration en 4 itérations de Legrand vers Shelly Pro 3EM |
| 085 | Iteration 1 — shelly-em plugin (live) | Planned | Plugin Sowel : act_power live et compteurs par canal, en parallèle de Legrand |
| 086 | Iteration 2 — Shelly drives roles | Planned | Promotion des canaux Shelly en main_energy_meter + energy_production_meter, retrait de Legrand |
| 087 | Iteration 3 — energydata-stack | Rejected | Remplacé par l'archive native du Shelly Pro 3EM (60 j in-device) ; voir 088 pour le correctif réel |
| 088 | Iteration 4 — Shelly gap backfill | Planned | Le plugin interroge la RPC EM1Data.GetData au boot et toutes les heures pour rejouer les minutes manquantes dans le pipeline live |
V1.5 : graphique par usage, bascules MQTT, recette state-trigger¶
| # | Title | Status | Résumé |
|---|---|---|---|
| 089 | Security hardening: plugin supply chain & backup path safety | ✅ | Livrée en v1.6.2. Voir specs/089-security-hardening-supply-chain-backup/. |
| 090 | MQTT mapping enable/disable | ✅ | Flag enabled par mapping sur les publishers MQTT, en complément de la bascule au niveau publisher. Icône power-off UI + opacité réduite sur les lignes désactivées. Permet à l'utilisateur de mettre en sourdine un seul mapping (source saisonnière) sans perdre sa configuration. |
| 091 | By-usage consumption chart | ✅ | Nouvel endpoint GET /energy/by-usage et bascule Total / Par usage sur la page Énergie qui rend une ventilation empilée par sous-compteur energy_meter + un résidu "Other" (compteur principal - Σ sous-compteurs). |
| 092 | State-triggered light recipe | ✅ | Nouveau plugin de recette externe state-trigger-light (dans plugins/registry.json). Allume les lumières pour une durée fixe quand l'alias state d'un équipement surveillé transite vers une valeur cible. Filtre nightOnly optionnel via le sunlight manager. Introduit les contraintes de slot crossZone et includeDescendants. |
V1.11 : durcissement runtime des plugins¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 094 | UI Redesign (umbrella + Phase 0 palette swap) | ✅ | Livrée. Voir specs/094-ui-redesign/. |
| 095 | Design System Phase 1: Typography Polish | ✅ | Livrée. Voir specs/095-design-system-typography/. |
| 096 | Design System Phase 2: Sidebar | ✅ | Livrée. Voir specs/096-design-system-sidebar/. |
| 097 | Design System Phase 3: Strip Pills (Zone Aggregation) | ✅ | Livrée. Voir specs/097-design-system-strip-pills/. |
| 098 | Design System Phase 4: Dashboard Widgets | ✅ | Livrée. Voir specs/098-design-system-dashboard/. |
| 099 | Design System Phase 5: Equipment Row | ✅ | Livrée. Voir specs/099-design-system-equipment-row/. |
| 100 | Design System Phase 6: Zone View 2-Column Layout | ✅ | Livrée. Voir specs/100-design-system-comportements/. |
| 101 | Activity Feed (Zone view right column) | ✅ | Livrée en v1.8.0. Voir specs/101-design-system-activity-feed/. |
| 102 | Design System Phase 8: Recipe Edit Modal + Surcharges par mode | ✅ | Livrée. Voir specs/102-design-system-recipe-modal/. |
| 104 | Self-update resilience | ✅ | Livrée en v1.6.3. Voir specs/104-self-update-resilience/. |
| 105 | WAN Hardening | ✅ | Livrée en v1.7.0. Voir specs/105-wan-hardening/. |
| 106 | Make the topbar "update available" pill actionable | ✅ | Livrée en v1.9.0. Voir specs/106-update-pill-actionable/. |
| 107 | Surface a changelog link per row in the UpdatesSheet | ✅ | Livrée en v1.10.0. Voir specs/107-update-row-changelog-link/. |
| 108 | Block releases without release notes | ✅ | Livrée en v1.10.0. Voir specs/108-release-notes-required/. |
| 109 | Preserve bound device data/orders across partial re-discoveries | ✅ | Livrée en v1.10.1. Voir specs/109-device-discovery-preserve-bound/. |
| 110 | Category-first binding resolution across the codebase | ✅ | Livrée en v1.10.3. Voir specs/110-category-first-binding-resolution/. |
| 111 | Isolation soft des plugins | ✅ | Proxies scopés autour des PluginDeps de chaque plugin (settings, event bus, device manager). Quatre invariants enforces au niveau JavaScript : settings scopés à integration.<own-id>.*, whitelist d'events system.*, ownership des devices forcée par integrationId, et confinement des erreurs sur les méthodes lifecycle. Actif sans condition depuis v1.11.0. Pas de breaking change pour les auteurs de plugins. |
| 112 | Handlers de crash process | ✅ | Listeners globaux uncaughtException et unhandledRejection installés au boot. Un throw qui échappe à toutes les autres protections produit désormais une ligne fatal structurée (stdout + data/logs/sowel.N.log) avant que le process exit, pour que Docker relance le conteneur avec une trace exploitable au lieu d'une boucle silencieuse. Audit F03, spec 112. Livré en v1.11.1. |
| 113 | Journal d'audit | ✅ | Trail SQLite persistant de toute action sensible (auth, user CRUD, settings, mode, backup, plugin). Nouvelle table audit_log + service AuditLogger appelé depuis les route handlers avec contexte acteur et IP. Endpoint admin-only GET /api/v1/audit avec pagination et filtrage. Rétention 365 jours purgée au boot. Les valeurs sensibles sont redactées du meta. Audit F13, spec 113. Livré en v1.11.1. |
V1.13 : store banne + bridge Somfy RTS¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 115 | Store banne + bridge Somfy RTS | ✅ | Nouveau type d'équipement awning (frère du shutter) avec sa famille de widget awnings et une illustration V3 colorée dédiée (fenêtre + cassette + 10 bandes trapézoïdales festonnées en mode déployé, frise rétractée en mode fermé). Réutilise les catégories shutter_position / shutter_move / set_shutter_position — toute intégration qui les émet peut piloter un store banne. Trois commandes de zone allAwningsExtend/Stop/Retract. Plugin compagnon sowel-plugin-somfy-rts pour le bridge ESP32+CC1101 somfyrts2mqtt. Livré en v1.13.0. |
V1.14 : UX station météo¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 114 | UX station météo | ✅ | Refonte du widget station météo : section dédiée au module extérieur (température, humidité, enveloppe min/max), liaisons exposées sur le sélecteur d'appareils, historisation par défaut du module extérieur Netatmo, désambiguïsation des libellés de même catégorie sur les graphiques. Livré en v1.14.x. |
V1.15 : navigateur calendrier Analyse + répartition sous-compteurs en direct¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 116 | Disponibilité des équipements | 📝 Brouillon | Propager la disponibilité (hors ligne / dégradé / en ligne) de l'état des appareils vers les équipements, avec badges UI et statut agrégé par zone. Rédigée le 2026-05-24, non démarrée. |
| 117 | Calendrier Analyse + sous-compteurs | ✅ | Navigateur calendrier sur la vue Analyse (jour/sem/mois/année + flèches) remplaçant l'ancien sélecteur de plage, avec fenêtre absolue et axe X temporel. Donut de répartition des sous-compteurs en direct sur la page Énergie. Burger mobile pour Analyse. Livré en v1.15.0. |
| 118 | Améliorations graphiques Analyse | 📝 Brouillon | Enveloppe min/max sur les courbes en résolution 1h/1d, barres pour les sélections pluie/énergie, total de pluie journalier correct dans le backfill Netatmo, garde-fous du backfill (--only). Documente l'incident de perte de données pluie du 2026-05-30. |
V1.17 - V1.19 : API historique énergie + afficheurs supervisés¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 119 | Agrégation par période de l'historique énergie | ✅ | Les endpoints d'historique énergie renvoient des buckets pré-agrégés alignés calendrier (24 horaires pour le jour, 7 quotidiens pour la semaine, 28-31 pour le mois, 12 mensuels pour l'année) : plus de ré-agrégation côté client. Un seul aggregateWindow InfluxDB aligné sur le fuseau serveur, split HP/HC conservé par bucket. Livré en v1.17.0. |
| 120 | Type d'équipement afficheur | ✅ | Nouveau type display pour les écrans supervisés par Sowel (premier matériel : le firmware AMOLED sowel-energy-display) : page de détail firmware/uptime/rssi, langue et luminosité en ligne, famille de widgets displays avec agrégation en ligne/total par zone. Livré en v1.18.0. |
| 121 | Plugin MQTT de supervision d'afficheurs | ✅ | Plugin MQTT compagnon (repo séparé, désormais sowel-plugin-displays) découvrant les afficheurs via un payload state retained avec disponibilité LWT, exposés comme appareils liables à l'équipement de la spec 120. Contrat state + cmd/<key> réutilisable par tout futur afficheur. Livré avec v1.18.0. |
| 122 | Action de réveil des afficheurs | ✅ | Ordre display_wake sans valeur demandant à l'écran de restaurer la luminosité préférée de l'utilisateur depuis la NVS ; les recettes de veille par présence n'ont plus à connaître le niveau. Livré en v1.19.0. |
V1.20 : valorisation en euros + mode ombre¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 123 | Valorisation du coût énergie | ✅ | Bascule Wh/€ sur la page Énergie revalorisant historique, totaux et répartition par usage en euros via le tarif HP/HC existant. Coûts calculés à la lecture, aucun changement de schéma InfluxDB ; bascule persistée en localStorage. Livré en v1.20.0. |
| 124 | Mode ombre | ✅ | SOWEL_SHADOW_MODE=1 rend un conteneur sûr face à une copie de la production : l'UI fonctionne, tout ce qui sort (plugins, recettes, publishers MQTT/notifications, polling GitHub) est neutralisé au boot et au runtime. Log d'avertissement, endpoint système, bandeau ambre. Livré en v1.20.0. |
V1.21 - V1.23 : solaire + briques recettes¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 125 | Équipement panneau solaire + APsystems | ✅ | Nouvel équipement solar_panel en lecture seule (un équipement = un panneau = une voie d'onduleur) : puissance/énergie/tension/courant/température DC, widget dédié, groupe Solaire du dashboard. Catégorie temperature_device hors moyennes de pièce, plugin compagnon sowel-plugin-apsystems. Livré en v1.21.0. |
| 126 | Slot select + getSunlight() | ✅ | Les formulaires de recettes gagnent un slot select (liste fermée localisée) et les recettes ctx.helpers.getSunlight() (lever/coucher/jour avec offsets spec 023) : les briques derrière la recette Programmation horaire du store. Livré en v1.23.0. |
V1.24 - V1.26 : notifications¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 127 | Notifications Web Push (PWA) | ✅ | Push natif sur la PWA installée en HTTPS, à côté de Telegram : activation par appareil dans les réglages, puis mapping d'un publisher Web Push sur n'importe quelle valeur. Clés VAPID générées au premier boot, abonnements par utilisateur. Livré en v1.24.0 (correctifs iOS jusqu'en v1.24.3). |
| 128 | Répétition de notification | ✅ | Option explicite de re-notification : tant qu'une valeur mappée reste active (ex. alarme State Watch), la notification se renvoie à cadence fixe et s'arrête silencieusement quand ça se résout. Aucune / Indéfiniment / Limitée à N. Livré en v1.26.0. |
V1.27 - V1.30 : mesure, arrosage, RBAC, triphasé¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 129 | Interrupteur avec mesure | ✅ | Une prise/interrupteur affiche puissance et énergie en direct quand l'appareil les remonte (ex. SONOFF S60ZBTPF) : puissance à côté du bouton ON/OFF, alimentation du dashboard énergie et de la répartition en direct. Les relais simples ne changent pas. Livré en v1.27.0. |
| 130 | Jours de semaine par créneau d'arrosage | ✅ | Chaque créneau d'arrosage peut être limité à des jours choisis (vide = tous les jours), ex. 07:30 les jours d'école et 09:00 le week-end. Nouveau champ multi-select de recette rendu en puces. Livré en v1.28.0. |
| 131 | RBAC : configuration admin only | ✅ | Le rôle Standard est limité à voir et actionner : dashboards, états et commandes oui, mais aucune création/renommage/suppression ni configuration. Appliqué côté serveur (403) et masqué dans l'UI. Livré en v1.29.0. Amendé par l'issue #912 : activer, désactiver et appliquer un mode passent dans la liste blanche standard — le mode actif est un état d'exécution et une actuation, tandis que ce qu'un mode est reste réservé à l'admin. |
| 132 | Répartition par phase sur Énergie Live | ✅ | Les installations triphasées peuvent afficher une barre par phase sous le diagramme de flux : un compteur principal portant les liaisons power_l1/l2/l3 rend le déséquilibre visible d'un coup d'œil. Convention de liaison ouverte à toute intégration. Livré en v1.30.0. |
V1.31 - V1.34 : caméra, min/max météo, chauffe-eau¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 133 | Type d'équipement caméra | ✅ | Équipement camera indépendant du fabricant : instantané rafraîchi périodiquement (page de détail + widget), vue en direct HLS à la demande, contrôles surveillance/projecteur/sirène optionnels. Tous les médias passent par le backend : le navigateur ne parle jamais à la caméra ni au relais du fabricant. Livré en v1.31.0. |
| 134 | Min/max journalier météo | ✅ | Les stations météo affichent le min et le max mesurés du jour sous chaque température (widgets PC et mobile, page de détail, modules extérieur et intérieur). Sowel suit l'enveloppe lui-même à partir des échantillons déjà reçus : indépendant du fabricant, sans configuration, remise à zéro à minuit local. Livré en v1.32.0. |
| 135 | Équipement chauffe-eau | ✅ | Nouvel équipement water_heater : ON/OFF via le canal relais standard (Tuya WHD02 fonctionne directement), température de l'eau optionnelle sous son propre alias hors moyennes de pièce, puissance/énergie automatiques sur relais avec mesure, icône d'état de chauffe. Livré en v1.34.0. |
V1.35 : sources personnelles de plugins¶
| # | Titre | Statut | Résumé |
|---|---|---|---|
| 136 | Sources personnelles de plugins | ✅ | Troisième niveau de confiance à côté d'officiel/communautaire (spec 089) : un admin enregistre ses propres dépôts GitHub publics comme sources de plugins, sans PR sur le registre central. Modèle TOFU : SHA256 du tarball affiché dans un modal de confirmation, épinglé en base, re-confirmation à chaque changement de contenu ; les restaurations de backup vérifient contre le hash épinglé. Nouvelle table plugin_sources, PersonalSourceManager, routes /api/v1/plugins/sources, badge Perso + section sources dans l'UI Plugins. Mergé le 2026-08-08 (#367), non livré. |
| 137 | Plugins Page: Recipe Categories and Search | ✅ | Livrée en v1.36.0. Voir specs/137-plugins-categories-search/. |
| 138 | Read-only tariff helper for recipes | ✅ | Livrée en v1.37.0. Voir specs/138-recipe-tariff-helper/. |
| 139 | Zone-qualified equipment pickers in recipe forms | ✅ | Livrée en v1.37.1. Voir specs/139-zone-qualified-recipe-pickers/. |
| 140 | Energy Capacity Arbiter | ✅ | Livrée en v1.39.0. Voir specs/140-energy-capacity-arbiter/. |
| 141 | Spec 141: Order Delivery Confirmation | ✅ | Livrée en v1.39.0. Voir specs/141-order-delivery-confirmation/. |
| 142 | Zone paths in the equipments admin list | ✅ | Livrée. Voir specs/142-equipments-list-zone-path/. |
| 143 | Spec 143: Low Battery Alerts | ✅ | Livrée en v1.43.0. Voir specs/143-low-battery-alerts/. |
| 144 | States and measurements on one Analyse chart | ✅ | Livrée en v1.42.0. Voir specs/144-analyse-mixed-state-axis/. |
| 145 | Series colours and Y axes on the Analyse chart | ✅ | Livrée en v1.43.0. Voir specs/145-analyse-series-color-and-y-axis/. |
| 146 | Confirmation before a sensitive gate action | ✅ | Livrée. Voir specs/146-gate-action-confirmation/. |
| 147 | Persist the activity feed and the arbiter decision journal | ✅ | Livrée. Voir specs/147-persist-activity-arbiter-history/. |
| 148 | Energy arbiter UI polish (design-system + redesigned timeline) | ✅ | Livrée. Voir specs/148-arbiter-ui-polish/. |
| 149 | Dashboard presentation resolver (phase 1) | ✅ | Livrée. Voir specs/149-dashboard-presentation-resolver/. |
| 150 | Typed value normalization at ingestion + unified binding candidates | ✅ | Livrée en v1.48.0. Voir specs/150-value-normalization-unified-binding/. |
| 151 | Two-Factor Authentication (TOTP + Backup Codes) | ✅ | Livrée. Voir specs/151-mfa-totp/. |
| 152 | Equipment solar command channel | ✅ | Livrée en v1.52.0. Voir specs/152-equipment-solar-command/. |
| 153 | VMC (2-speed ventilation) equipment type | ✅ | Livrée. Voir specs/153-vmc-equipment/. |
| 154 | Per-equipment invert direction for shutter-family equipments | ✅ | Livrée en v1.52.5. Voir specs/154-shutter-invert/. |
| 155 | Invert Direction for Boolean Gate Triggers (issue #627) | ✅ | Livrée. Voir specs/155-gate-invert-direction/. |
| 156 | UPS (uninterruptible power supply) equipment type | ✅ | Livrée en v1.53.0. Voir specs/156-ups-equipment/. |
| 157 | Shared FlowDiagram, and the UPS panel rebuilt on it | ✅ | Livrée en v1.54.0. Voir specs/157-flow-diagram/. |
| 158 | Arbiter baseline metrics | ✅ | Livrée en v1.55.0. Voir specs/158-arbiter-metrics/. |
| 159 | Weather forecast: multi-model and ensemble confidence | ✅ | Livrée en v1.56.0. Voir specs/159-weather-forecast-multi-model/. |
| 160 | PV production forecast | ✅ | Livrée en v1.57.0. Voir specs/160-pv-production-forecast/. |
| 161 | Fit the PV model from existing history | ✅ | Livrée en v1.57.0. Voir specs/161-pv-history-backfill/. |
| 162 | Tell the household when the panels stop performing | ✅ | Livrée en v1.58.0. Voir specs/162-pv-health/. |
| 163 | PV monitoring and configuration find their place | ✅ | Livrée en v1.58.0. Voir specs/163-pv-ui-reorg/. |
| 164 | Granted-but-idle on the arbiter timeline | ✅ | Livrée en v1.59.0. Voir specs/164-arbiter-timeline-idle-grant/. |
| 165 | One load-state model for the arbitration surface | ✅ | Livrée en v1.59.0. Voir specs/165-arbiter-state-model/. |
| 166 | Claimant-declared need for a granted load | ✅ | Livrée en v1.60.0. Voir specs/166-arbiter-claimant-need/. |
| 167 | Documentation currency gates | ✅ | Livrée. Voir specs/167-documentation-currency/. |
| 168 | Widget prévisions : bande 5 jours et panneau détail | ✅ | Livrée. Voir specs/168-forecast-widget-five-days/. |
| 169 | Tuile Dashboard pour une instance de recette | ✅ | Livrée. Voir specs/169-dashboard-recipe-widget/. |
| 170 | Une zone somme la puissance que ses sous-compteurs mesurent | ✅ | Livrée. Voir specs/170-zone-power-aggregate/. |
| 171 | Un clic sur une tuile de recette déclenche sa commande | ✅ | Livrée. La spec 169 a donné une tuile à une instance de recette et a laissé toute la carte inerte : une carte qui affichait « Prêt, un clic ouvre le Portail pour 15 min » ne faisait rien quand on cliquait, alors que tous les autres widgets actionnent au clic sur la carte depuis la spec 098. Une tuile qui n'affiche qu'une seule commande la déclenche désormais depuis toute la carte, même cycle et même valeur suivante que la pastille, qui reste là pour qui préfère viser ; deux commandes, aucune, une instance désactivée et le mode édition laissent la carte inerte. Comme cela transforme un carré de 240 px en ouvre-portail, le paquet déclare où la question de la confirmation est répondue : tile.confirmFrom nomme l'emplacement d'équipement que la commande actionne et le requireConfirmation de cet équipement (spec 146) décide alors seul, donc la réponse est donnée une fois et toutes les surfaces qui actionnent le portail posent la même question ; confirmParam la confie à l'instance là où aucun équipement ne peut être dérivé, et tile.confirm est le défaut du paquet. Sur mobile, une carte gardée ouvre la feuille glisser-pour-confirmer de la spec 146 ; la pastille n'est jamais gardée et le bureau ne confirme jamais. Voir specs/171-recipe-tile-primary-action/. |
| 172 | Le panneau des mises à jour sait terminer une mise à jour personnelle | ✅ | Livrée. Voir specs/172-updates-sheet-personal-confirm/. |
| 173 | Un compteur qui se trouve à l'intérieur d'un autre | ✅ | Livrée. Voir specs/173-nested-submeters/. |
| 174 | Une action minutée sur un équipement actionnable | ✅ | Phases 1 et 2 (moteur, API, et les deux surfaces d'usage). Rien dans le moteur ne savait dire « agis maintenant, reviens en arrière dans N minutes » : chaque occurrence était une recette tenant son propre minuteur — motion-light, state-trigger-light, delivery-gate — trois copies avec trois jeux de règles d'annulation qui divergeaient déjà. Un équipement porte désormais au plus un retour que le moteur lui doit, persisté en base plutôt qu'en setTimeout : une échéance encore devant survit à un redémarrage sur son reliquat, une échéance passée pendant l'arrêt part au retour — c'est le cas pour lequel la fonctionnalité existe. Quatre règles sont tranchées plutôt que découvertes : un retour fait à la main sur la mesure miroir désarme (agir plus tard déferait le geste de l'utilisateur, et sur une commande qui bascule rouvrirait le portail qu'il vient de fermer) ; un second armement de la même action repousse l'échéance sans rien envoyer (« ouvre encore », devant un portail ouvert, veut dire « laisse-moi plus de temps ») ; un retour qui n'a pas pu partir lève une alerte et s'arrête au lieu de rejouer à l'aveugle ; supprimer l'équipement emporte son échéance. Les deux moitiés passent par executeOrder, donc l'inversion (spec 154), la résolution de valeur (spec 150) et la confirmation de livraison (spec 141) sont héritées et non redites. La phase 2 configure la commande sur la page équipement et la rend sur la tuile Dashboard et la carte compacte, via UN seul composant de décompte partagé ; les trois surfaces restantes attendent la spec 149 (#325), qui hérite désormais d'une implémentation et non de cinq. Elle a aussi supprimé le refus d'une action et d'un retour de même valeur, qui excluait le portail à impulsion séquentielle pour lequel la fonctionnalité existe, et l'a remplacé par une règle d'éligibilité : l'équipement doit porter l'ordre et une mesure d'état qui lui est liée, sans quoi un retour fait à la main ne pourrait jamais terminer le créneau. Hors périmètre également : un replaySafe déclaré par l'intégration, qui transformerait la règle d'échec d'un défaut prudent en la bonne réponse. Voir specs/174-equipment-timed-action/. |
| 175 | Une mesure de puissance est jugée sur sa propre cadence | ✅ | Quatre surfaces décidaient si une puissance pouvait être affichée en direct, et elles se contredisaient : un compteur à trois minutes d'un cycle de 300 s parfaitement sain était silencieux dans la bannière Live, « périmé » sur sa tuile du Dashboard et retiré du total de sa zone, au même instant. Chacune tenait une constante déduite du TYPE d'équipement, qui ne dit rien de la fréquence à laquelle un appareil parle : main_energy_meter couvre aussi bien un Shelly à 1 Hz qu'un connecteur cloud à 300 s, et un seul chiffre est forcément faux pour l'un des deux. Le moteur dérive désormais la fenêtre de ce que fait réellement la source, l'intervalle médian entre ses arrivées récentes ou, à défaut, l'intervalle d'interrogation déclaré par son intégration, sous la forme clamp(2,5 x cadence, 120 s, 30 min), et la porte sur la liaison sous le nom freshnessBudgetMs. Les surfaces ne comparent plus qu'un âge à un nombre qu'on leur donne : la divergence disparaît par construction et non par discipline, et la détection suit la source, un compteur à 1 Hz qui meurt se voit en deux minutes au lieu de dix, un poller à 300 s garde son calme. L'estimateur vit en mémoire et sa statistique est une médiane, ce qui absorbe une coupure de six heures au milieu d'échantillons d'une seconde ; au redémarrage, on retombe sur la cadence déclarée puis sur dix minutes prudentes, plutôt que d'afficher tous les compteurs périmés au boot. Elle a aussi supprimé demand_5min, un alias que LIVE_POWER_ALIASES et la règle de budget traitaient à part au motif qu'un Legrand NLPC n'aurait pas de canal power : il en a un, aucun plugin du registre n'a jamais produit cet alias, et sa seule déclaration dans l'histoire du dépôt était une fixture de test. Hors périmètre, volontairement : le statut d'équipement de la spec 116 garde ses fenêtres par catégorie. Voir specs/175-cadence-derived-freshness/. |
| 176 | L'état de marche d'un thermostat a son propre alias | ✅ | Sur un thermostat sous-compté, l'alias power est la puissance de la pince (convention métering), et l'alias est unique par équipement : le booléen marche/arrêt rapporté par le device n'avait donc nulle part où vivre, et chaque surface UI comparait ce wattage à true, lisant l'unité comme éteinte en permanence. Le toggle ne se stabilisait jamais, chaque appui renvoyait ON (cinq ordres ON en 90 s mesurés en production avec la PAC à 2974 W), et l'extinction exigeait un double appui dans la fenêtre optimiste, car la carte effaçait TOUT l'état optimiste au moindre changement de donnée alors que la pince en pousse un toutes les quelques secondes. Même cause racine que l'issue #901, une couche au-dessus. Le booléen du device se lie désormais sous state, le MÊME alias marche/arrêt que tous les équipements à relais (aucun nouveau nom dans le data model ; portée limitée aux thermostats), et l'override de catégorie spec 152 le marque appliance_state : l'arbitre d'énergie le reconnaît comme état de marche tandis que le métering, l'intégrateur de sous-comptage et le panneau énergie ne le confondent jamais avec le wattage. Toute lecture marche/arrêt passe par un helper unique (l'alias state d'abord, un power booléen déclaré en repli, jamais un wattage), l'effacement optimiste devient par alias avec un TTL de 90 s en garde-fou, et deux bugs latents sont morts au passage : RELEVANT_DATA.thermostat datait d'avant les catégories spec 077 (un thermostat fraîchement lié perdait silencieusement power/consigne/sonde extérieure), et un ordre toggle_power s'aliasait state, que rien ne lit. Compagnon : panasonic-cc 2.3.2 ajoute un second poll à la demande à 45 s pour la latence de Comfort Cloud. Voir specs/176-thermostat-run-state/. |
| 177 | Ce qu'est un thermostat ; les extras rendus comme des extras | ✅ | Avant, un thermostat Sowel était ce que les devices Panasonic et MCZ exposaient : leurs clés (nanoe, airSwingUD, profile, resetAlarm) formaient la liste d'auto-liaison dans l'UI produit, un device devait porter la clé brute targetTemperature pour être proposé comme thermostat, et la carte avait une branche par fabricant — la cause derrière la spec 176, dont les propres mots étaient « un alias n'est pas un vocabulaire ». Le cœur est désormais déclaré une fois dans src/shared/thermostat-contract.ts (temperature, setpoint, state, power, operationMode, outsideTemperature optionnel), un device est un thermostat dès qu'il porte une catégorie setpoint / set_setpoint, la température de la pièce et le mode se résolvent par catégorie comme le reste du cœur (operation_mode / set_operation_mode rejoignent la taxonomie, valeurs auto/heat/cool/dry/fan/off), et un thermostat lie tous les ordres de son device — le cœur canonisé, le reste en extras sous sa propre clé. La carte mène avec le cœur et rend les extras génériquement d'après le type de l'ordre ; les branches resetAlarm, stoveState, profile, fanSpeed et ecoMode ont disparu. Aucun changement de donnée, de plugin, de liaison ni de migration : un thermostat existant garde toutes ses liaisons et tous ses contrôles. Partie 1 de l'issue #919 ; la partie 2 (#922) fait publier le contrat par les plugins. Voir specs/177-thermostat-contract/. |
| 178 | Appuyer encore demande plus longtemps, puis abandonne | ✅ | La spec 174 n'avait donné qu'un geste au moteur : un second appui prolonge le créneau de la même durée, indéfiniment. Cela répond « pas encore » mais jamais « combien de temps encore » — sur l'installation de référence, obtenir une heure sur un portail réglé à un quart d'heure demande quatre appuis identiques, et le contrôle ne peut pas dire ce que fera le suivant puisque tous font la même chose. Un équipement déclare désormais des PALIERS de durées (durationStepsMs, de deux à six, croissants) et un appui les gravit : le premier agit et arme le plus court, chaque suivant repousse l'échéance à maintenant + palier suivant sans rien envoyer, et un appui au-delà du dernier abandonne l'échéance sans revenir en arrière — le portail reste ouvert et plus rien ne le refermera. Ce dernier appui n'est volontairement pas le bouton d'annulation, qui envoie le retour : « arrêter le décompte » et « fermer maintenant » sont deux intentions, et chacune garde son contrôle. Le palier est persisté (timed_actions.step_index), pour qu'un redémarrage ne relance pas la montée en silence et ne transforme pas un appui d'abandon en une heure de plus. Des paliers modifiés sous un créneau en cours le replacent par sa durée et non par son indice, un indice stocké voulant dire autre chose dès que les paliers bougent. durationMs est aligné sur le premier palier à l'écriture : deux endroits prétendant dire ce que fait le premier appui, c'est ainsi qu'ils finissent par se contredire. Tout ce qui n'a pas de paliers garde exactement la règle 3 de la spec 174. Voir specs/178-timed-action-duration-steps/. |
| 179 | Un compteur alimenté par un autre réseau | ✅ | La spec 173 déclarait une topologie que l'arithmétique de réconciliation ne voyait pas — un compteur à l'intérieur d'un autre. Voici l'autre : une pince sur un circuit alimenté par un second compteur du fournisseur (le cas qui l'a soulevée : une prise de recharge VE sur un autre abonnement). L'enrôlement étant une liste noire (#523), la pince entre dans toutes les réconciliations contre le compteur principal, et trois chiffres se faussent d'un coup : la répartition affiche une part de 3 kW que le total principal n'a jamais portée, le résidu « Autre » est écrasé à 0, et la spec 123 facture au tarif principal les kilowattheures d'un autre réseau. Même principe de conception que la 173 — déclarer ce qui est vrai du tableau électrique, pas une case « masquer » : Equipment.separateSupply dit que le compteur pend d'un autre réseau, et les deux surfaces (répartition par usage et donut en direct spec 117) l'affichent à part — son propre groupe, séries brutes, en kWh seulement, jamais en € — tandis que sa carte, son historique et ses graphiques ne bougent pas. Refusé sur le compteur principal et les types de production (la référence ne peut pas être hors d'elle-même), et un compteur sur alimentation séparée ne peut pas être parent spec 173 — rien de ce que la répartition affiche ne peut être « dans » un compteur d'un autre réseau ; une déclaration d'imbrication qui pointe dessus est conservée mais simplement inutilisée, si bien que retirer le drapeau restaure la soustraction telle quelle. L'agrégation de zone (spec 170) reste volontairement brute : le garage tire réellement ces watts, quel que soit le compteur qui les facture. Voir specs/179-separate-supply-meter/. |
Comment utiliser cet index après une perte de contexte¶
- Trouvez le thème dont vous avez besoin via les en-têtes de section ci-dessus
- Ouvrez
specs/XXX-name/spec.mdpour les exigences et critères d'acceptation - Ouvrez
specs/XXX-name/architecture.mdpour le design technique, les changements de modèle de données, l'impact au niveau fichier - Ouvrez
specs/XXX-name/plan.mdpour les étapes d'implémentation
Pour l'architecture actuelle basée sur les plugins, commencez par la spec 053 (PackageManager), c'est la racine de tout ce qui touche aux plugins.
Pour l'auto-update, commencez par la spec 060, elle remplace la spec 057 et est le design actuel.
Pour la vue d'ensemble du système, voir technical/architecture.md.
Pour l'exploitation production (déploiement, backup, auto-update, logs), voir technical/deployment.md.