Lire le niveau de fioul à l'aide d'une webcam avec LLM vision

Bonjour,

Je viens de parcourir le forum et je constate qu’il existe deux manière de mesurer le niveau de fioul :

  • par ultrason,
  • par pesée.

Pour la méthode par ultrason il faut percer la cuve de fioul par le dessus ou utiliser une trappe de visite, deux méthodes impossibles dans mon cas. Il y a aussi des problèmes de norme, donc d’assurance.

J’envisage une méthode simple : mettre une caméra devant la cuve et prendre une photo toutes les 6 heures pour mesurer le niveau du liquide.

Ci-dessous des photos de la cuve de 1000l. Il y a trois cuves toutes au même niveau.

Sur cette photo, je dirais qu’il y a environ 900 litres (300x3). Vu que le niveau est très approximatif, une lecture par jour est envisagable.

J’envisage d’utiliser LLM Vision avec Ollama en local ou Groq.

Avant de débuter le projet, j’aimerais savoir si une telle solution d’analyse d’image ou d’IA existe déjà sous Home Assistant et si cela a déjà été fait.

Merci d’avance,
Kellogs

Je réponds à mon propre post. Claude AI me suggère :

automations.yaml

automation:
  - alias: "Niveau cuve fioul"
    triggers:
      - trigger: time
        at: "07:00:00"
      - trigger: time
        at: "19:00:00"
    actions:
      - action: light.turn_on
        target:
          entity_id: light.cave
      - delay: "00:00:03"
      - action: llmvision.image_analyzer
        data:
          provider: Ollama
          model: llama3.2-vision:11b
          message: >
            Regarde la paroi de cette cuve blanche. 
            Le fioul est un liquide sombre visible en bas de la cuve. 
            Estime le niveau de remplissage en pourcentage entier de 0 à 100. 
            Réponds uniquement avec le nombre, sans texte ni unité.
          image_entity: camera.cave_cuve
          max_tokens: 10
          target_width: 640
        response_variable: analyse
      - action: light.turn_off
        target:
          entity_id: light.cave
      - action: input_number.set_value
        target:
          entity_id: input_number.niveau_cuve_fioul
        data:
          value: "{{ analyse.response_text | int(0) }}"

configuration.yaml

input_number:
  niveau_cuve_fioul:
    name: "Niveau cuve fioul"
    min: 0
    max: 100
    step: 1
    unit_of_measurement: "%"
    icon: mdi:oil-level

Cela a l’air très simple.

Ensuite, j’installe HA LLM depuis HACS et je configure l’adresse de mon serveur Ollama local (mais on peut utiliser Qroc, c’est quasi-gratuit).

Dans mon serveur Debian R720XD, il y a une petite carte Nvidia. J’utilise Docker et j’installe installé ollama dans un container de cette manière :
cat docker-compose.yml

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: on-failure
    ports:
      - "11434:11434"
    volumes:
      - /tank/ollama:/root/.ollama
      - /usr/lib/x86_64-linux-gnu/nvidia/current:/usr/local/nvidia/lib64:ro
    environment:
      - OLLAMA_HOST=0.0.0.0
      - OLLAMA_MAX_LOADED_MODELS=3       # ajuster selon modèle et RAM disponible
      - OLLAMA_CONTEXT_LENGTH=8192
      - OLLAMA_NUM_PARALLEL=1
      - OLLAMA_MAX_RAM=230G              # limite Ollama pour ne pas toucher ARC
      - OLLAMA_KEEP_ALIVE=5m
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]

Je lance une interrogation test pour voir si cela fonctionne :

curl http://192.168.10.196:11434/api/generate \
  -d "{
    \"model\": \"llama3.2-vision:11b\",
    \"prompt\": \"This is a white plastic fuel oil tank. The dark area at the bottom is fuel oil visible through the translucent wall. Estimate the fill level as an integer percentage from 0 to 100. Reply with the number only.\",
    \"images\": [\"$(base64 -i ~/Desktop/IMG_4084.jpg)\"],
    \"stream\": false,
    \"options\": {\"num_predict\": 5}
  }"

Durant l’interrogation, mon serveur monte à 50% d’utilisation environ (il semblerait qu’il utilise beaucoup le CPU car c’est une petite carte nvidia) :

