Files
pilot/backup_v1/20251229_0205/mqtt_unvai.py
Gilles Soulier c5381b7112 Pilot v2: Core implementation + battery telemetry
Major updates:
- Complete Rust rewrite (pilot-v2/) with working MQTT client
- Fixed MQTT event loop deadlock (background task pattern)
- Battery telemetry for Linux (auto-detected via /sys/class/power_supply)
- Home Assistant auto-discovery for all sensors and switches
- Comprehensive documentation (AVANCEMENT.md, CLAUDE.md, roadmap)
- Docker test environment with Mosquitto broker
- Helper scripts for development and testing

Features working:
 MQTT connectivity with LWT
 YAML configuration with validation
 Telemetry: CPU, memory, IP, battery (Linux)
 Commands: shutdown, reboot, sleep, screen (dry-run tested)
 HA discovery and integration
 Allowlist and cooldown protection

Ready for testing on real hardware.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 06:23:00 +01:00

234 lines
7.4 KiB
Python

import paho.mqtt.client as mqtt
import socket
hostname = socket.gethostname()
# Paramètres MQTT
mqtt_broker_ip_address = "10.0.0.3"
mqtt_port = 1883
mqtt_username = ""
mqtt_password = ""
discovery_prefix = "homeassistant"
device_name = "yoga14"
mac_address = "60:57:18:99:ed:05" # Ajout du mac_address manquant
device_info = {
"identifiers": [device_name],
"name": "Yoga 14",
"manufacturer": "Lenovo",
"model": "laptop",
"sw_version": "1.0.0",
"suggested_area": "salon",
}
# Configuration des entités
shutdown_entity = {
"name": f"shutdown_{device_name}",
"type": "switch",
"unique_id": f"shutdown_{device_name}_{mac_address}",
"command_topic": f"pilot/{device_name}/shutdown/set",
"state_topic": f"pilot/{device_name}/shutdown/state",
"availability_topic": f"pilot/{device_name}/shutdown/available",
"device_class": "switch",
"payload_on": "ON",
"payload_off": "OFF",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:power",
"device": device_info,
}
reboot_entity = {
"name": f"reboot_{device_name}",
"type": "switch",
"unique_id": f"reboot_{device_name}_{mac_address}",
"command_topic": f"pilot/{device_name}/reboot/set",
"state_topic": f"pilot/{device_name}/reboot/state",
"availability_topic": f"pilot/{device_name}/reboot/available",
"device_class": "switch",
"payload_on": "ON",
"payload_off": "OFF",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:restart",
"device": device_info,
}
battery_entity = {
"name": f"battery_{device_name}",
"type": "sensor",
"unique_id": f"battery_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/battery/state",
"unit_of_measurement": "%",
"device_class": "battery",
"availability_topic": f"pilot/{device_name}/battery/available",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:battery",
"device": device_info,
"update_interval": 60
}
charging_status_entity = {
"name": f"charging_status_{device_name}",
"type": "binary_sensor",
"unique_id": f"charging_status_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/charging_status/state",
"availability_topic": f"pilot/{device_name}/charging_status/available",
"device_class": "battery_charging",
"payload_on": "ON",
"payload_off": "OFF",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:battery-charging",
"device": device_info,
"update_interval": 5
}
screen_entity = {
"name": f"screen_{device_name}",
"type": "switch",
"unique_id": f"screen_{device_name}_{mac_address}",
"command_topic": f"pilot/{device_name}/screen/set",
"state_topic": f"pilot/{device_name}/screen/state",
"availability_topic": f"pilot/{device_name}/screen/available",
"device_class": "switch",
"payload_on": "ON",
"payload_off": "OFF",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:monitor",
"device": device_info,
}
# Ajout des nouvelles entités pour le CPU et la mémoire
cpu_temperature_entity = {
"name": f"cpu_temperature_{device_name}",
"type": "sensor",
"unique_id": f"cpu_temperature_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/cpu_temperature/state",
"unit_of_measurement": "°C",
"device_class": "temperature",
"availability_topic": f"pilot/{device_name}/cpu_temperature/available",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:thermometer",
"device": device_info,
"update_interval": 20
}
cpu_usage_entity = {
"name": f"cpu_usage_{device_name}",
"type": "sensor",
"unique_id": f"cpu_usage_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/cpu_usage/state",
"unit_of_measurement": "%",
"device_class": "power",
"availability_topic": f"pilot/{device_name}/cpu_usage/available",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:chip",
"device": device_info,
"update_interval": 10
}
memory_usage_entity = {
"name": f"memory_usage_{device_name}",
"type": "sensor",
"unique_id": f"memory_usage_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/memory_usage/state",
"unit_of_measurement": "%",
# "device_class": "memory",
"availability_topic": f"pilot/{device_name}/memory_usage/available",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:memory",
"device": device_info,
"update_interval": 10
}
cpu_frequency_entity = {
"name": f"cpu_frequency_{device_name}",
"type": "sensor",
"unique_id": f"cpu_frequency_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/cpu_frequency/state",
"unit_of_measurement": "GHz",
"device_class": "frequency",
"availability_topic": f"pilot/{device_name}/cpu_frequency/available",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:speedometer",
"device": device_info,
"update_interval": 20
}
ip_address_entity = {
"name": f"ip_address_{device_name}",
"type": "sensor",
"unique_id": f"ip_address_{device_name}_{mac_address}",
"state_topic": f"pilot/{device_name}/ip_address/state",
"availability_topic": f"pilot/{device_name}/ip_address/available",
#"device_class": "connectivity",
"payload_available": "online",
"payload_not_available": "offline",
"icon": "mdi:ip",
"device": device_info,
"update_interval": 60
}
cpu_frequency_slider_entity = {
"name": f"cpu_frequency_slider_{device_name}",
"type": "number",
"unique_id": f"cpu_frequency_slider_{device_name}_{mac_address}",
"command_topic": f"pilot/{device_name}/cpu_frequency_slider/set",
"state_topic": f"pilot/{device_name}/cpu_frequency_slider/state",
"availability_topic": f"pilot/{device_name}/cpu_frequency_slider/available",
"payload_available": "online",
"payload_not_available": "offline",
"min": 0.5,
"max": 3.0,
"step": 0.1,
"unit_of_measurement": "GHz",
"icon": "mdi:speedometer",
"device": device_info,
}
def deactivate_entities(client):
"""Désactive toutes les entités en les marquant comme 'unavailable'."""
entities = [
shutdown_entity,
reboot_entity,
battery_entity,
screen_entity,
cpu_temperature_entity,
cpu_usage_entity,
memory_usage_entity,
cpu_frequency_entity,
charging_status_entity,
ip_address_entity,
cpu_frequency_slider_entity
]
for entity in entities:
client.publish(entity["availability_topic"], entity["payload_not_available"], retain=True)
client.loop_stop() # Arrête la boucle MQTT proprement pour s'assurer que tous les messages sont publiés
print("All entities deactivated.")
# Fonction appelée lors de la connexion au broker MQTT
def on_connect(client, userdata, flags, rc):
if rc == 0:
print(f"Connected with result code {rc}")
deactivate_entities(client)
client.disconnect() # Déconnecter après la publication
# Configuration et démarrage du client MQTT
client = mqtt.Client()
client.username_pw_set(mqtt_username, mqtt_password)
client.on_connect = on_connect
client.connect(mqtt_broker_ip_address, mqtt_port, 60)
client.loop_forever()