Consommation d'eau avec Selenium dans home Assistant

Bonjour,

J’ai développé un script en python qui me permet de récupérer ma consomation d’eau chez mon fournisseur. Il fonctionne tres bien dans mon environnement docker en dehors de home assistant :

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
import time
from dotenv import load_dotenv
import os

# Charger les variables d'environnement depuis le fichier .env
load_dotenv()

# Récupérer les informations de connexion depuis les variables d'environnement
email = os.getenv('EMAIL_OCEA')  # Récupère la variable EMAIL_OCEA
password = os.getenv('PASSWORD_OCEA')  # Récupère la variable PASSWORD_OCEA

def fetch_water_consumption():
    # Options Firefox en mode headless
    options = Options()
    options.headless = True

    # Connexion au serveur Selenium distant sur localhost:4444
    driver = webdriver.Remote(
        command_executor='http://192.168.x.x:4444/wd/hub',
        options=options
    )

    try:
        # Ouvrir la page de connexion
        driver.get("https://espace-resident.ocea-sb.com")

        # Attendre que la page se charge
        time.sleep(2)

        # Trouver les champs de saisie et entrer l'email et le mot de passe
        email_field = driver.find_element(By.ID, "email")
        password_field = driver.find_element(By.ID, "password")

        email_field.send_keys(email)
        password_field.send_keys(password)

        # Cliquer sur le bouton "Se connecter"
        login_button = driver.find_element(By.ID, "next")
        login_button.click()

        # Attendre que la page se charge après la connexion
        time.sleep(5)

        # Récupérer les valeurs de consommation d'eau
        consomation_elements = driver.find_elements(By.CLASS_NAME, "v-card-text.conso")

        if len(consomation_elements) >= 2:
            eau_froide = consomation_elements[0].text.strip()  # Consommation d'eau froide
            eau_chaude = consomation_elements[1].text.strip()  # Consommation d'eau chaude
            print(f"Consommation eau froide : {eau_froide}")
            print(f"Consommation eau chaude : {eau_chaude}")
        else:
            print("Impossible de trouver les consommations d'eau.")
    
    except Exception as e:  
        print(f"Erreur lors de l'extraction des données : {e}")

    finally:
        # Fermer le navigateur
        driver.quit()

# Exécution de la fonction
fetch_water_consumption()

Je cherche à intégréer ce script à home assistant. Je suis partie sur la piste de appdeamon que j’ai configuré comme ceci :


Voici le script adapté à Home assistant et installé dans le répertoire apps/ de AppDaemon :

import appdaemon.plugins.hass.hassapi as hass
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import os
from dotenv import load_dotenv
import time

class WaterConsumption(hass.Hass):
    def initialize(self):
        """
        Initialise l'application et charge les informations nécessaires.
        """
        # Charger les informations de connexion depuis .env
        load_dotenv("/config/appdaemon/apps/.env")
        self.email = os.getenv("EMAIL_OCEA")
        self.password = os.getenv("PASSWORD_OCEA")

        # Ajouter un événement pour lancer la récupération des données
        self.listen_event(self.fetch_water_data_event, "fetch_water_data_event")

    def fetch_water_data_event(self, event_name, data, kwargs):
        """
        Gère l'événement pour déclencher la récupération des données.
        """
        self.fetch_water_data()

    def fetch_water_data(self):
        """
        Récupère les données de consommation d'eau et met à jour les capteurs Home Assistant.
        """
        # Configurer Selenium avec Chrome en mode headless
        chrome_options = Options()
        chrome_options.add_argument('--headless')  # Mode sans interface graphique
        chrome_options.add_argument('--no-sandbox')  # Désactive le sandboxing
        chrome_options.add_argument('--disable-gpu')  # Désactive le GPU
        chrome_options.add_argument('--disable-dev-shm-usage')  # Utilisation alternative pour éviter les problèmes de mémoire

        # Configurer le chemin vers chromedriver via la classe Service
        service = Service('/usr/bin/chromedriver')

        # Instancier le driver Chrome
        driver = webdriver.Chrome(service=service, options=chrome_options)

        try:
            # Accéder au site
            driver.get("https://espace-resident.ocea-sb.com")
            time.sleep(2)

            # Remplir les champs de connexion
            driver.find_element(By.ID, "email").send_keys(self.email)
            driver.find_element(By.ID, "password").send_keys(self.password)

            # Cliquer sur le bouton de connexion
            driver.find_element(By.ID, "next").click()
            time.sleep(5)

            # Récupérer les consommations d'eau
            consumption_elements = driver.find_elements(By.CLASS_NAME, "v-card-text.conso")
            if len(consumption_elements) >= 2:
                eau_froide = consumption_elements[0].text.strip()
                eau_chaude = consumption_elements[1].text.strip()

                # Mettre à jour les capteurs Home Assistant
                self.set_state(
                    "sensor.eau_froide",
                    state=eau_froide,
                    attributes={"unit_of_measurement": "m3", "friendly_name": "Eau Froide"}
                )
                self.set_state(
                    "sensor.eau_chaude",
                    state=eau_chaude,
                    attributes={"unit_of_measurement": "m3", "friendly_name": "Eau Chaude"}
                )

                self.log(f"Consommation eau froide : {eau_froide}, eau chaude : {eau_chaude}")
            else:
                self.log("Impossible de trouver les consommations d'eau.", level="ERROR")

        except Exception as e:
            self.log(f"Erreur lors de l'extraction des données : {e}", level="ERROR")

        finally:
            driver.quit()

