ash ray cure Life is a bitch |
Ca sert à rien que je partage tout le projet : c'est basé sur un truc que j'ai modélisé autour d'une boite de conservation qui n'est plus trouvable : https://www.amazon.fr/gp/product/B09GBD8F8V (2,5l)
Et avec un seul capteur de pression qui supporte l'ensemble du distributeur, y'a un peu de jeu, et parfois le poids remonte légèrement.
Probablement qu'un jour j'améliorerai ça avec 3 capteurs pour avoir un truc plus stable + le réservoir aussi imprimé en 3d, mais ça marche suffisamment bien pour que j'ai la flemme pour l'instant
Après si vous voulez, le capteur c'est ça (version 5Kg) : https://fr.aliexpress.com/item/1005005990833147.html
Et la config esphome :
Code :
- esphome:
- name: distributeur-croquettes
- friendly_name: Distributeur croquettes
- platformio_options:
- board_build.f_flash: 40000000L
- board_build.flash_mode: dio
- board_build.flash_size: 4MB
- on_boot:
- then:
- - sensor.template.publish:
- id: quantity_eaten
- state: !lambda 'return id(quantity_eaten_val);'
- - text_sensor.template.publish:
- id: last_refill_time
- state: !lambda 'return id(last_refill_val);'
- - text_sensor.template.publish:
- id: last_eat_time
- state: !lambda 'return id(last_eat_val);'
- esp32:
- board: esp32-c3-devkitm-1
- variant: esp32c3
- framework:
- type: esp-idf
- version: recommended
- wifi:
- ssid: "SSID"
- password: "password
- output_power: 20.5
- power_save_mode: none
- api:
- ota:
- platform: esphome
- logger:
- level: INFO
- # logs:
- # sensor: INFO
- globals:
- - id: previous_weight
- type: float
- restore_value: no
- initial_value: '0'
- - id: previous_weight_eating
- type: float
- restore_value: no
- initial_value: '0'
- - id: quantity_eaten_val
- type: float
- restore_value: yes
- initial_value: '0'
- - id: last_refill_val
- type: std::string
- restore_value: yes
- - id: last_eat_val
- type: std::string
- restore_value: yes
- text_sensor:
- - platform: template
- id: status
- name: Status
- icon: mdi:state-machine
- - platform: template
- id: last_refill_time
- name: Date of last refill
- icon: mdi:basket-fill
- - platform: template
- id: last_eat_time
- name: Date of last eat
- icon: mdi:basket-unfill
- time:
- - platform: sntp
- id: sntp_time
- timezone: Europe/Paris
- switch:
- - platform: template
- id: debug
- name: Debug
- optimistic: true
- restore_mode: RESTORE_DEFAULT_OFF
- sensor:
- - platform: duty_time
- id: eating_counter
- update_interval: 1s
- - platform: duty_time
- id: refilling_counter
- update_interval: 1s
- - platform: hx711
- name: "HX711 raw value"
- id: hx711_raw_value
- internal: true
- dout_pin: GPIO8
- clk_pin: GPIO7
- gain: 128
- update_interval: 0.2s
- filters:
- - quantile:
- window_size: 10
- send_every: 1
- send_first_at: 1
- quantile: .8
- - platform: copy
- source_id: hx711_raw_value
- id: hx711_tare_value
- name: "Average value for taring"
- icon: mdi:weight-kilogram
- internal: false
- filters:
- - sliding_window_moving_average:
- window_size: 300
- send_every: 300
- send_first_at: 300
- - platform: copy
- source_id: hx711_raw_value
- id: hx711_raw_weight
- name: "Raw weight"
- internal: true
- unit_of_measurement: g
- accuracy_decimals: 0
- filters:
- - calibrate_linear:
- - 570380 -> 0
- - 1009300 -> 1000
- - platform: copy
- source_id: hx711_raw_weight
- id: hx711_value
- name: "Weight"
- state_class: "measurement"
- device_class: "weight"
- internal: false
- unit_of_measurement: g
- accuracy_decimals: 0
- icon: mdi:scale
- filters:
- - lambda: |-
- if (id(debug).state) {
- return x;
- }
- if (x <= 0.1) {
- if(x < -100){
- if(id(status).state != "Refilling" ){
- ESP_LOGI("custom", "Refilling" );
- id(status).publish_state("Refilling" );
- }
- id(refilling_counter).start();
- id(refilling_counter).reset();
- return 0;
- }
- x = 0;
- }
- if(id(previous_weight)==0) id(previous_weight)=x;
- if(id(previous_weight_eating)==0) id(previous_weight_eating)=x;
- if(id(status).state == "" ) id(status).publish_state("Idle" );
- if(id(status).state == "Refilling" ){
- if(id(refilling_counter).state < 5){
- ESP_LOGI("custom", "Refilling ended, waiting 5s before to report weight. Counter = %f", id(refilling_counter).state);
- return 0;
- }
-
- //5s since refill ended
- id(refilling_counter).stop();
- //Refresh last refill time
- id(last_refill_time).publish_state(id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S" ));
- id(last_refill_val) = id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S" );
- ESP_LOGI("custom", "Refilling ended, report new weight = %f", x);
- id(status).publish_state("Idle" );
- id(previous_weight)=x;
- return x;
- }
- if(fabs(id(previous_weight) - x) <= 2 && id(status).state != "Eating" ){
- ESP_LOGD("custom", "Small weight change, sending previous value" );
- return id(previous_weight);
- }
- //else{
-
- if(id(status).state != "Eating" ){
- ESP_LOGI("custom", "Eating" );
- id(status).publish_state("Eating" );
- id(previous_weight_eating) = -9999;
- }
-
- if(fabs(id(previous_weight_eating) - x) > 1 ){
- ESP_LOGI("custom", "Change of weight, reset eating counter. Last weight = %f / Current weight = %f", id(previous_weight_eating), x);
- id(previous_weight_eating) = x;
- id(eating_counter).start();
- id(eating_counter).reset();
- }
- if(id(status).state == "Eating" ){
- if(id(eating_counter).state < 30){
- ESP_LOGI("custom", "Eating ended, waiting 30s before to report weight. Counter = %f", id(eating_counter).state);
- return id(previous_weight);
- }
-
- //30s since refill ended
- id(eating_counter).stop();
- //Refresh last eating time
- id(last_eat_time).publish_state(id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S" ));
- id(last_eat_val) = id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S" );
-
- ESP_LOGI("custom", "Eating ended" );
- id(status).publish_state("Idle" );
- }
-
- ESP_LOGI("custom", "Report new weight = %f", x);
- id(quantity_eaten_val) += id(previous_weight) - x;
- id(quantity_eaten).publish_state(id(quantity_eaten_val));
- id(previous_weight)=x;
- return x;
-
- - platform: template
- name: "Quantity eaten"
- id: quantity_eaten
- unit_of_measurement: "g"
- state_class: "measurement"
- device_class: "weight"
- accuracy_decimals: 0
- icon: mdi:cat
- - platform: wifi_signal # Reports the WiFi signal strength/RSSI in dB
- name: "WiFi Signal dB"
- id: wifi_signal_db
- update_interval: 60s
- entity_category: "diagnostic"
- icon: mdi:wifi
- filters:
- - sliding_window_moving_average:
- window_size: 5
- send_every: 5
- send_first_at: 1
- - platform: copy # Reports the WiFi signal strength in %
- source_id: wifi_signal_db
- name: "WiFi Signal Percent"
- id: wifi_signal_percent
- filters:
- - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
- unit_of_measurement: "%"
- entity_category: "diagnostic"
- device_class: ""
- icon: mdi:wifi
- button:
- - platform: restart
- icon: mdi:power-cycle
- name: "ESP Reboot"
- - platform: template
- name: "Reset quantity eaten"
- icon: mdi:restore
- on_press:
- then:
- - globals.set:
- id: quantity_eaten_val
- value: "0"
- - sensor.template.publish:
- id: quantity_eaten
- state: "0"
|
Dans home assistant, ça remonte comme ça :
Debug c'est pour ne pas renvoyer les valeurs, et péter les historiques dans home assistant le temps de la config.
Croquettes restantes : quantité restantes de croquettes dans le réservoir
Date dernier remplissage : dernière fois que j'ai rempli
Date dernier repas : dernière fois que le chat a bouffé
Quantité croquettes mangées aujourd'hui : c'est calculé via un compteur de service dans home assistant, en se basant sur la quantité totale de croquettes mangées
Quantité mangée : quantité totale que le chat a bouffé depuis que j'ai fait ce distributeur
Statut : qui peut être "Idle", "Eating" ou "Refilling"
Valeur moyenne pour tare : moyenne sur les 5 dernières minutes de la valeur brut renvoyée par le capteur. Ca sert juste au départ pour calibrer le distributeur, cf les lignes 132 et 133, avec la valeur du capteur lorsque le distributeur est vide (0g) et avec un poids de 1000g. Ensuite ça calcule la quantité réelle selon ces 2 valeurs de calibration.
Si ça vous intéresse, à vous d'adapter
|