Sowel : Modèle de données¶
Version : 1.0, 2026-02-19
Ce document est la référence du modèle de données central de Sowel. Il décrit l'architecture en trois couches (Topologie -> Fonctionnel -> Physique), toutes les entités, leurs relations et les règles d'agrégation.
1. Architecture en trois couches¶
Sowel sépare les responsabilités en trois couches distinctes :
+-------------------------------------------------------------+
| LAYER 1 -- TOPOLOGY (Zones) |
| Spatial structure of the home |
| Hierarchical: Home -> Floor -> Room |
| Aggregates data automatically from child Equipments |
+-------------------------------------------------------------+
| LAYER 2 -- FUNCTIONAL (Equipments + Groups) |
| What the user sees and controls |
| Placed IN a Zone, optionally IN a Group |
| Binds to one or more physical Devices |
+-------------------------------------------------------------+
| LAYER 3 -- PHYSICAL (Devices) |
| Hardware discovered from integrations |
| Auto-discovered, raw data and commands |
| Never directly manipulated by the end user |
+-------------------------------------------------------------+
Principe directeur : un Device est ce qui est sur le réseau. Un Equipment est ce qui est dans la pièce.
2. Diagramme entité-relation¶
Zone (hierarchy: parent -> children)
|
+-- EquipmentGroup (optional functional grouping)
| +-- Equipment*
|
+-- Equipment (functional unit, user-facing)
+-- DataBinding --> DeviceData (on a Device)
+-- OrderBinding --> DeviceOrder (on a Device)
+-- [V0.5] ComputedData (expression-based virtual data)
Device (physical, auto-discovered)
+-- DeviceData (readable properties: temperature, state, brightness...)
+-- DeviceOrder (writable commands: set brightness, turn on...)
3. Zone¶
Une Zone représente une aire spatiale dans la maison. Les zones forment une hiérarchie en arbre.
3.1 Interface¶
interface Zone {
id: string; // UUID v4
name: string; // "Cuisine", "Etage 1", "Maison"
parentId: string | null; // null = root zone
icon?: string; // Lucide icon name: "home", "sofa", "bed"
description?: string; // "Piece principale, 35m2"
displayOrder: number; // Sort order among siblings (0-based)
createdAt: string; // ISO 8601
updatedAt: string; // ISO 8601
}
3.2 Hiérarchie¶
Les zones sont imbriquables sur n'importe quelle profondeur. Structure typique :
Maison (root, parentId: null)
+-- RDC (floor, parentId: Maison)
| +-- Cuisine (room, parentId: RDC)
| +-- Cuisine (room, parentId: RDC)
| +-- Entree (room, parentId: RDC)
| +-- WC (room, parentId: RDC)
+-- Etage (floor, parentId: Maison)
| +-- Chambre Parentale (room, parentId: Etage)
| +-- Chambre Enfant (room, parentId: Etage)
| +-- Salle de Bain (room, parentId: Etage)
| +-- Couloir (room, parentId: Etage)
+-- Exterieur (area, parentId: Maison)
+-- Jardin (area, parentId: Exterieur)
+-- Garage (area, parentId: Exterieur)
3.3 Données agrégées de zone¶
Le moteur calcule automatiquement les données agrégées de chaque Zone à partir des Equipments qu'elle contient. Aucune configuration manuelle requise, c'est une fonctionnalité centrale.
L'agrégation est récursive : une Zone parent agrège ses propres Equipments plus toutes les Zones enfants.
| Attribute | Type | Règle d'agrégation | Source (DataCategory) | Description |
|---|---|---|---|---|
temperature |
number | null | AVG | temperature |
Température moyenne de la zone |
humidity |
number | null | AVG | humidity |
Humidité moyenne |
pressure |
number | null | AVG | pressure |
Pression atmosphérique moyenne |
luminosity |
number | null | AVG | luminosity |
Luminosité moyenne (lux) |
co2 |
number | null | AVG | co2 |
Niveau de CO2 moyen (ppm) |
voc |
number | null | AVG | voc |
Niveau de COV moyen (ppb) |
motion |
boolean | OR | motion |
true si AU MOINS UN capteur de mouvement détecte du mouvement |
presence |
boolean | OR + timeout | motion |
true si du mouvement détecté dans un timeout configurable |
openDoors |
number | COUNT (open) | contact_door |
Nombre de contacts de porte ouverts |
openWindows |
number | COUNT (open) | contact_window |
Nombre de contacts de fenêtre ouverts |
waterLeak |
boolean | OR | water_leak |
true si AU MOINS UN capteur de fuite d'eau se déclenche |
smoke |
boolean | OR | smoke |
true si AU MOINS UN détecteur de fumée se déclenche |
lightsOn |
number | COUNT (on) | light_state |
Nombre de lumières allumées |
lightsTotal |
number | COUNT (all) | light_state |
Nombre total d'équipements lumière |
averageBrightness |
number | null | AVG (on only) | light_brightness |
Luminosité moyenne des lumières allumées |
shuttersOpen |
number | COUNT (open) | shutter_position |
Nombre de volets ouverts |
shuttersTotal |
number | COUNT (all) | shutter_position |
Nombre total de volets |
averageShutterPosition |
number | null | AVG | shutter_position |
Position moyenne des volets (%) |
totalPower |
number | SUM | power |
Puissance instantanée totale (W) |
totalEnergy |
number | SUM | energy |
Consommation d'énergie totale (kWh) |
heatingActive |
boolean | OR | thermostat equipments | true si un thermostat chauffe activement |
targetTemperature |
number | null | AVG | thermostat equipments | Consigne de température cible moyenne |
Note : cette liste évoluera. De nouveaux attributs agrégés peuvent être ajoutés à mesure que de nouveaux types d'Equipment et DataCategories sont introduits.
3.4 Auto-ordres de zone¶
Les zones exposent des commandes en lot qui agissent sur tous les Equipments de la zone (et des zones enfants récursivement) :
| Order | Effet |
|---|---|
allOff |
Éteint TOUS les Equipments contrôlables de la Zone |
allLightsOff |
Éteint tous les Equipments de type lumière |
allLightsOn |
Allume tous les Equipments de type lumière |
allShuttersOpen |
Ouvre tous les volets |
allShuttersClose |
Ferme tous les volets |
3.5 Schéma SQLite¶
CREATE TABLE zones (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
parent_id TEXT REFERENCES zones(id) ON DELETE SET NULL,
icon TEXT,
description TEXT,
display_order INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
4. Equipment Group¶
Un EquipmentGroup est un regroupement fonctionnel d'Equipments au sein d'une Zone. Il permet de contrôler et de surveiller un sous-ensemble d'équipements ensemble.
4.1 Interface¶
interface EquipmentGroup {
id: string; // UUID v4
name: string; // "Volets Sud", "Eclairage Ambiance"
zoneId: string; // FK -> Zone (a group belongs to exactly one zone)
icon?: string; // Lucide icon name
description?: string;
displayOrder: number; // Sort order within the zone
createdAt: string; // ISO 8601
updatedAt: string; // ISO 8601
}
4.2 Objectif et exemples¶
Cuisine (Zone)
+-- Group "Volets Sud"
| +-- Volet Baie Vitree (Equipment: shutter)
| +-- Volet Porte Fenetre (Equipment: shutter)
+-- Group "Volets Nord"
| +-- Volet Fenetre Nord (Equipment: shutter)
+-- Group "Eclairage Ambiance"
| +-- Spots Plafond (Equipment: dimmer)
| +-- Lampe Canape (Equipment: dimmer)
+-- Detection Cuisine (Equipment: motion_sensor, no group)
+-- Temperature Cuisine (Equipment: sensor, no group)
Comportements clés :
- Un Equipment appartient à au plus un Group (optionnel, via
groupId) - Un Group appartient à exactement une Zone
- Les Groups ont leurs propres données agrégées (mêmes règles que les Zones, périmètre = membres du groupe)
- Les Groups peuvent recevoir des ordres en lot (par ex., "fermer tous les volets de Volets Sud")
4.3 Données agrégées de groupe¶
Les Groups calculent les données agrégées avec les mêmes règles que les Zones (section 3.3), mais limitées aux Equipments membres du groupe. Cela permet :
- "Position moyenne des volets de Volets Sud" vs "Position moyenne des volets de Volets Nord"
- "Nombre de lumières allumées dans Eclairage Ambiance" vs comptage à l'échelle de la zone
4.4 Schéma SQLite¶
CREATE TABLE equipment_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE,
icon TEXT,
description TEXT,
display_order INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
5. Equipment¶
Un Equipment est l'unité fonctionnelle visible par l'utilisateur. C'est l'entité primaire avec laquelle l'utilisateur interagit dans l'UI, les scénarios et les commandes vocales.
5.1 Interface¶
type EquipmentType =
| "light" // on/off light
| "dimmer" // dimmable light
| "color_light" // color-capable light
| "shutter" // cover, blind, shutter
| "thermostat" // heating/cooling control
| "lock" // door lock
| "alarm" // alarm system
| "sensor" // generic sensor (temp, humidity...)
| "motion_sensor" // motion detector
| "contact_sensor" // door/window contact
| "media_player" // media device
| "camera" // surveillance camera
| "switch" // on/off switch or plug
| "water_valve" // smart irrigation valve (toggle + timed watering)
| "generic"; // anything else
interface Equipment {
id: string; // UUID v4
name: string; // "Spots Cuisine", "Volet Baie Vitree"
zoneId: string; // FK -> Zone (where the equipment functions)
groupId: string | null; // FK -> EquipmentGroup (optional)
type: EquipmentType; // Semantic type, drives UI rendering & aggregation
icon?: string; // Lucide icon name (overrides type default)
description?: string;
enabled: boolean; // Disabled equipments are ignored by the engine
createdAt: string; // ISO 8601
updatedAt: string; // ISO 8601
}
5.2 Equipment vs Device¶
| Device | Equipment | |
|---|---|---|
| Nature | Matériel physique | Abstraction fonctionnelle |
| Découverte | Auto-découvert depuis les intégrations | Créé manuellement par l'utilisateur |
| Identité | ID spécifique à l'intégration | Nom choisi par l'utilisateur |
| Localisation | Où il est installé physiquement | Où il est utilisé fonctionnellement |
| Cardinalité | 1 Device -> N Equipments possible | 1 Equipment -> N Devices possible |
| Interaction user | Jamais (couche technique) | Toujours (interface principale) |
Exemples :
- 1 Device -> 1 Equipment : capteur de température Aqara -> "Temperature Cuisine"
- 1 Device -> N Equipments : module double relais -> "Lumiere Cuisine" + "Lumiere Cellier"
- N Devices -> 1 Equipment : 3 capteurs PIR -> "Detection Cuisine" (via computed data, V0.5)
6. Data Binding¶
Un DataBinding mappe une propriété Device Data vers un alias au niveau Equipment.
6.1 Interface¶
interface DataBinding {
id: string; // UUID v4
equipmentId: string; // FK -> Equipment
deviceDataId: string; // FK -> DeviceData
alias: string; // Equipment-level name: "state", "brightness", "temperature"
}
6.2 Comment ça marche¶
Device "Variateur #1"
+-- DeviceData: key="state", value="ON" <--+
+-- DeviceData: key="brightness", value=180 <---+-- DataBinding
+-- DeviceData: key="linkquality", value=85 |
|
Equipment "Spots Cuisine" |
+-- Data alias "state" ----------------------------+ (bound to DeviceData "state")
+-- Data alias "brightness" ----------------------- (bound to DeviceData "brightness")
+-- [not bound to linkquality -- it's a technical metric, not user-facing]
6.3 Contraintes¶
UNIQUE(equipment_id, alias), chaque alias est unique par Equipment- Quand le DeviceData change, l'alias lié de l'Equipment reflète la nouvelle valeur immédiatement
- L'alias est utilisé dans les expressions, l'affichage UI, l'agrégation de zone et les conditions de Scenario
6.4 Schéma SQLite¶
CREATE TABLE data_bindings (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
device_data_id TEXT NOT NULL REFERENCES device_data(id) ON DELETE CASCADE,
alias TEXT NOT NULL,
UNIQUE(equipment_id, alias)
);
7. Order Binding¶
Un OrderBinding mappe un Device Order vers un alias de commande au niveau Equipment.
7.1 Interface¶
interface OrderBinding {
id: string; // UUID v4
equipmentId: string; // FK -> Equipment
deviceOrderId: string; // FK -> DeviceOrder
alias: string; // Equipment-level command: "turn_on", "set_brightness"
}
7.2 Comment ça marche¶
Quand un Equipment Order est exécuté :
User clicks "Turn On" on Equipment "Spots Cuisine"
-> API: POST /equipments/:id/orders/turn_on { value: true }
-> Equipment Manager finds OrderBinding alias="turn_on"
-> Resolves to DeviceOrder
-> Integration Plugin dispatches command to device
7.3 Dispatch multi-devices¶
Un Equipment peut avoir plusieurs OrderBindings avec le même alias pointant vers des Devices différents. Cela permet de contrôler plusieurs devices avec une seule commande :
Equipment "Eclairage Cuisine"
+-- OrderBinding: alias="turn_on" -> DeviceOrder on Relais #1
+-- OrderBinding: alias="turn_on" -> DeviceOrder on Relais #2
L'exécution de turn_on dispatche vers les DEUX relais en parallèle.
Note sur la contrainte du schéma : pour le dispatch multi-devices, la contrainte UNIQUE est sur (equipment_id, alias, device_order_id), pas seulement (equipment_id, alias).
7.4 Schéma SQLite¶
CREATE TABLE order_bindings (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
device_order_id TEXT NOT NULL REFERENCES device_orders(id) ON DELETE CASCADE,
alias TEXT NOT NULL,
UNIQUE(equipment_id, alias, device_order_id)
);
8. Device (Couche 3, physique)¶
Les Devices sont auto-découverts depuis les intégrations configurées (Zigbee2MQTT, Panasonic CC, MCZ Maestro, Netatmo HC, etc.). Ils sont documentés ici par souci de complétude.
8.1 Interface¶
interface Device {
id: string; // UUID v4
mqttBaseTopic: string; // Integration-specific topic or identifier
mqttName: string; // Integration-specific name or ID
name: string; // User-editable display name
manufacturer?: string; // "Aqara", "IKEA", "Panasonic", "MCZ"
model?: string; // "MCCGQ11LM", "CS-Z25VKEW", etc.
ieeeAddress?: string; // Hardware address (Zigbee IEEE, serial, etc.)
source: DeviceSource; // "zigbee2mqtt" | "panasonic_cc" | "mcz_maestro" | "netatmo_hc" | ...
status: DeviceStatus; // "online" | "offline" | "unknown"
lastSeen: string | null; // ISO 8601
rawExpose?: unknown; // Raw integration-specific metadata
createdAt: string;
updatedAt: string;
}
8.2 DeviceData¶
interface DeviceData {
id: string;
deviceId: string; // FK -> Device
key: string; // Property name: "temperature", "state", "brightness"
type: DataType; // "boolean" | "number" | "enum" | "text" | "json"
category: DataCategory; // Semantic category for aggregation rules
value: unknown; // Current value
unit?: string; // "C", "%", "lx", "W"
lastUpdated: string | null;
}
8.3 DeviceOrder¶
interface DeviceOrder {
id: string;
deviceId: string; // FK -> Device
key: string; // "state", "brightness", "position"
type: DataType;
mqttSetTopic: string; // MQTT topic to publish to
payloadKey: string; // Key in the JSON payload
min?: number; // For numeric: minimum value
max?: number; // For numeric: maximum value
enumValues?: string[]; // For enum: allowed values
unit?: string;
}
9. Computed Data (V0.5)¶
Différé en V0.5, documenté ici dans le cadre du modèle de données complet.
Une ComputedData est un point de donnée virtuel sur un Equipment dont la valeur est dérivée d'une expression sur d'autres sources de données.
9.1 Interface¶
interface ComputedData {
id: string; // UUID v4
equipmentId: string; // FK -> Equipment
key: string; // "state", "average_temperature", "motion"
type: DataType;
category: DataCategory; // Used by Zone aggregation
expression: string; // Computation expression
value: unknown; // Current computed value
}
9.2 Langage d'expression¶
// Boolean
OR(binding.motion_1, binding.motion_2)
AND(binding.door, binding.window)
NOT(binding.occupancy)
// Numeric
AVG(binding.temp_1, binding.temp_2)
MIN(binding.temp_1, binding.temp_2)
MAX(binding.temp_1, binding.temp_2)
SUM(binding.power_1, binding.power_2)
// Conditional
IF(binding.brightness > 0, "on", "off")
THRESHOLD(binding.temperature, 19, "cold", "ok")
// References
binding.<alias> -> DataBinding on the same Equipment
equipment.<equipmentId>.<alias> -> Data on another Equipment
zone.<zoneId>.<key> -> Zone aggregated Data
10. Flux de données réactif¶
Le pipeline complet piloté par les événements :
Integration event (MQTT message, cloud API poll, etc.)
|
v
Integration Plugin (receives + parses)
|
v
Device Manager (updates DeviceData)
|
+--> Event: "device.data.updated"
|
v
Equipment Manager
+-- Updates bound Equipment Data (via DataBindings)
+-- [V0.5] Re-evaluates ComputedData expressions
|
+--> Event: "equipment.data.changed"
|
v
Zone Aggregator
+-- Re-computes Zone aggregated data
+-- Re-computes Group aggregated data
+-- Propagates up the zone hierarchy (recursive)
|
+--> Event: "zone.data.changed"
|
v
Scenario Engine (V0.7)
+-- Evaluates triggers
+-- Checks conditions
+-- Executes actions
|
+--> Actions may dispatch Equipment/Zone Orders -> Integration Plugin -> device
|
v
WebSocket Server
+-- Broadcasts all events to connected UI clients
11. Événements de l'Event Bus¶
Tous les événements sont typés via les unions discriminées TypeScript.
Événements système¶
| Event | Payload | Quand |
|---|---|---|
system.started |
-- | Démarrage moteur terminé |
system.mqtt.connected |
-- | Broker MQTT connecté |
system.mqtt.disconnected |
-- | Broker MQTT perdu |
system.error |
error: string |
Erreur non récupérable |
Événements Device (V0.1)¶
| Event | Payload | Quand |
|---|---|---|
device.discovered |
device: Device |
Nouveau device trouvé |
device.removed |
deviceId, deviceName |
Device supprimé |
device.status_changed |
deviceId, deviceName, status |
Online/offline |
device.data.updated |
deviceId, deviceName, dataId, key, value, previous |
Changement de propriété |
Événements Equipment (V0.3)¶
| Event | Payload | Quand |
|---|---|---|
equipment.data.changed |
equipmentId, key, value, previous |
Donnée liée modifiée |
equipment.order.executed |
equipmentId, orderAlias, value |
Ordre dispatché |
Événements Zone (V0.3+)¶
| Event | Payload | Quand |
|---|---|---|
zone.data.changed |
zoneId, key, value, previous |
Donnée agrégée modifiée |
12. Schéma SQLite complet¶
-- ============================================================
-- ZONES (V0.2)
-- ============================================================
CREATE TABLE zones (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
parent_id TEXT REFERENCES zones(id) ON DELETE SET NULL,
icon TEXT,
description TEXT,
display_order INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================
-- EQUIPMENT GROUPS (V0.2)
-- ============================================================
CREATE TABLE equipment_groups (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE,
icon TEXT,
description TEXT,
display_order INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================
-- DEVICES (V0.1 -- existing)
-- ============================================================
CREATE TABLE devices (
id TEXT PRIMARY KEY,
mqtt_base_topic TEXT NOT NULL UNIQUE,
mqtt_name TEXT NOT NULL,
name TEXT NOT NULL,
manufacturer TEXT,
model TEXT,
ieee_address TEXT,
source TEXT NOT NULL, -- integration source: 'zigbee2mqtt', 'panasonic_cc', 'mcz_maestro', 'netatmo_hc', ...
status TEXT NOT NULL DEFAULT 'unknown',
last_seen DATETIME,
raw_expose JSON,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE device_data (
id TEXT PRIMARY KEY,
device_id TEXT NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
key TEXT NOT NULL,
type TEXT NOT NULL,
category TEXT NOT NULL DEFAULT 'generic',
value TEXT,
unit TEXT,
last_updated DATETIME,
UNIQUE(device_id, key)
);
CREATE TABLE device_orders (
id TEXT PRIMARY KEY,
device_id TEXT NOT NULL REFERENCES devices(id) ON DELETE CASCADE,
key TEXT NOT NULL,
type TEXT NOT NULL,
mqtt_set_topic TEXT NOT NULL,
payload_key TEXT NOT NULL,
min_value REAL,
max_value REAL,
enum_values JSON,
unit TEXT,
UNIQUE(device_id, key)
);
-- ============================================================
-- EQUIPMENTS (V0.3)
-- ============================================================
CREATE TABLE equipments (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
zone_id TEXT NOT NULL REFERENCES zones(id) ON DELETE CASCADE,
group_id TEXT REFERENCES equipment_groups(id) ON DELETE SET NULL,
type TEXT NOT NULL DEFAULT 'generic',
icon TEXT,
description TEXT,
enabled INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE data_bindings (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
device_data_id TEXT NOT NULL REFERENCES device_data(id) ON DELETE CASCADE,
alias TEXT NOT NULL,
UNIQUE(equipment_id, alias)
);
CREATE TABLE order_bindings (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
device_order_id TEXT NOT NULL REFERENCES device_orders(id) ON DELETE CASCADE,
alias TEXT NOT NULL,
UNIQUE(equipment_id, alias, device_order_id)
);
-- ============================================================
-- COMPUTED DATA (V0.5)
-- ============================================================
CREATE TABLE computed_data (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
key TEXT NOT NULL,
type TEXT NOT NULL,
category TEXT NOT NULL DEFAULT 'generic',
expression TEXT NOT NULL,
value TEXT,
UNIQUE(equipment_id, key)
);
-- ============================================================
-- INTERNAL RULES (V0.5)
-- ============================================================
CREATE TABLE internal_rules (
id TEXT PRIMARY KEY,
equipment_id TEXT NOT NULL REFERENCES equipments(id) ON DELETE CASCADE,
name TEXT NOT NULL,
condition_expr TEXT NOT NULL,
action_expr TEXT NOT NULL,
enabled INTEGER DEFAULT 1
);
-- ============================================================
-- RECIPES (V0.8)
-- ============================================================
CREATE TABLE recipe_instances (
id TEXT PRIMARY KEY,
recipe_id TEXT NOT NULL,
params JSON NOT NULL DEFAULT '{}',
enabled INTEGER DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE recipe_state (
instance_id TEXT NOT NULL REFERENCES recipe_instances(id) ON DELETE CASCADE,
key TEXT NOT NULL,
value TEXT,
PRIMARY KEY (instance_id, key)
);
CREATE TABLE recipe_log (
id TEXT PRIMARY KEY,
instance_id TEXT NOT NULL REFERENCES recipe_instances(id) ON DELETE CASCADE,
level TEXT NOT NULL DEFAULT 'info',
message TEXT NOT NULL,
data JSON,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================
-- USERS & AUTH
-- ============================================================
CREATE TABLE users (
id TEXT PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
display_name TEXT NOT NULL,
password_hash TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'standard',
preferences JSON DEFAULT '{}',
enabled INTEGER DEFAULT 1,
last_login_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE api_tokens (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
name TEXT NOT NULL,
token_hash TEXT NOT NULL,
last_used_at DATETIME,
expires_at DATETIME,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE refresh_tokens (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token_hash TEXT NOT NULL,
expires_at DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
-- ============================================================
-- SETTINGS (key-value store for integration config)
-- ============================================================
CREATE TABLE settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
13. Récapitulatif des endpoints API¶
Zones (V0.2)¶
| Method | Route | Description |
|---|---|---|
| GET | /api/v1/zones |
Liste toutes les zones (structure arborescente) |
| GET | /api/v1/zones/:id |
Récupère une zone avec données agrégées |
| POST | /api/v1/zones |
Crée une zone |
| PUT | /api/v1/zones/:id |
Met à jour une zone |
| DELETE | /api/v1/zones/:id |
Supprime une zone (sans enfants ni équipements liés) |
Equipment Groups (V0.2)¶
| Method | Route | Description |
|---|---|---|
| GET | /api/v1/zones/:zoneId/groups |
Liste les groupes d'une zone |
| POST | /api/v1/zones/:zoneId/groups |
Crée un groupe dans une zone |
| PUT | /api/v1/groups/:id |
Met à jour un groupe |
| DELETE | /api/v1/groups/:id |
Supprime un groupe |
Equipments (V0.3)¶
| Method | Route | Description |
|---|---|---|
| GET | /api/v1/equipments |
Liste tous les équipements |
| GET | /api/v1/equipments/:id |
Récupère un équipement avec liaisons et données courantes |
| POST | /api/v1/equipments |
Crée un équipement |
| PUT | /api/v1/equipments/:id |
Met à jour un équipement |
| DELETE | /api/v1/equipments/:id |
Supprime un équipement |
| POST | /api/v1/equipments/:id/orders/:alias |
Exécute un ordre d'équipement |
Zone Orders (V0.3+)¶
| Method | Route | Description |
|---|---|---|
| POST | /api/v1/zones/:id/orders/:orderKey |
Exécute un auto-ordre de zone (allOff, allLightsOff, ...) |
| POST | /api/v1/groups/:id/orders/:orderKey |
Exécute un ordre de groupe |
Pour la référence complète de l'API, voir Référence API.
14. Roadmap d'implémentation¶
| Version | Entités implémentées |
|---|---|
| V0.1 | Device, DeviceData, DeviceOrder |
| V0.2 | Zone, EquipmentGroup (CRUD + UI) |
| V0.3 | Equipment, DataBinding, OrderBinding (CRUD + exécution d'ordres + UI) |
| V0.5 | ComputedData, InternalRule |
| V0.3+ | Moteur d'agrégation de zone, auto-ordres de zone |