# 🏠 Spécifications Home Assistant pour IPWatch MQTT Ce document définit les spécifications pour intégrer les équipements IPWatch dans Home Assistant via MQTT Discovery. ## 1. Vue d'ensemble L'intégration Home Assistant permet de : - **Détecter automatiquement** les équipements IPWatch via MQTT Discovery - **Visualiser** l'état des équipements (online/offline) - **Contrôler** les équipements (shutdown, reboot) - **Monitorer** les métriques système (CPU, RAM, Disk, Uptime) - **Créer des automatisations** basées sur l'état des équipements ## 2. MQTT Discovery ### 2.1 Principe MQTT Discovery permet à Home Assistant de détecter automatiquement les entités sans configuration manuelle. **Topic de découverte** : `homeassistant/{component}/ipwatch_{unique_id}/{object_id}/config` **Composants supportés** : - `sensor` : Métriques système - `binary_sensor` : État de disponibilité - `button` : Actions (shutdown, reboot) ### 2.2 Configuration Discovery pour Sensor L'agent MQTT publie automatiquement sa configuration au démarrage : **Topic** : `homeassistant/sensor/ipwatch_10_0_0_100/system/config` **Payload** : ```json { "name": "Server 01 - Système", "unique_id": "ipwatch_10_0_0_100_system", "state_topic": "ipwatch/device/10.0.0.100/status", "value_template": "{{ value_json.hostname }}", "json_attributes_topic": "ipwatch/device/10.0.0.100/status", "availability": { "topic": "ipwatch/device/10.0.0.100/availability", "payload_available": "online", "payload_not_available": "offline" }, "device": { "identifiers": ["ipwatch_10_0_0_100"], "name": "Server 01", "model": "IPWatch MQTT Agent v1.0", "manufacturer": "IPWatch", "sw_version": "1.0.0" }, "icon": "mdi:desktop-tower", "qos": 1 } ``` ### 2.3 Configuration Discovery pour Binary Sensor (Availability) **Topic** : `homeassistant/binary_sensor/ipwatch_10_0_0_100/availability/config` **Payload** : ```json { "name": "Server 01 - Disponibilité", "unique_id": "ipwatch_10_0_0_100_availability", "state_topic": "ipwatch/device/10.0.0.100/availability", "payload_on": "online", "payload_off": "offline", "device_class": "connectivity", "device": { "identifiers": ["ipwatch_10_0_0_100"], "name": "Server 01" }, "icon": "mdi:lan-connect", "qos": 1 } ``` ### 2.4 Configuration Discovery pour Buttons **Shutdown Button** : **Topic** : `homeassistant/button/ipwatch_10_0_0_100/shutdown/config` **Payload** : ```json { "name": "Server 01 - Shutdown", "unique_id": "ipwatch_10_0_0_100_shutdown", "command_topic": "ipwatch/device/10.0.0.100/command", "payload_press": "{\"command\":\"shutdown\",\"timestamp\":\"{{ now().isoformat() }}\"}", "availability": { "topic": "ipwatch/device/10.0.0.100/availability", "payload_available": "online", "payload_not_available": "offline" }, "device": { "identifiers": ["ipwatch_10_0_0_100"], "name": "Server 01" }, "icon": "mdi:power-off", "qos": 1 } ``` **Reboot Button** : **Topic** : `homeassistant/button/ipwatch_10_0_0_100/reboot/config` **Payload** : ```json { "name": "Server 01 - Reboot", "unique_id": "ipwatch_10_0_0_100_reboot", "command_topic": "ipwatch/device/10.0.0.100/command", "payload_press": "{\"command\":\"reboot\",\"timestamp\":\"{{ now().isoformat() }}\"}", "availability": { "topic": "ipwatch/device/10.0.0.100/availability", "payload_available": "online", "payload_not_available": "offline" }, "device": { "identifiers": ["ipwatch_10_0_0_100"], "name": "Server 01" }, "icon": "mdi:restart", "qos": 1 } ``` ## 3. Entités Créées dans Home Assistant ### 3.1 Sensors (Métriques Système) Chaque équipement IPWatch crée automatiquement ces sensors : | Entity ID | Nom | Description | Attribut JSON | |-----------|-----|-------------|---------------| | `sensor.server_01_systeme` | Server 01 - Système | État général | Tous les attributs | | `sensor.server_01_cpu` | Server 01 - CPU | Usage CPU | `cpu_percent` | | `sensor.server_01_memory` | Server 01 - RAM | Usage mémoire | `memory_percent` | | `sensor.server_01_disk` | Server 01 - Disk | Usage disque | `disk_percent` | | `sensor.server_01_uptime` | Server 01 - Uptime | Temps de fonctionnement | `uptime` | **Exemple de valeur du sensor système** : ```json { "hostname": "server-01", "ip": "10.0.0.100", "platform": "Linux", "platform_version": "5.15.0-91-generic", "uptime": 86400, "cpu_percent": 45.2, "memory_percent": 62.5, "disk_percent": 78.3, "timestamp": "2025-12-23T10:30:00Z" } ``` ### 3.2 Binary Sensors | Entity ID | Nom | État | Icon | |-----------|-----|------|------| | `binary_sensor.server_01_disponibilite` | Server 01 - Disponibilité | on/off | `mdi:lan-connect` | ### 3.3 Buttons | Entity ID | Nom | Action | Icon | |-----------|-----|--------|------| | `button.server_01_shutdown` | Server 01 - Shutdown | Éteindre | `mdi:power-off` | | `button.server_01_reboot` | Server 01 - Reboot | Redémarrer | `mdi:restart` | ## 4. Configuration Home Assistant ### 4.1 Configuration MQTT Dans `configuration.yaml` : ```yaml # Configuration MQTT mqtt: broker: localhost port: 1883 username: !secret mqtt_username password: !secret mqtt_password discovery: true discovery_prefix: homeassistant birth_message: topic: 'homeassistant/status' payload: 'online' will_message: topic: 'homeassistant/status' payload: 'offline' ``` ### 4.2 Secrets Dans `secrets.yaml` : ```yaml mqtt_username: ipwatch mqtt_password: VotreMotDePasse ``` ### 4.3 Templates pour Sensors Individuels (Optionnel) Si vous souhaitez créer des sensors séparés pour chaque métrique : ```yaml # Sensor CPU mqtt: - sensor: name: "Server 01 CPU" unique_id: ipwatch_10_0_0_100_cpu state_topic: "ipwatch/device/10.0.0.100/status" value_template: "{{ value_json.cpu_percent }}" unit_of_measurement: "%" icon: mdi:cpu-64-bit availability: topic: "ipwatch/device/10.0.0.100/availability" payload_available: "online" payload_not_available: "offline" device: identifiers: ["ipwatch_10_0_0_100"] name: "Server 01" # Sensor RAM - sensor: name: "Server 01 Memory" unique_id: ipwatch_10_0_0_100_memory state_topic: "ipwatch/device/10.0.0.100/status" value_template: "{{ value_json.memory_percent }}" unit_of_measurement: "%" icon: mdi:memory availability: topic: "ipwatch/device/10.0.0.100/availability" device: identifiers: ["ipwatch_10_0_0_100"] # Sensor Disk - sensor: name: "Server 01 Disk" unique_id: ipwatch_10_0_0_100_disk state_topic: "ipwatch/device/10.0.0.100/status" value_template: "{{ value_json.disk_percent }}" unit_of_measurement: "%" icon: mdi:harddisk availability: topic: "ipwatch/device/10.0.0.100/availability" device: identifiers: ["ipwatch_10_0_0_100"] # Sensor Uptime - sensor: name: "Server 01 Uptime" unique_id: ipwatch_10_0_0_100_uptime state_topic: "ipwatch/device/10.0.0.100/status" value_template: "{{ (value_json.uptime / 3600) | round(1) }}" unit_of_measurement: "h" icon: mdi:clock-outline availability: topic: "ipwatch/device/10.0.0.100/availability" device: identifiers: ["ipwatch_10_0_0_100"] ``` ## 5. Lovelace UI Cards ### 5.1 Entity Card (Simple) ```yaml type: entities title: Server 01 entities: - entity: binary_sensor.server_01_disponibilite name: Disponibilité - entity: sensor.server_01_cpu name: CPU - entity: sensor.server_01_memory name: RAM - entity: sensor.server_01_disk name: Disque - entity: sensor.server_01_uptime name: Uptime - entity: button.server_01_shutdown name: Éteindre - entity: button.server_01_reboot name: Redémarrer ``` ### 5.2 Glance Card (Compact) ```yaml type: glance title: Server 01 entities: - entity: binary_sensor.server_01_disponibilite name: État - entity: sensor.server_01_cpu name: CPU - entity: sensor.server_01_memory name: RAM - entity: sensor.server_01_disk name: Disque ``` ### 5.3 Gauge Card (Métriques visuelles) ```yaml type: vertical-stack cards: - type: gauge entity: sensor.server_01_cpu name: CPU min: 0 max: 100 severity: green: 0 yellow: 60 red: 80 - type: gauge entity: sensor.server_01_memory name: RAM min: 0 max: 100 severity: green: 0 yellow: 70 red: 90 - type: gauge entity: sensor.server_01_disk name: Disque min: 0 max: 100 severity: green: 0 yellow: 80 red: 95 ``` ### 5.4 Custom Card (Markdown) ```yaml type: markdown content: | ## 🖥️ Server 01 **État** : {{ states('binary_sensor.server_01_disponibilite') }} **CPU** : {{ states('sensor.server_01_cpu') }}% **RAM** : {{ states('sensor.server_01_memory') }}% **Disque** : {{ states('sensor.server_01_disk') }}% **Uptime** : {{ states('sensor.server_01_uptime') }}h {% if is_state('binary_sensor.server_01_disponibilite', 'on') %} ✅ Serveur en ligne {% else %} ❌ Serveur hors ligne {% endif %} ``` ### 5.5 Button Card (Actions rapides) ```yaml type: horizontal-stack cards: - type: button entity: button.server_01_shutdown name: Éteindre icon: mdi:power-off tap_action: action: call-service service: button.press service_data: entity_id: button.server_01_shutdown hold_action: action: none - type: button entity: button.server_01_reboot name: Redémarrer icon: mdi:restart tap_action: action: call-service service: button.press service_data: entity_id: button.server_01_reboot ``` ## 6. Automatisations ### 6.1 Alerte si serveur offline ```yaml alias: "Alert - Server 01 Offline" description: Notification si serveur hors ligne trigger: - platform: state entity_id: binary_sensor.server_01_disponibilite to: "off" for: minutes: 5 action: - service: notify.mobile_app data: title: "⚠️ Serveur Offline" message: "Server 01 (10.0.0.100) est hors ligne depuis 5 minutes" data: priority: high mode: single ``` ### 6.2 Alerte CPU élevé ```yaml alias: "Alert - Server 01 High CPU" description: Notification si CPU > 90% trigger: - platform: numeric_state entity_id: sensor.server_01_cpu above: 90 for: minutes: 10 condition: - condition: state entity_id: binary_sensor.server_01_disponibilite state: "on" action: - service: notify.mobile_app data: title: "🔥 CPU élevé" message: "Server 01 - CPU à {{ states('sensor.server_01_cpu') }}%" mode: single ``` ### 6.3 Shutdown programmé (extinction nocturne) ```yaml alias: "Scheduled Shutdown - Server 01" description: Éteindre le serveur à 23h chaque soir trigger: - platform: time at: "23:00:00" condition: - condition: state entity_id: binary_sensor.server_01_disponibilite state: "on" action: - service: button.press target: entity_id: button.server_01_shutdown mode: single ``` ### 6.4 Wake-on-LAN au démarrage de HA ```yaml alias: "WOL - Server 01 on HA Start" description: Démarrer le serveur quand Home Assistant démarre trigger: - platform: homeassistant event: start action: - service: wake_on_lan.send_magic_packet data: mac: "AA:BB:CC:DD:EE:FF" broadcast_address: "192.168.1.255" mode: single ``` ## 7. Intégration Personnalisée (Custom Integration) ### 7.1 Structure du Custom Component Pour créer une intégration personnalisée plus avancée : ``` custom_components/ └── ipwatch/ ├── __init__.py ├── manifest.json ├── config_flow.py ├── const.py ├── sensor.py ├── binary_sensor.py ├── button.py └── strings.json ``` ### 7.2 Manifest **`manifest.json`** : ```json { "domain": "ipwatch", "name": "IPWatch Network Monitor", "version": "1.0.0", "documentation": "https://github.com/your-repo/ipwatch-ha", "requirements": ["paho-mqtt==1.6.1"], "dependencies": ["mqtt"], "codeowners": ["@yourusername"], "iot_class": "local_push", "config_flow": true } ``` ### 7.3 Constants **`const.py`** : ```python """Constants for IPWatch integration.""" DOMAIN = "ipwatch" CONF_MQTT_BROKER = "mqtt_broker" CONF_MQTT_PORT = "mqtt_port" CONF_DEVICE_IP = "device_ip" CONF_DEVICE_NAME = "device_name" # MQTT Topics TOPIC_PREFIX = "ipwatch/device" TOPIC_COMMAND = "command" TOPIC_STATUS = "status" TOPIC_AVAILABILITY = "availability" TOPIC_RESPONSE = "response" # Commands COMMAND_SHUTDOWN = "shutdown" COMMAND_REBOOT = "reboot" COMMAND_STATUS = "status" # Platforms PLATFORMS = ["sensor", "binary_sensor", "button"] ``` ### 7.4 Config Flow (UI Configuration) **`config_flow.py`** : ```python """Config flow for IPWatch integration.""" import voluptuous as vol from homeassistant import config_entries from homeassistant.core import callback from .const import DOMAIN, CONF_DEVICE_IP, CONF_DEVICE_NAME class IPWatchConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for IPWatch.""" VERSION = 1 async def async_step_user(self, user_input=None): """Handle the initial step.""" errors = {} if user_input is not None: # Validate user input await self.async_set_unique_id(user_input[CONF_DEVICE_IP]) self._abort_if_unique_id_configured() return self.async_create_entry( title=user_input[CONF_DEVICE_NAME], data=user_input ) data_schema = vol.Schema({ vol.Required(CONF_DEVICE_IP): str, vol.Required(CONF_DEVICE_NAME): str, }) return self.async_show_form( step_id="user", data_schema=data_schema, errors=errors ) ``` ### 7.5 Sensor Platform **`sensor.py`** : ```python """Sensor platform for IPWatch.""" from homeassistant.components.sensor import SensorEntity from homeassistant.core import callback from .const import DOMAIN async def async_setup_entry(hass, config_entry, async_add_entities): """Set up IPWatch sensor based on a config entry.""" device_ip = config_entry.data[CONF_DEVICE_IP] device_name = config_entry.data[CONF_DEVICE_NAME] sensors = [ IPWatchCPUSensor(device_ip, device_name), IPWatchMemorySensor(device_ip, device_name), IPWatchDiskSensor(device_ip, device_name), IPWatchUptimeSensor(device_ip, device_name), ] async_add_entities(sensors) class IPWatchCPUSensor(SensorEntity): """Representation of IPWatch CPU sensor.""" def __init__(self, device_ip, device_name): """Initialize the sensor.""" self._device_ip = device_ip self._device_name = device_name self._state = None self._available = False @property def name(self): """Return the name of the sensor.""" return f"{self._device_name} CPU" @property def unique_id(self): """Return a unique ID.""" return f"ipwatch_{self._device_ip.replace('.', '_')}_cpu" @property def state(self): """Return the state of the sensor.""" return self._state @property def unit_of_measurement(self): """Return the unit of measurement.""" return "%" @property def icon(self): """Return the icon.""" return "mdi:cpu-64-bit" @property def available(self): """Return True if entity is available.""" return self._available @callback def _handle_status_update(self, msg): """Handle MQTT status updates.""" import json payload = json.loads(msg.payload) self._state = payload.get("cpu_percent") self._available = True self.async_write_ha_state() async def async_added_to_hass(self): """Subscribe to MQTT topics.""" await self.hass.components.mqtt.async_subscribe( f"ipwatch/device/{self._device_ip}/status", self._handle_status_update ) ``` ### 7.6 Button Platform **`button.py`** : ```python """Button platform for IPWatch.""" from homeassistant.components.button import ButtonEntity from .const import DOMAIN, COMMAND_SHUTDOWN, COMMAND_REBOOT import json from datetime import datetime async def async_setup_entry(hass, config_entry, async_add_entities): """Set up IPWatch buttons.""" device_ip = config_entry.data[CONF_DEVICE_IP] device_name = config_entry.data[CONF_DEVICE_NAME] buttons = [ IPWatchShutdownButton(hass, device_ip, device_name), IPWatchRebootButton(hass, device_ip, device_name), ] async_add_entities(buttons) class IPWatchShutdownButton(ButtonEntity): """Shutdown button for IPWatch device.""" def __init__(self, hass, device_ip, device_name): """Initialize the button.""" self.hass = hass self._device_ip = device_ip self._device_name = device_name @property def name(self): """Return the name.""" return f"{self._device_name} Shutdown" @property def unique_id(self): """Return unique ID.""" return f"ipwatch_{self._device_ip.replace('.', '_')}_shutdown" @property def icon(self): """Return icon.""" return "mdi:power-off" async def async_press(self): """Handle button press.""" topic = f"ipwatch/device/{self._device_ip}/command" payload = json.dumps({ "command": COMMAND_SHUTDOWN, "timestamp": datetime.now().isoformat() }) await self.hass.components.mqtt.async_publish( topic, payload, qos=1 ) ``` ## 8. Scripts Python pour Administration ### 8.1 Script de Découverte Automatique **`scripts/publish_discovery.py`** : ```python #!/usr/bin/env python3 """ Publie la configuration MQTT Discovery pour tous les équipements IPWatch """ import paho.mqtt.client as mqtt import json import sys def publish_discovery(broker, port, device_ip, device_name): """Publie les configs Discovery pour un équipement""" client = mqtt.Client() client.connect(broker, port) unique_id = f"ipwatch_{device_ip.replace('.', '_')}" # Sensor système config = { "name": f"{device_name} - Système", "unique_id": f"{unique_id}_system", "state_topic": f"ipwatch/device/{device_ip}/status", "value_template": "{{ value_json.hostname }}", "json_attributes_topic": f"ipwatch/device/{device_ip}/status", "availability": { "topic": f"ipwatch/device/{device_ip}/availability", "payload_available": "online", "payload_not_available": "offline" }, "device": { "identifiers": [unique_id], "name": device_name, "model": "IPWatch MQTT Agent v1.0", "manufacturer": "IPWatch" }, "icon": "mdi:desktop-tower", "qos": 1 } topic = f"homeassistant/sensor/{unique_id}/system/config" client.publish(topic, json.dumps(config), qos=1, retain=True) print(f"✓ Published sensor config for {device_name}") # Binary sensor availability config = { "name": f"{device_name} - Disponibilité", "unique_id": f"{unique_id}_availability", "state_topic": f"ipwatch/device/{device_ip}/availability", "payload_on": "online", "payload_off": "offline", "device_class": "connectivity", "device": {"identifiers": [unique_id]}, "icon": "mdi:lan-connect", "qos": 1 } topic = f"homeassistant/binary_sensor/{unique_id}/availability/config" client.publish(topic, json.dumps(config), qos=1, retain=True) print(f"✓ Published binary_sensor config for {device_name}") # Buttons for cmd in ["shutdown", "reboot"]: config = { "name": f"{device_name} - {cmd.capitalize()}", "unique_id": f"{unique_id}_{cmd}", "command_topic": f"ipwatch/device/{device_ip}/command", "payload_press": json.dumps({"command": cmd}), "availability": { "topic": f"ipwatch/device/{device_ip}/availability", "payload_available": "online", "payload_not_available": "offline" }, "device": {"identifiers": [unique_id]}, "icon": f"mdi:{'power-off' if cmd == 'shutdown' else 'restart'}", "qos": 1 } topic = f"homeassistant/button/{unique_id}/{cmd}/config" client.publish(topic, json.dumps(config), qos=1, retain=True) print(f"✓ Published button {cmd} config for {device_name}") client.disconnect() if __name__ == "__main__": if len(sys.argv) != 5: print("Usage: python publish_discovery.py ") sys.exit(1) publish_discovery(sys.argv[1], int(sys.argv[2]), sys.argv[3], sys.argv[4]) ``` **Utilisation** : ```bash python3 scripts/publish_discovery.py localhost 1883 10.0.0.100 "Server 01" ``` ## 9. Développement de l'App Home Assistant ### 9.1 Recommandations Pour développer une application Home Assistant dédiée à IPWatch : 1. **Utiliser MQTT Discovery** : Simplifie l'ajout d'équipements 2. **Créer un Custom Component** : Intégration native dans Home Assistant 3. **Implémenter Config Flow** : Configuration via UI (Settings → Integrations) 4. **Supporter Multiple Devices** : Un équipement IPWatch = un device HA 5. **Gérer les états** : Mapping clair entre MQTT et entités HA 6. **Ajouter des diagnostics** : Logs et debugging pour faciliter le support ### 9.2 Fonctionnalités Avancées **WOL depuis Home Assistant** : ```yaml # Configuration Wake-on-LAN wake_on_lan: # Service call service: wake_on_lan.send_magic_packet data: mac: "AA:BB:CC:DD:EE:FF" broadcast_address: "192.168.1.255" ``` **Intégration avec Lovelace Dashboard** : - Card personnalisée pour afficher grille IPWatch - Actions rapides (shutdown, reboot, WOL) - Graphiques historiques des métriques **Notifications Push** : - Alertes sur changements d'état - Notifications sur nouveaux équipements détectés ## 10. Tests et Validation ### 10.1 Tester Discovery ```bash # Écouter les messages Discovery mosquitto_sub -h localhost -t "homeassistant/#" -v # Vérifier que Home Assistant a créé les entités # Developer Tools → States # Rechercher : sensor.server_01, binary_sensor.server_01, button.server_01 ``` ### 10.2 Tester les Commandes ```bash # Tester shutdown via MQTT mosquitto_pub -h localhost \ -t "ipwatch/device/10.0.0.100/command" \ -m '{"command":"shutdown","timestamp":"2025-12-23T10:30:00Z"}' # Vérifier la réponse mosquitto_sub -h localhost \ -t "ipwatch/device/10.0.0.100/response" -v ``` ### 10.3 Tester les Automatisations 1. Créer une automatisation simple 2. Déclencher manuellement 3. Vérifier les logs HA : Settings → System → Logs ## 11. Dépannage ### Entités non découvertes ```bash # Vérifier que Discovery est activé # configuration.yaml mqtt: discovery: true # Republier les configs python3 scripts/publish_discovery.py localhost 1883 10.0.0.100 "Server 01" # Redémarrer Home Assistant ``` ### Boutons ne fonctionnent pas - Vérifier que l'agent MQTT est en ligne - Vérifier les permissions sudo sur le client - Consulter les logs de l'agent : `sudo journalctl -u ipwatch-mqtt-agent -f` ### Sensors non mis à jour - Vérifier que le topic status est publié toutes les 30 secondes - Vérifier le QoS (doit être 1) - Vérifier la disponibilité du broker MQTT ## 12. Références - **Home Assistant MQTT Discovery** : https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery - **Home Assistant Developer Docs** : https://developers.home-assistant.io/ - **MQTT Sensor** : https://www.home-assistant.io/integrations/sensor.mqtt/ - **MQTT Button** : https://www.home-assistant.io/integrations/button.mqtt/ - **Config Flow** : https://developers.home-assistant.io/docs/config_entries_config_flow_handler/ ## 13. Checklist de Développement Avant de publier l'intégration Home Assistant : - [ ] MQTT Discovery implémenté pour tous les composants - [ ] Config Flow pour configuration via UI - [ ] Gestion des erreurs et retry automatique - [ ] Documentation complète (README, HACS) - [ ] Tests unitaires et d'intégration - [ ] Validation HACS (Home Assistant Community Store) - [ ] Icônes et traductions - [ ] Changelog et versioning sémantique - [ ] CI/CD pour tests automatisés - [ ] Support multi-langues (i18n)