top - 20:19:01 up 9 days,  3:49,  1 user,  load average: 11.42, 3.86, 1.41
Tasks: 656 total,   1 running, 655 sleeping,   0 stopped,   0 zombie
%Cpu(s): 48.6 us,  1.3 sy,  0.0 ni, 49.6 id,  0.5 wa,  0.0 hi,  0.0 si,  0.0 st 
MiB Mem : 322374.5 total,  13139.7 free, 307545.6 used,   4602.9 buff/cache     
MiB Swap: 244140.0 total, 244139.9 free,      0.1 used.  14828.9 avail Mem 

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                         
3473857 root      20   0   16.6g  11.2g  28724 S  1584   3.5  16:35.68 ollama                                          
    656 root      20   0       0      0      0 S   4.3   0.0   4:01.95 btrfs-transaction                               
   2111 root      20   0   88812   9892   7272 S   2.6   0.0  27:55.33 monit                                           
   2003 root      20   0    3528   2608   2316 S   1.0   0.0  49:49.97 ledmon                                          
3474094 mario     20   0   10872   5820   3604 R   1.0   0.0   0:00.17 top                                             
      1 root      20   0   26244  17564  10972 S   0.7   0.0  15:22.91 systemd                                         
    251 root      20   0       0      0      0 S   0.7   0.0  36:42.98 kcompactd0                                      
   2305 root      20   0  836828  13432  10304 S   0.7   0.0  48:15.32 collectd                                        
 105357 root      20   0 3198552  48036  15392 S   0.7   0.0  23:31.88 containerd                                      
     15 root      20   0       0      0      0 I   0.3   0.0  13:52.68 rcu_preempt                                     
    736 root      20   0  149636  33504  31932 S   0.3   0.0   3:52.79 systemd-journal                                 
   1999 message+  20   0    8840   5480   4260 S   0.3   0.0   3:32.80 dbus-daemon                                     
   2014 root      20   0   19128   9308   8008 S   0.3   0.0   1:14.49 systemd-logind                                  
   2293 root      20   0  544112  47456   1984 S   0.3   0.0  39:06.52 rrdcached                                       
3069684 root      20   0 1358680  86388  25392 S   0.3   0.0   1:21.45 tailscaled                                      
3471335 root      20   0       0      0      0 I   0.3   0.0   0:00.02 kworker/25:1-events                             
      2 root      20   0       0      0      0 S   0.0   0.0   0:30.85 kthreadd                                        
      3 root      20   0       0      0      0 S   0.0   0.0   0:00.00 pool_workqueue_release                          
      4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/R-rcu_gp                                
      5 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/R-sync_wq                               
      6 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/R-kvfree_rcu_reclaim                    
      7 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/R-slub_flushwq                          
      8 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 kworker/R-netns

Après 10 minutes, il me répond 50% donc je modifie le prompt :

curl http://192.168.10.196:11434/api/generate \
  -d "{
    \"model\": \"llama3.2-vision:11b\",
    \"prompt\": \"This is a single white translucent plastic fuel oil tank. There is a vertical metal fixing bar in the center of the tank - ignore it completely. The dark brownish area at the very bottom is fuel oil visible through the translucent plastic wall. The light beige upper area contains no fuel. Measure the height of the dark fuel area compared to the total visible height of the tank. Give only an integer from 0 to 100 representing this ratio in percent. Reply with the number only, no text.\",
    \"images\": [\"$(base64 -i ~/Desktop/IMG_4084.jpg)\"],
    \"stream\": false,
    \"options\": {\"num_predict\": 5}
  }"

Il me répond 20.

Le problème vient de l’absence de graduation. Donc je passe commande sur Amazon d’une règle graduée autocollante de 2 m :

Enfin je configure ma carte nvidia. Le calcul utilise 30% de GPU et 70% de CPU, mais la réponse est donnée en 37 secondes. Donc inutile d’utiliser Croq. Cependant, pour ceux qui n’ont pas de GPU, Croq c’est vraiment la solution.

La suite la semaine prochaine …

Il me reste à :

  • Placer un caméra de surveillance (j’ai commandé une R520A),
  • Domotiser l’éclairage.
  • Coller l’échelle de graduation.

Cordialement,
Kellogs

1 « J'aime »

J’ai déplacé une webcam Reolink pour faire un test et l’image est assez nette, donc pas besoin d’allumer la lumière. Quand il y aura une graduation, ce sera bien lisible.