Voici les logs lors du lancement de AppDaemon :

2025-01-22 00:12:20.722190 INFO AppDaemon: Loading app hello_world using class HelloWorld from module hello
2025-01-22 00:12:20.723293 INFO AppDaemon: Loading app water_consumption using class WaterConsumption from module water_consumption
2025-01-22 00:12:20.724922 INFO AppDaemon: Calling initialize() for hello_world
2025-01-22 00:12:20.830044 INFO hello_world: Hello from AppDaemon
2025-01-22 00:12:20.830908 INFO hello_world: You are now ready to run Apps!
2025-01-22 00:12:20.832008 INFO AppDaemon: Calling initialize() for water_consumption
2025-01-22 00:12:20.834295 INFO AppDaemon: App initialization complete

Lorsque que j’exécute fetch_water_data_event dans avec un bouton et un script j’otient ca :

2025-01-22 13:45:45.292696 INFO AppDaemon: Calling initialize() for water_consumption
2025-01-22 13:45:54.660533 INFO AppDaemon: Terminating water_consumption
2025-01-22 13:45:54.663016 INFO AppDaemon: Reloading Module: /config/apps/water_consumption.py
2025-01-22 13:45:54.665987 INFO AppDaemon: Loading app water_consumption using class WaterConsumption from module water_consumption
2025-01-22 13:45:54.667761 INFO AppDaemon: Calling initialize() for water_consumption
2025-01-22 13:47:02.246297 ERROR water_consumption: Erreur lors de l'extraction des donn��es : object of type 'NoneType' has no len()

Ma question : Qu’est-ce que j’ai pas compris ?


System Information

version core-2025.1.2
installation_type Home Assistant OS
dev false
hassio true
docker true
user root
virtualenv false
python_version 3.13.1
os_name Linux
os_version 6.6.66-haos
arch x86_64
timezone Europe/Paris
config_dir /config
Home Assistant Community Store
GitHub API ok
GitHub Content ok
GitHub Web ok
HACS Data ok
GitHub API Calls Remaining 5000
Installed Version 2.0.3
Stage running
Available Repositories 1573
Downloaded Repositories 10
Home Assistant Cloud
logged_in false
can_reach_cert_server ok
can_reach_cloud_auth ok
can_reach_cloud ok
Home Assistant Supervisor
host_os Home Assistant OS 14.1
update_channel stable
supervisor_version supervisor-2024.12.3
agent_version 1.6.0
docker_version 27.2.0
disk_total 30.8 GB
disk_used 7.1 GB
healthy true
supported true
host_connectivity true
supervisor_connectivity true
ntp_synchronized true
virtualization kvm
board ova
supervisor_api ok
version_api ok
installed_addons Advanced SSH & Web Terminal (20.0.0), AirSend (1.2), Mosquitto broker (6.5.0), Samba Backup (5.2.0), File editor (5.8.0), MariaDB (2.7.2), phpMyAdmin (0.11.0), AppDaemon (0.16.7), Zigbee2MQTT (2.0.0-2), Matter Server (7.0.0)
Dashboards
dashboards 3
resources 5
views 9
mode storage
Recorder
oldest_recorder_run 20 décembre 2024 à 20:56
current_recorder_run 21 janvier 2025 à 21:10
estimated_db_size 373.83 MiB
database_engine mysql
database_version 10.11.6
___

Je continue mes recherches et j’ai l’impression qu’il me manque selelium (/usr/bin/chromedriver) sur HA. J’ai plusieurs pistes comme apt et addons pour installé ces packages.

mes pistes :
https://www.reddit.com/r/homeassistant/comments/1byjsaf/has_anyone_got_selenium_running_in_hacs/ pour l’addons
problème je n’ai aucune idée comment procéder :

et une piste pour apk

Avez vous un avis sur la piste à suivre addons vs apk et comment faire ?

Salut

Dans appdaemon, tu peux dans la configuration faire la liste des packages que tu veux installer au démarrage de l’addons.

1 « J'aime »

J’ai fini par abandonner pour le moment le lancement du serveur selenium. J’utilise pour le moment un serveur selenium indépendant à home assistant (dans un container sur mon nas). Je parviens bien à récupérer les valeurs à partir du site de mon fournisseur via le script apps/water_consumption.py répertoire de l’add-on AppDaemon :

import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.firefox.options import Options
from dotenv import load_dotenv
import appdaemon.plugins.hass.hassapi as hass

class WaterConsumption(hass.Hass):
    def initialize(self):
        # Charger les variables d'environnement
        load_dotenv()

        # Récupérer les informations de connexion
        self.email = os.getenv("EMAIL_OCEA")
        self.password = os.getenv("PASSWORD_OCEA")

        # Écouter un événement personnalisé
        self.listen_event(self.fetch_water_consumption, "fetch_water_data_event")

    def fetch_water_consumption(self, event_name, data, kwargs):
        self.log("Début de l'extraction des données de consommation d'eau...")

        # Configurer Selenium en mode headless
        options = Options()
        options.headless = True

        driver = webdriver.Remote(
            command_executor="http://192.168.x.x:4444/wd/hub",
            options=options,
        )

        try:
            # Ouvrir la page de connexion
            driver.get("https://espace-resident.ocea-sb.com")
            time.sleep(2)  # Attendre que la page se charge

            # Trouver les champs de saisie et entrer les informations
            driver.find_element(By.ID, "email").send_keys(self.email)
            driver.find_element(By.ID, "password").send_keys(self.password)

            # Cliquer sur le bouton "Se connecter"
            driver.find_element(By.ID, "next").click()
            time.sleep(5)  # Attendre que la page suivante se charge

            # Récupérer les consommations d'eau
            consumption_elements = driver.find_elements(By.CLASS_NAME, "v-card-text.conso")

            if len(consumption_elements) >= 2:
                eau_froide = consumption_elements[0].text.strip().replace(" m3", "").replace(",", ".")  # Consommation d'eau froide sans unité
                eau_chaude = consumption_elements[1].text.strip().replace(" m3", "").replace(",", ".")  # Consommation d'eau chaude sans unité

                # Enregistrer les données dans des états Home Assistant
                self.set_state("sensor.eau_froide",state=eau_froide)
                self.set_state("sensor.eau_chaude",state=eau_chaude)

                self.log(f"Consommation récupérée : Eau froide = {eau_froide}m3, Eau chaude = {eau_chaude}m3")
            else:
                self.log("Impossible de trouver les consommations d'eau.", level="ERROR")

        except Exception as e:
            self.log(f"Erreur lors de l'extraction des données : {e}", level="ERROR")
        finally:
            # Fermer le navigateur
            driver.quit()
            self.log("Fin de l'extraction des données.")

Le fichier apps/.env dans le répertoire de l’add-on AppDaemon :

EMAIL_OCEA=mon_login
PASSWORD_OCEA=mon_mot_de_pass

Voici le contenu de apps/app.yaml dans répertoire de l’add-on AppDaemon :

---
water_consumption:
  module: water_consumption
  class: WaterConsumption

et l’automatisation pour récupéré toutes les heures la conso d’eau :

alias: fetch_water_data
description: ""
triggers:
  - trigger: time_pattern
    hours: /1
conditions: []
actions:
  - event: fetch_water_data_event
    event_data: {}
mode: single

configuration.yaml :

template: !include template.yaml
utility_meter: !include utility_meter.yaml

template.yaml :

  - sensor:
      - name: "Eau Froide"
        unit_of_measurement: "m³"
        device_class: water
        state_class: total_increasing
        unique_id: eau_froide
        state: "{{ states('sensor.eau_froide') | int }"
      - name: "Eau Chaude"
        unit_of_measurement: "m³"
        device_class: water
        state_class: total_increasing
        unique_id: eau_chaude
        state: "{{ states('sensor.eau_chaude') | int }}"

utility_meter.yaml

eau_chaude_usage_monthly:
  source: sensor.eau_chaude
  cycle: monthly
eau_froide_usage_monthly:
  source: sensor.eau_froide
  cycle: monthly

Je vais observé comment cela se comporte à la fin du mois et si la consomation va bien etre remise à zéro (peut etre pas tout compris encore…). Il faudra peut etre adapter le rythme de prise de mesure ou autre…
Je continue mes recherche à propos de selenium sous HA mais apres quelque tests cela semble tres instable ou alors je m’y prends comme un manche…

Une question si quelqu’un est arrivé jusque là : pourquoi les entités sensor.eau_chaude et sensor.eau_froide disparaissent au reboot de HA ?

1 « J'aime »