Bonjour,
Dans le même ordre d’idée mais avec une jauge avec aiguille présente sur le dessus de la citerne à mazout (la citerne est à l’intérieur de l’habitation).

  • prendre une image de la jauge avec une caméra ou un appareil photo d’un Raspberry Pi 3b.
  • utiliser un script Python sur le Raspberry permettant d’analyser l’image reçue avec OpenCV.
  • en fonction de la position de l’aiguille, transmettre l’information (l’état) à Home Assistant via wifi (en mqtt ?).

Afin de ne pas polluer ce post, je vais ouvrir un nouveau sujet …Le sujet en question

Sans graduation et repère, il risque de faire des estimations à la louche.

J’ai du mal a voir comment il va déterminer, 19% puis 18% etc.

J’ai avancé de mon côté :

alias: Niveau fioul
description: ""
triggers:
  - trigger: time
    at: "04:02:00"
conditions: []
actions:
  - action: llmvision.image_analyzer
    metadata: {}
    data:
      store_in_timeline: false
      use_memory: false
      include_filename: false
      target_width: 1280
      generate_result: false
      expose_images: false
      response_format: text
      provider: 01KQMY12WNCXRR54TNBTR8W1ZY
      image_entity:
        - camera.reolink_rlc_520a_snapshots_main
      message: >-
        There are three white translucent plastic fuel oil tanks side by side.
        The lower darker gray portion of each tank contains fuel oil. The upper
        lighter portion is empty. What percentage of the MIDDLE tank height is
        filled with fuel? Answer with a single integer only.
      model: llama3.2-vision:11b
      max_tokens: 10
      temperature: 1
    response_variable: analyse
  - action: input_number.set_value
    metadata: {}
    target:
      entity_id: input_number.niveau_cuve_fioul
    data:
      value: "{{ analyse.response_text | regex_search('\\d+') | int(0) }}"
mode: single

Sans bande graduée, le modèle non-déterministe répond n’importe quoi : parfois 0, parfois 1 et parfois 57. Donc j’attends la bande graduée pour reprendre.

Par ailleurs, il s’est passé quelque chose de bizarre : après une première valeur de input_number.niveau_cuve_fioul à 57% au bout de quelques minutes la variable est repassée à 0. Je ne me souviens pas avoir cliqué pour relancer l’automatisation.

Cet après-midi, j’ai acheté un lot de 11 caméras PoE Dahua sur LBC à un prix défiant toute concurrence. Ce sont de très bonnes caméras récentes, très bien supportées. Dès que je les reçois, je tente de lire la consommation d’eau sur le compteur, ce qui ne devrait pas poser de problème à Ollama.

Salut,

Tu es minimaliste là…
Tu peux mesurer la hauteur du liquide (ici le niveau de fuel dans la cuve) avec une sonde de pression hydrostatique.

Bon à savoir, cela m’intéresse.

Cependant il faut une sonde ATEX certifiée hydrocarbures. C’est le cas de la sonde citée ? Je suis assez réservé quant à plonger une sonde et un matériel électrique dans du fioul et laisser le fioul agir durant 10 ans. Je doute que les joints tiennent et cela ne me convient pas nécessairement. Cela nécessitera que je sorte régulièrement chaque année la sonde pour la contrôler. Les bouchons de cuve sont rigides et la question de l’immersion de la sonde se pose.

Ceci dit je souhaite explorer la piste de l’IA à fond, car on peut lire toutes sortes de données avec une simple webcam et il n’y a aucun contact avec le fioul. Par ailleurs, mon compteur d’eau n’est pas domotisable et je compte bien lire la consommation d’eau de cette manière.

Il y a énormément de développements possibles avec LLM vision …

En usage domestique, tu n’est pas dans le domaine de l’ATEX (directive).
D’ailleurs, il n’y a pas de zonage ATEX autour d’une cuve fuel.
Le point éclair du Fuel domestique est de 55°C.
Cela veut dire que ce fuel à température ambiante n’émet pas suffisamment de vapeur pour créer une ATEX.
Maintenant, effectivement, cela ne veut pas dire que l’on peu faire tout et n’importe quoi.

Ce qui me dérange, c’est de plonger une sonde électrique dans le fioul où elle séjournera des années. Il faut être organisé pour extraire et vérifier la sonde à intervalle régulier et en avoir les compétences et je ne les ai pas …

J’ai reçu la règle graduée, elle fait 2cm de large, donc lecture difficile à distance. Il faudra envoyer une grande image au LLM … Mais si cela ne fonctionne pas, il reste la possibilité de faire ma propre graduation. C’est assez facile …