Advertisement
ClaudioGH

Codice per la gestione di una centralina idroponica

Dec 30th, 2024 (edited)
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
YAML 57.23 KB | Source Code | 0 0
  1. /*
  2.  * Questo codice è rilasciato sotto la licenza MIT.
  3.  *
  4.  * Copyright (c) [2024-2025] [ClaudioG]
  5.  *
  6.  * Youtube channel: https://www.youtube.com/@claudiog_4_hydroponic
  7.  *
  8.  * Con la presente si concede il permesso, gratuitamente, a chiunque ottenga una copia
  9.  * di questo software e dei file di documentazione associati (il "Software"),
  10.  * di utilizzare il Software senza restrizioni, inclusi, a titolo esemplificativo ma non esaustivo,
  11.  * i diritti di usare, copiare, modificare, unire, pubblicare, distribuire, concedere in sublicenza
  12.  * e/o vendere copie del Software, e di permettere alle persone a cui il Software è fornito
  13.  * di farlo, nel rispetto delle seguenti condizioni:
  14. *
  15.  * L'avviso di copyright sopra riportato e questo avviso di autorizzazione devono essere
  16.  * inclusi in tutte le copie o porzioni sostanziali del Software.
  17.  *
  18.  * IL SOFTWARE VIENE FORNITO "COSÌ COM'È", SENZA GARANZIA DI ALCUN TIPO,
  19.  * ESPRESSA O IMPLICITA, INCLUSE, MA NON SOLO, LE GARANZIE DI COMMERCIABILITÀ,
  20.  * IDONEITÀ PER UNO SCOPO PARTICOLARE E NON VIOLAZIONE. IN NESSUN CASO GLI AUTORI
  21.  * O I TITOLARI DEL COPYRIGHT SARANNO RESPONSABILI PER QUALSIASI RECLAMO, DANNO
  22.  * O ALTRA RESPONSABILITÀ, SIA IN UN'AZIONE CONTRATTUALE, ILLECITO O ALTRO,
  23.  * DERIVANTE DA, DA O IN CONNESSIONE CON IL SOFTWARE O L'USO O ALTRI
  24.  * RAPPORTI NEL SOFTWARE.
  25.  *
  26.  * Nota: Questo codice è stato sviluppato specificamente per l'ESP32.
  27.  */
  28.  
  29. /*
  30.  * This code is released under the MIT License.
  31.  *
  32.  * Copyright (c) [2024-2025] [ClaudioG]
  33.  *
  34.  * YouTube channel: https://www.youtube.com/@claudiog_4_hydroponic
  35.  *
  36.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  37.  * of this software and associated documentation files (the "Software"),
  38.  * to deal in the Software without restriction, including without limitation
  39.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  40.  * and/or sell copies of the Software, and to permit persons to whom the Software
  41.  * is furnished to do so, subject to the following conditions:
  42. *
  43.  * The above copyright notice and this permission notice shall be included in
  44.  * all copies or substantial portions of the Software.
  45.  *
  46.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  47.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  48.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  49.  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  50.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  51.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  52.  * OTHER DEALINGS IN THE SOFTWARE.
  53.  *
  54.  * Note: This code has been specifically developed for the ESP32.
  55.  */
  56.  
  57. esphome:
  58.     name: centralinapostazioneidroponica8 # Massimo 31 caratteri
  59.     friendly_name: "Centralina per la gestione dei dispositivi domotici della piattaforma idroponica 8"
  60.     # AL FINE DI EVITARE CHE I SENSORI LATO HA SIANO IN ERRORE A CAUSA DELLA MANCANZA DEL VALORE, SI ASSEGNA AL BOOT IL VALORE 0
  61.     on_boot:
  62.         priority: 800 # Si esegue all'avvio con priorità ALTA https://esphome.io/components/esphome.html#on-boot
  63.         then:
  64.             - sensor.template.publish:
  65.                 id: lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8
  66.                 state: 0.0
  67.             - sensor.template.publish:
  68.                 id: lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8
  69.                 state: 0.0
  70.             - sensor.template.publish:
  71.                 id: lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8
  72.                 state: 0.0
  73.             - sensor.template.publish:
  74.                 id: lastricosolare_conducibilitasoluzionefertilizzantepostazioneidroponica8
  75.                 state: 0.0
  76.  
  77. esp32:
  78.     board: esp32dev
  79.     framework:
  80.         type: arduino
  81.    
  82. wifi:
  83.     networks:
  84.     - ssid: !secret eolo_ssid
  85.       password: !secret eolo_wpa
  86.     - ssid: !secret iliad_ssid
  87.       password: !secret iliad_wpa
  88.     - ssid: !secret wind3_ssid
  89.       password: !secret wind3_wpa
  90.     manual_ip: # https://esphome.io/components/wifi.html#manual-ips
  91.         static_ip: 192.168.0.127
  92.         gateway: 192.168.0.1
  93.         subnet: 255.255.255.0
  94.         dns1: 8.8.8.8
  95.         dns2: 8.8.4.4
  96.     reboot_timeout: 1min # se ESP32 non si connette al wifi per 1 minuto, si riavvia
  97.     power_save_mode: none # https://esphome.io/components/wifi.html#power-save-mode
  98.     output_power: 20
  99.     on_connect:
  100.         then:
  101.         - globals.set:
  102.             id: sono_connesso_al_wifi
  103.             value: 'true'
  104.     on_disconnect:
  105.         then:
  106.         - globals.set:
  107.             id: sono_connesso_al_wifi
  108.             value: 'false'
  109.     ap:
  110.         ssid: !secret esp32_postazione_idroponica_8_fallback_ssid
  111.         password: !secret esp32_postazione_idroponica_8_fallback_password
  112.  
  113. captive_portal:
  114. api:
  115.     encryption:
  116.         key: !secret esp32_postazione_idroponica_8_api_encryption
  117.  
  118. ota:
  119.     - platform: esphome
  120.       password: !secret esp32_postazione_idroponica_8_ota_password
  121.  
  122. logger:
  123.   level: DEBUG
  124.  
  125. web_server:
  126.     port: 80
  127.  
  128. one_wire:
  129.   - platform: gpio
  130.     pin: GPIO4  
  131.  
  132. time:
  133.   - platform: homeassistant
  134.     id: homeassistant_time
  135.  
  136. switch:
  137.   - platform: gpio
  138.     pin: GPIO16  
  139.     name: "Pompa acido postazione idroponica 8"
  140.     icon: mdi:water-pump
  141.   - platform: gpio
  142.     pin: GPIO17  
  143.     name: "Pompa fertilizzante postazione idroponica 8"
  144.     icon: mdi:water-pump
  145.  
  146.   ###########################################################################################################
  147.   #          SENSORI DA DICHIARARE IN HOME ASSISTANT PER IL CORRETTO FUNZIONAMENTO DI QUESTA SKILL          #
  148.   #                                                                                                         #
  149.   # - input_number.lastricosolare_valorecompensazionetemperaturasoluzionefertilizzantepostazioneidroponica8 #
  150.   # - input_number.lastricosolare_valorecompensazionephgrezzosoluzionefertilizzantepostazioneidroponica8    #
  151.   # - input_number.lastricosolare_valorecompensazionetdspostazioneidroponica8                               #
  152.   #                                                                                                         #
  153.   ###########################################################################################################
  154.  
  155.  
  156. globals:
  157.  ###################################################################################################
  158.   #                                     VARIABILI GLOBALI                                           #
  159.   #                                                                                                 #
  160.   #    Sono variabili che mantengono il loro valore attuale anche quando l'ESP32 viene riavviato.   #
  161.   # Possono inoltre essere gestite all'interno di lambda diverse da quella in cui sono state create #
  162.   #    Se hanno l'attributo restore_value: true al riavvio riprendono il valore initial_value:     #
  163.   #                                                                                                 #
  164.   ###################################################################################################
  165.  
  166.   ###########################################################
  167.   # VARIABILI CREATE AD ESCLUSIVO USO E CONSUMO DELL'UTENTE #
  168.   ###########################################################
  169.  
  170.   ################################################################################################################
  171.   #                       DETERMINAZIONE DEL VALORE DI SOGLIA TRA LE 10 MISURAZIONI                              #
  172.   #                IL MIO GOAL E' IMPOSTARE UN VALORE LIMITE DI ±0,5 pH DALLA MEDIA DEI VALORI                   #
  173.   # QUESTO SIGNIFICA CHE TUTTI I VALORI CHE AVRANNO UN VALORE ±0,5 pH RISPETTO ALLA LORO MEDIA SARANNO SCARTATI. #
  174.   #     QUESTA VARIABILE LAVORA PERO' IN VOLT. QUINDI DOBBIAMO FARE LA FORMULA INVERSA DELLA LEGGE DI NERNST     #
  175.   #                                       0,5pH × 0,059 V/pH =0,0295V                                            #
  176.   #       SAPPIAMO CHE LA TENSIONE DI RIFERIMENTO E' 2,5V (PER pH 7), QUINDI LA SOGLIA DI ERRORE % SARA':        #
  177.   #                                          0.0295V / 2,5V  = 0.0118V                                           #
  178.   ################################################################################################################
  179.   - id: soglia_errore_massimo_ammesso_singola_lettura_grezza
  180.     type: float
  181.     restore_value: true
  182.     initial_value: '0.0118'
  183.  
  184.   #################################################################################################################
  185.   #                       DETERMINAZIONE DEL VALORE DI SOGLIA TRA 2 MISURAZIONI SUCCESSIVE                        #
  186.   #            IL MIO GOAL E' IMPOSTARE UN VALORE LIMITE DI ±1 pH RISPETTO ALLA MISURAZIONE PRECEDENTE            #
  187.   # QUESTO SIGNIFICA CHE SE IL VALORE DEL NUOVO PH E' ±1 pH RISPETTO A QUELLO DEL GIRO PRECEDENTE SARA' SCARTATO. #
  188.   #      QUESTA VARIABILE LAVORA PERO' IN VOLT. QUINDI DOBBIAMO FARE LA FORMULA INVERSA DELLA LEGGE DI NERNST     #
  189.   #                                         1 pH × 0,059 V/pH =0,059V                                             #
  190.   #          SAPPIAMO CHE LA TENSIONE DI RIFERIMENTO E' 2,5V (PER pH 7), QUINDI LA SOGLIA DI ERRORE SARA':        #
  191.   #                                           0.059V / 2,5V  = 0.0236V                                            #
  192.   #################################################################################################################
  193.  
  194.   - id: soglia_differenza_nuova_lettura_grezza_ammessa_ph
  195.     type: float
  196.     restore_value: true
  197.     initial_value: '0.0236'
  198.  
  199.   #################################################################################################################
  200.   #                     DETERMINAZIONE DEL VALORE DI SOGLIA TRA LE 10 MISURAZIONI DI TDS                          #
  201.   #                IL MIO GOAL E' IMPOSTARE UN VALORE LIMITE DI ±100 ppm DALLA MEDIA DEI VALORI                   #
  202.   # QUESTO SIGNIFICA CHE TUTTI I VALORI CHE AVRANNO UN VALORE ±100 ppm RISPETTO ALLA LORO MEDIA SARANNO SCARTATI. #
  203.   #                 QUESTA VARIABILE LAVORA PERO' IN VOLT. QUINDI DOBBIAMO FARE QUESTO CALCOLO:                   #
  204.   #      IL MIO STRUMENTO HA UN INTERVALLO DI MISURAZIONE TDS: 0 ~ 1000ppm E UN SEGNALE DI USCITA: 0 ~ 2.3V       #
  205.   #                    QUINDI TENSIONE(V)= (TDS(ppm)/1000(ppm))*2,3 ==> 100/1000*2,3 ==> 0,23V                    #
  206.   #################################################################################################################
  207.   - id: soglia_errore_massimo_ammesso_singola_lettura_grezza_tds
  208.     type: float
  209.     restore_value: true
  210.     initial_value: '0.23'
  211.  
  212.   #############################################################################################################
  213.   #                     DETERMINAZIONE DEL VALORE DI SOGLIA TRA 2 MISURAZIONI SUCCESSIVE DI TDS               #
  214.   #            IL MIO GOAL E' IMPOSTARE UN VALORE LIMITE DI ±500 ppm RISPETTO ALLA MISURAZIONE PRECEDENTE     #
  215.   # QUESTO SIGNIFICA CHE SE IL NUOVO VALORE E' ±500 ppm RISPETTO A QUELLO DEL GIRO PRECEDENTE SARA' SCARTATO. #
  216.   #                 QUESTA VARIABILE LAVORA PERO' IN VOLT. QUINDI DOBBIAMO FARE QUESTO CALCOLO:               #
  217.   #      IL MIO STRUMENTO HA UN INTERVALLO DI MISURAZIONE TDS: 0 ~ 1000ppm E UN SEGNALE DI USCITA: 0 ~ 2.3V   #
  218.   #                    QUINDI TENSIONE(V)= (TDS(ppm)/1000(ppm))*2,3 ==> 500/1000*2,3 ==> 1,15V                 #
  219.   #############################################################################################################
  220.  
  221.   - id: soglia_differenza_nuova_lettura_grezza_ammessa_tds
  222.     type: float
  223.     restore_value: true
  224.     initial_value: '1.15'
  225.  
  226.   #############################################################################################################
  227.   #                              FATTORE DI CONVERSIONE DA TDS A CONDUCIBILITA'                               #
  228.   #             IN GIRO HO TROVATO UN SACCO DI COSTANTI QUANTITATIVAMENTE DIVERSE LE UNE DALLE ALTRE          #
  229.   #                                                                                                           #
  230.   #   SUGGERISCO QUINDI DI PRENDERE LA PROPRIA PENNETTA, METTERLA IN UN BICCHIERE D'ACQUA, FARE STABILIZZARE  #
  231.   #       LA LETTURA DEL TDS, CAMBIARE LA VISUALIZZAZIONE DELLO STRUMENTO IN EC E POI FARE IL RAPPORTO:       #
  232.   #                    TDS (ppm)/EC(µS/cm) E METTERE IL RISULTATO NELLA VARIABILE QUA SOTTO                   #
  233.   #############################################################################################################
  234.  
  235.   - id: fattore_conversione_tds_conducibilita
  236.     type: float
  237.     restore_value: true
  238.     initial_value: '0.5'
  239.  
  240.   #######################################################################
  241.   #      DETERMINAZIONE DELLA SENZIBILITA' DELLA CELLA DI CARICO        #
  242.   # AL FINE DI AVERE LETTURE PIU' STABILI E MENO INFLUENZATE DAL RUMORE #
  243.   #       DEFINISCI QUI LA SENSIBILITA' DELLA CELLA DI CARICO IN KG     #                                                                                                    #
  244.   #                     E LA SUA CAPACITA' MASSIMA                      #
  245.   #######################################################################
  246.  
  247.   - id: sensibilita_cella_di_carico
  248.     type: int
  249.     restore_value: true  
  250.     initial_value: '1'
  251.  
  252.   - id: capacita_massima_vasca
  253.     type: int
  254.     restore_value: true  
  255.     initial_value: '50'
  256.  
  257.   - id: sono_connesso_al_wifi
  258.     type: bool
  259.     restore_value: true
  260.     initial_value: 'true'
  261.  
  262. ######################
  263. # VARIABILI TECNICHE #
  264. ######################
  265.  
  266.   - id: nuovo_valore_ph_grezzo_processato
  267.     type: float
  268.     restore_value: true
  269.     initial_value: '0.0'
  270.  
  271.   - id: nuovo_valore_tds_grezzo_processato
  272.     type: float
  273.     restore_value: true
  274.     initial_value: '0'
  275.  
  276.   - id: offset_tara_cella_di_carico
  277.     type: int
  278.     restore_value: false  
  279.     initial_value: '0'
  280.  
  281. button:
  282.     - platform: restart
  283.       name: "Forza riavvio ESP-32 postazione idroponica 8"
  284.       icon: "mdi:restart"
  285.      
  286.     - platform: template
  287.       name: "Tara cella di carico"
  288.       icon: "mdi:button-pointer"
  289.       on_press:
  290.         then:
  291.           - lambda: |-
  292.                 id(offset_tara_cella_di_carico) = id(lastricosolare_volumedellasoluzionefertilizzantepostazioneidroponica8).state;  // Sostituisci 1000.0 con il valore di offset desiderato
  293.                 ESP_LOGI("Cella di carico", "Impostata manualmente la tara a: %dKg", id(offset_tara_cella_di_carico));
  294.  
  295. sensor:
  296.   #####################################################################################
  297.    # SENSORI NECESSARI PER IMPORTARE I VALORI DEI SENSORI DA HOME ASSISTANT IN ESPHOME #
  298.    #####################################################################################
  299.   - platform: homeassistant
  300.     name: "Valore di compensazione della temperatura proveniente da Home Assistant per la postazione idroponica 8"
  301.     id: ha_compensazionetemperaturasoluzionefertilizzantepostazioneidroponica8
  302.     entity_id: input_number.lastricosolare_valorecompensazionetemperaturasoluzionefertilizzantepostazioneidroponica8
  303.     accuracy_decimals: 1
  304.     on_value: # Se cambio il valore della compensazione, cambia subito il valore visualizzato
  305.       then:
  306.         lambda: |-
  307.           if (id(ha_compensazionetemperaturasoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  308.             id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).publish_state(id(lastricosolare_temperaturagrezzasoluzionefertilizzantepostazioneidroponica8).state + id(ha_compensazionetemperaturasoluzionefertilizzantepostazioneidroponica8).state);
  309.           }
  310.  
  311.   - platform: homeassistant
  312.     name: "Valore di compensazione del pH proveniente da Home Assistant per la postazione idroponica 8"
  313.     id: ha_compensazionephsoluzionefertilizzantepostazioneidroponica8
  314.     entity_id: input_number.lastricosolare_valorecompensazionephgrezzosoluzionefertilizzantepostazioneidroponica8
  315.     accuracy_decimals: 1
  316.     on_value: # Se cambio il valore della compensazione, cambia subito il valore visualizzato
  317.       then:
  318.         lambda: |-
  319.           if (id(ha_compensazionephsoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  320.             id(lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(nuovo_valore_ph_grezzo_processato) + id(ha_compensazionephsoluzionefertilizzantepostazioneidroponica8).state);
  321.           }
  322.  
  323.   - platform: homeassistant
  324.     name: "Valore di compensazione del TDS proveniente da Home Assistant per la postazione idroponica 8"
  325.     id: ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8
  326.     entity_id: input_number.lastricosolare_valorecompensazionetdsgrezzosoluzionefertilizzantepostazioneidroponica8
  327.     accuracy_decimals: 0
  328.     on_value: # Se cambio il valore della compensazione, cambia subito il valore visualizzato
  329.       then:
  330.         lambda: |-
  331.           if (id(ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  332.             id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(nuovo_valore_tds_grezzo_processato) + id(ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8).state);
  333.           }
  334.          
  335.     ##############################
  336.     # SENSORI PROPRI DELL'ESP-32 #
  337.     ##############################
  338.   - platform: wifi_signal
  339.     id: intensita_segnale_wifi
  340.     name: "Intensità del segnale WiFi"
  341.     update_interval: 300s
  342.     icon: "mdi:wifi"
  343.     device_class: "signal_strength"
  344.     state_class: "measurement"
  345.     accuracy_decimals: 1
  346.    
  347.   - platform: dallas_temp
  348.     name: "Valore grezzo della temperatura della soluzione fertilizzante nella postazione idroponica 8"
  349.     id: lastricosolare_temperaturagrezzasoluzionefertilizzantepostazioneidroponica8
  350.     update_interval: 5min
  351.     internal: true # questo sensore non verrà esportato in home assistant
  352.     #unit_of_measurement: "°C"
  353.     #icon: "mdi:thermometer-water"
  354.     #device_class: "temperature"
  355.     #state_class: "measurement"
  356.     accuracy_decimals: 1
  357.  
  358.   - platform: adc
  359.     id: valore_ph_grezzo
  360.     name: "Valore pH grezzo"
  361.     pin: GPIO34
  362.     update_interval: 30s
  363.     internal: true
  364.     accuracy_decimals: 3
  365.     attenuation: 12db # https://esphome.io/components/sensor/adc.html#adc-esp32-attenuation
  366.     on_value:
  367.       then:
  368.         - lambda: |-
  369.             static float buffer_letture_V_ph[10]; // Buffer con 10 posizioni
  370.             static int indice_buffer_ph = 0; // Indice corrente nel buffer
  371.             static bool buffer_pieno_ph = false; // Flag per indicare se il buffer è stato riempito
  372.             static float ultimo_valore_V_grezza_processato_ph = 0; // Inizializza la variabile contenente la lettura di tensione precedente (o la prima del ciclo) a quella in corso
  373.             static float nuovo_valore_V_grezza_processato_ph = 0; // Inizializza la variabile contenente la nuova lettura di tensione
  374.             static int conteggio_cicli_con_valore_ph_tutti_fuori_media = 0; // Inizializza la variabile che conta le volte che lo strumento non può dare un output perchè tutti i valori misurati sono fuori media
  375.             static int conteggio_cicli_con_valore_ph_fuori_media = 0; // Inizializza la variabile che conta le volte che lo strumento non può dare un output aggiornato perchè il valore ponderato è fuori media
  376.  
  377.             // Resetta a 0 il valore di tutte le 10 posizioni del buffer quando deve riiniziare il giro
  378.             if (buffer_pieno_ph) {
  379.               for (int i = 0; i < 10; i++) {
  380.                  buffer_letture_V_ph[i] = 0.0;  // Reset di tutte le posizioni a 0
  381.               }
  382.               buffer_pieno_ph = false;
  383.               indice_buffer_ph = 0;
  384.             }
  385.             // Inserisce la nuova lettura grezza nel buffer
  386.             buffer_letture_V_ph[indice_buffer_ph] = id(valore_ph_grezzo).state;
  387.            
  388.             // Incrementa l'indice per la prossima lettura, riavvolge a 0 quando arriva a 10 azzerando l'array'
  389.             indice_buffer_ph++;
  390.            
  391.             if (indice_buffer_ph >= 10) {
  392.                 buffer_pieno_ph = true;
  393.  
  394.                 // Log dello stato del buffer
  395.                 ESP_LOGI("pHmetro", "STATO ATTUALE DEL BUFFER:");
  396.                 for (int i = 0; i < 10; i++) {
  397.                     ESP_LOGI("pHmetro", "Posizione n° %d: Valore: %.3f V", i, buffer_letture_V_ph[i]);
  398.                 }
  399.                
  400.                 ///////////////////////////////////////////////////////////////
  401.                 // CONTROLLO RISPETTO TOLLERANZA DI SOGLIA FRA LE 10 LETTURE //
  402.                 ///////////////////////////////////////////////////////////////
  403.  
  404.                 // Calcolo della media provvisoria
  405.                 float somma_valori_V_grezze_ph = 0;
  406.                 for (int i = 0; i < 10; i++) {
  407.                     somma_valori_V_grezze_ph += buffer_letture_V_ph[i];
  408.                 }
  409.                 float media_provvisoria_V_grezze_ph = somma_valori_V_grezze_ph / 10;
  410.  
  411.                 // Calcolo valore assoluto del fuori soglia per la lettura del pH grezzo
  412.                 float soglia_di_scarto_V_grezze_ph = media_provvisoria_V_grezze_ph * id(soglia_errore_massimo_ammesso_singola_lettura_grezza);
  413.                 ESP_LOGI("pHmetro","CONTROLLO DEL RISPETTO DELLA TOLLERANZA DI SOGLIA FRA LE 10 LETTURE");
  414.                 ESP_LOGI("pHmetro", "Essendo la soglia di scarto calcolata di ±%.3f V e la media delle 10 misurazioni di %.3f V,", soglia_di_scarto_V_grezze_ph, media_provvisoria_V_grezze_ph);
  415.                 ESP_LOGI("pHmetro", "rimangono solamente questi valori validi:");
  416.                 // Calcolo finale della media ponderata escludendo valori fuori soglia
  417.                 somma_valori_V_grezze_ph = 0;
  418.                 int conteggio_valori_V_in_soglia_ph = 0;
  419.                
  420.                 ESP_LOGI("pHmetro","Valori utilizzabili rimasti:");
  421.                 for (int i = 0; i < 10; i++) {
  422.                     if (fabs(buffer_letture_V_ph[i] - media_provvisoria_V_grezze_ph) <= soglia_di_scarto_V_grezze_ph) { //fabs= valore assoluto
  423.                         ESP_LOGI("pHmetro", "Posizione n° %d: Valore: %.3f V", i, buffer_letture_V_ph[i]);
  424.                         somma_valori_V_grezze_ph += buffer_letture_V_ph[i];
  425.                         conteggio_valori_V_in_soglia_ph++;
  426.                     }
  427.                 }
  428.                 if (conteggio_valori_V_in_soglia_ph == 0) {
  429.                     ESP_LOGI("pHmetro", "          NESSUNO!!");
  430.                 }
  431.                 // a questo punto somma_valori_V_grezze_ph conterrà la somma dei SOLI valori in soglia in numero quantificati dalla variabile conteggio_valori_V_in_soglia_ph
  432.  
  433.                 if (fabs(ultimo_valore_V_grezza_processato_ph) > 0.0001) { // Non primo giro N.B. utilizzato fabs e il numero float a causa delle piccole grandezze in gioco
  434.                     if (conteggio_valori_V_in_soglia_ph > 0) { // Se c'è almeno un valore valido, calcola la media
  435.                         conteggio_cicli_con_valore_ph_tutti_fuori_media = 0; // Resetta il contatore dei cicli fuori media perchè devono essere CONSECUTIVI
  436.                         // Calcola il nuovo valore processato
  437.                         nuovo_valore_V_grezza_processato_ph = somma_valori_V_grezze_ph / conteggio_valori_V_in_soglia_ph;
  438.                         ESP_LOGI("pHmetro", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_ph , nuovo_valore_V_grezza_processato_ph);
  439.                     } else {
  440.                         ESP_LOGI("pHmetro", "Numero di volte che TUTTE le letture vengono calcolate fuori soglia: %d", (conteggio_cicli_con_valore_ph_tutti_fuori_media + 1));
  441.                         conteggio_cicli_con_valore_ph_tutti_fuori_media++; // Incrementa il contatore di cicli fuori media
  442.                         if (conteggio_cicli_con_valore_ph_tutti_fuori_media == 5) {
  443.                             ESP_LOGI("pHmetro", "Superati i 5 cicli con tutte le letture fuori media!");
  444.                             id(invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_ph).execute(); //Manda la notifica sul cellulare
  445.                             conteggio_cicli_con_valore_ph_tutti_fuori_media = 0; // Reset della variabile
  446.                             nuovo_valore_V_grezza_processato_ph = media_provvisoria_V_grezze_ph; // Prende per buono il valore grezzo medio
  447.                             ESP_LOGI("pHmetro", "Utilizzato come valore di fallback il valore grezzo medio: %.3f V", nuovo_valore_V_grezza_processato_ph);
  448.                         } else {
  449.                             nuovo_valore_V_grezza_processato_ph =  ultimo_valore_V_grezza_processato_ph; // Ripropone la misurazione grezza precedente
  450.                             ESP_LOGI("pHmetro", "Utilizzato come valore di fallback la misurazione grezza precedente: %.3f V", nuovo_valore_V_grezza_processato_ph);
  451.                         }
  452.                     }
  453.                 } else {
  454.                     ESP_LOGI("pHmetro", "Questo è il primo giro della giostra!!");
  455.                     ESP_LOGI("pHmetro", "Utilizzato il valore della media provvisoria grezza: %.3f V", media_provvisoria_V_grezze_ph);
  456.                     nuovo_valore_V_grezza_processato_ph = media_provvisoria_V_grezze_ph; // Prende il valore grezzo medio, non avendo, allo stato, altri dati a disposizione
  457.                 }
  458.                
  459.                 ///////////////////////////////////////////////////////////////////////
  460.                 // CONTROLLO RISPETTO TOLLERANZA DI SOGLIA CON LA LETTURA PRECEDENTE //
  461.                 ///////////////////////////////////////////////////////////////////////
  462.                 ///////////////////////////////////////////////////////////////////////
  463.                 //  DA NON FARE NEL PERIODO TRA  IL RABBOCCO E LA PRIMA IRRIGAZIONE  //
  464.                 ///////////////////////////////////////////////////////////////////////
  465.  
  466.                 auto now = id(homeassistant_time).now(); // Ottieni l'orario corrente
  467.                 if (now.hour >= 3 && now.hour < 6) {
  468.                     ESP_LOGI("pHmetro", "FASCIA ORARIA INERDETTA AL CONTROLLO DEL RISPETTO DELLA SOGLIA CON LA LETTURA PRECEDENTE.");
  469.                 } else {
  470.                     ESP_LOGI("pHmetro","CONTROLLO DEL RISPETTO DELLA TOLLERANZA DI SOGLIA FINALE");
  471.                     ESP_LOGI("pHmetro", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_ph , nuovo_valore_V_grezza_processato_ph);
  472.                     if (fabs(ultimo_valore_V_grezza_processato_ph) > 0.0001) { // Non primo giro N.B. utilizzato fabs e il numero float a causa delle piccole grandezze in gioco
  473.                         ESP_LOGI("pHmetro", "Valore di scarto %.3f V Soglia impostata: %.3f V", fabs(nuovo_valore_V_grezza_processato_ph - ultimo_valore_V_grezza_processato_ph) / ultimo_valore_V_grezza_processato_ph, id(soglia_differenza_nuova_lettura_grezza_ammessa_ph));
  474.                         if ((fabs(nuovo_valore_V_grezza_processato_ph - ultimo_valore_V_grezza_processato_ph) / ultimo_valore_V_grezza_processato_ph) > id(soglia_differenza_nuova_lettura_grezza_ammessa_ph)) { //Soglia NON rispettata)
  475.                             ESP_LOGI("pHmetro", "Il nuovo valore misurato è fuori dalla soglia impostata rispetto al valore precedente!!");
  476.                             ESP_LOGI("pHmetro", "Numero di volte che il valore viene calcolato fuori soglia: %d", conteggio_cicli_con_valore_ph_fuori_media + 1);
  477.                             conteggio_cicli_con_valore_ph_fuori_media++; // incrementa valore letture fuori media
  478.                             if (conteggio_cicli_con_valore_ph_fuori_media == 5) {
  479.                                 ESP_LOGI("pHmetro", "Superati i 5 cicli con la lettura fuori media!");
  480.                                 id(invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_ph).execute(); //Manda la notifica sul cellulare
  481.                                 conteggio_cicli_con_valore_ph_fuori_media = 0; // resetta la variabile
  482.                                 // fa passare il valore attuale di nuovo_valore_V_grezza_processato_ph
  483.                             } else {
  484.                                 nuovo_valore_V_grezza_processato_ph = ultimo_valore_V_grezza_processato_ph;
  485.                                 ESP_LOGI("pHmetro", "Utilizzato come valore di fallback la misurazione grezza precedente: %.3f V", nuovo_valore_V_grezza_processato_ph);                            // Fa passare il valore precedente)
  486.                             }
  487.                         } else {
  488.                             ESP_LOGI("pHmetro", "Il nuovo valore misurato %.3f V rientra nella soglia impostata rispetto al valore precedente.", nuovo_valore_V_grezza_processato_ph);
  489.                             conteggio_cicli_con_valore_ph_fuori_media = 0; // resetta la variabile perchè i cicli devono essere CONSECUTIVI
  490.                         }
  491.                     } else {
  492.                         ESP_LOGI("pHmetro", "Questo è il primo giro della giostra!!");
  493.                         ESP_LOGI("pHmetro", "Utilizzato la misurazione grezza attuale: %.3f V", nuovo_valore_V_grezza_processato_ph);
  494.                     }
  495.                 }
  496.                 ESP_LOGI("pHmetro", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_ph , nuovo_valore_V_grezza_processato_ph);
  497.                 ultimo_valore_V_grezza_processato_ph = nuovo_valore_V_grezza_processato_ph;
  498.                  
  499.                  
  500.                 /////////////////////////////////////////////////////////////////////////////////////
  501.                 //                        TRASFORMAZIONE DEI VOLT IN pH                            //
  502.                 // NEL NOSTRO CONTESTO DI FUNZIONAMENTO DEL pHMETRO (pH= 0 ==> 0V E pH= 14 ==> 5V) //
  503.                 //    DOBBIAMO CALCOLARE LA VARIAZIONE ∆V RISPETTO AL pH CON LA SEGUENTE FORMULA: //
  504.                 //                         ∆V = (5V - 0 V) / 14 = 0,357                            //
  505.                 //                DATO CHE SAPPIAMO CHE A pH= 7 LA TENSIONE E' DI 2,5 V            //
  506.                 //         E DATO CHE VOGLIAMO UTILIZZARE UNA SCALA LINEARE DEI VALORI V E pH      //
  507.                 //      LA FORMULA COMUNEMENTE USATA PER I pHMETRI COMMERCIALI E' LA SEGUENTE:    //
  508.                 //                                    2,5 - Vmisurata                              //
  509.                 //                        pH = 7.0 - ------------------                            //
  510.                 //                                         0,357                                   //
  511.                 /////////////////////////////////////////////////////////////////////////////////////
  512.                  
  513.                 ESP_LOGI("pHmetro", "Ultimo valore in tensione: %.3f V ",nuovo_valore_V_grezza_processato_ph);  
  514.                 // Calcola il pH basato sull'ultima lettura grezza
  515.                 id(nuovo_valore_ph_grezzo_processato) = (7.0 - ((2.5 - nuovo_valore_V_grezza_processato_ph) / 0.357));
  516.                 ESP_LOGI("pHmetro", "Valore pH calcolato: %.3f ",id(nuovo_valore_ph_grezzo_processato));  
  517.                  
  518.                 /////////////////////////////////////////////////////////////////////////////////////////////////
  519.                 //            PONDERAZIONE DEL VALORE DEL pH IN RELAZIONE ALLA TEMPERATURA DEL FLUIDO          //
  520.                 //  LA TEMPERATURA INFLUISCE SULL'ATTIVITA' IONICA DELLE SOLUZIONI E GLI ELETTRODI DEL pH SONO //
  521.                 //    SENSIBILI ALLA TEMPERATURA PERCHE' LA MISURA DEL POTENZIALE ELETTRICO GENERATO VARIA IN  //
  522.                 //       FUNZIONE DELLA TEMPERATURA DELLA SOLUZIONE, IN ACCORDO CON L'EQUAZIONE DI NERNST      //
  523.                 //                       LA FORMULA CORRENTEMENTE UTILIZZATA E':                              //
  524.                 //        pHcompensato= pHmisurato + ((Triferimento-Tattuale) * fattore di compensazione)      //
  525.                 //  DOVE: Triferimento= 25° e fattore di compensazione = 0,03 (VALORE EMPIRICO DI USO COMUNE)  //
  526.                 /////////////////////////////////////////////////////////////////////////////////////////////////
  527.  
  528.                 if (id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  529.                   id(nuovo_valore_ph_grezzo_processato) +=  ((25 - id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).state) * 0.03);
  530.                   ESP_LOGI("pHmetro", "Valore pH ponderato con la temperatura: %.3f Temperatura rilevata: %.1f°C", id(nuovo_valore_ph_grezzo_processato), id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).state);              
  531.                 } else {
  532.                   ESP_LOGI("pHmetro", "ATTENZIONE !! Valore pH NON ponderato con la temperatura il cui valore non è allo stato disponibile.");
  533.                 }
  534.                  
  535.                 // AGGIUNGE IL VALORE DI COMPENSAZIONE PROVENIENTE DA HOME ASSISTANT
  536.                 if (id(ha_compensazionephsoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  537.                     id(nuovo_valore_ph_grezzo_processato) +=  id(ha_compensazionephsoluzionefertilizzantepostazioneidroponica8).state;
  538.                     ESP_LOGI("pHmetro", "Valore pH ponderato con Home Assistant: %.3f Valore correttivo: %.1f",id(nuovo_valore_ph_grezzo_processato),id(ha_compensazionephsoluzionefertilizzantepostazioneidroponica8).state);  
  539.                 }
  540.  
  541.                 // Verifica che il pH sia valido
  542.                 if (isnan(id(nuovo_valore_ph_grezzo_processato)) || id(nuovo_valore_ph_grezzo_processato) < 0.0 || id(nuovo_valore_ph_grezzo_processato) > 14.0) {
  543.                   ESP_LOGW("pHmetro", "Valore pH non valido: %.1f", id(nuovo_valore_ph_grezzo_processato));
  544.                   id(lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8).state);  // Pubblica il valore precendete
  545.                 } else {
  546.                   ESP_LOGI("pHmetro", "Valore pH reale: %.1f ",id(nuovo_valore_ph_grezzo_processato));  
  547.                   id(lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(nuovo_valore_ph_grezzo_processato)); // Pubblica il valore corretto
  548.                 }
  549.             }
  550.  
  551.   - platform: adc
  552.     pin: GPIO35
  553.     id: valore_tds_grezzo
  554.     name: "Valore TDS grezzo"
  555.     update_interval: 30s
  556.     internal: true
  557.     accuracy_decimals: 0
  558.     attenuation: 12db
  559.     on_value:
  560.       then:
  561.         - lambda: |-
  562.             static float buffer_letture_V_tds[10]; // Buffer con 10 posizioni
  563.             static int indice_buffer_tds = 0; // Indice corrente nel buffer
  564.             static bool buffer_pieno_tds = false; // Flag per indicare se il buffer è stato riempito
  565.             static float ultimo_valore_V_grezza_processato_tds = 0; // Inizializza la variabile contenente la lettura precedente (o la prima del ciclo) a quella in corso
  566.             static float nuovo_valore_V_grezza_processato_tds = 0; // Inizializza la variabile contenente la nuova lettura di tensione
  567.             static int conteggio_cicli_con_valore_tds_tutti_fuori_media = 0; // Inizializza la variabile che conta le volte che lo strumento non può dare un output perchè tutti i valori misurati sono fuori media
  568.             static int conteggio_cicli_con_valore_tds_fuori_media = 0; // Inizializza la variabile che conta le volte che lo strumento non può dare un output aggiornato perchè il valore ponderato è fuori media
  569.  
  570.             // Resetta a 0 il valore di tutte le 10 posizioni del buffer quando deve riiniziare il giro
  571.             if (buffer_pieno_tds) {
  572.               for (int i = 0; i < 10; i++) {
  573.                  buffer_letture_V_tds[i] = 0.0;  // Reset di tutte le posizioni a 0
  574.               }
  575.               buffer_pieno_tds = false;
  576.               indice_buffer_tds = 0;
  577.             }
  578.             // Inserisce la nuova lettura grezza nel buffer
  579.             buffer_letture_V_tds[indice_buffer_tds] = id(valore_tds_grezzo).state;
  580.            
  581.             // Incrementa l'indice per la prossima lettura
  582.             indice_buffer_tds++;
  583.          
  584.  
  585.             if (indice_buffer_tds >= 10) {
  586.                 buffer_pieno_tds = true;
  587.                 ESP_LOGI("sensore_TDS", "STATO ATTUALE DEL BUFFER:");
  588.                 for (int i = 0; i < 10; i++) {
  589.                   ESP_LOGI("sensore_TDS", "Posizione %d: %.3f V", i, buffer_letture_V_tds[i]);
  590.                 }
  591.  
  592.                 ///////////////////////////////////////////////////////////////
  593.                 // CONTROLLO RISPETTO TOLLERANZA DI SOGLIA FRA LE 10 LETTURE //
  594.                 ///////////////////////////////////////////////////////////////
  595.                  
  596.                 // Calcolo della media provvisoria
  597.                 float somma_valori_V_grezze_tds = 0;
  598.                 for (int i = 0; i < 10; i++) {
  599.                   somma_valori_V_grezze_tds += buffer_letture_V_tds[i];
  600.                 }
  601.                 float media_provvisoria_V_grezze_tds = somma_valori_V_grezze_tds / 10;
  602.                  // Calcolo valore assoluto del fuori soglia per la lettura del pH grezzo
  603.                 float soglia_di_scarto_V_grezze_tds = media_provvisoria_V_grezze_tds * id(soglia_errore_massimo_ammesso_singola_lettura_grezza_tds);
  604.                 ESP_LOGI("sensore_TDS","CONTROLLO DEL RISPETTO DELLA TOLLERANZA DI SOGLIA FRA LE 10 LETTURE");
  605.                 ESP_LOGI("sensore_TDS", "Essendo la soglia di scarto calcolata di ±%.3f V e la media delle 10 misurazioni di %.3f V,", soglia_di_scarto_V_grezze_tds, media_provvisoria_V_grezze_tds);
  606.                 ESP_LOGI("sensore_TDS", "rimangono solamente questi valori validi:");
  607.  
  608.                 // Calcolo finale della media ponderata escludendo valori fuori soglia
  609.                 somma_valori_V_grezze_tds = 0;
  610.                 int conteggio_valori_V_in_soglia_tds = 0;
  611.                 ESP_LOGI("sensore_TDS","Valori utilizzabili rimasti:");
  612.                 for (int i = 0; i < 10; i++) {
  613.                   if (fabs(buffer_letture_V_tds[i] - media_provvisoria_V_grezze_tds) <= soglia_di_scarto_V_grezze_tds) { //fabs= valore assoluto
  614.                     ESP_LOGI("sensore_TDS", "Posizione n° %d: Valore: %.3f V", i, buffer_letture_V_tds[i]);
  615.                     somma_valori_V_grezze_tds += buffer_letture_V_tds[i];
  616.                     conteggio_valori_V_in_soglia_tds++;
  617.                   }
  618.                 }
  619.                
  620.                 if (conteggio_valori_V_in_soglia_tds == 0) {
  621.                   ESP_LOGI("sensore_TDS", "          NESSUNO!!");
  622.                 }
  623.                 // a questo punto somma_valori_V_grezze_tds conterrà la somma dei SOLI valori in soglia in numero quantificati dalla variabile conteggio_valori_V_in_soglia_ph
  624.                 if (fabs(ultimo_valore_V_grezza_processato_tds) > 0.0001) { // Non primo giro N.B. utilizzato fabs e il numero float a causa delle piccole grandezze in gioco
  625.                     if (conteggio_valori_V_in_soglia_tds > 0) { // Se c'è almeno un valore valido, calcola la media
  626.                         conteggio_cicli_con_valore_tds_tutti_fuori_media = 0; // Resetta il contatore dei cicli fuori media perchè devono essere CONSECUTIVI
  627.                         // Calcola il nuovo valore processato
  628.                         nuovo_valore_V_grezza_processato_tds = somma_valori_V_grezze_tds / conteggio_valori_V_in_soglia_tds;
  629.                         ESP_LOGI("sensore_TDS", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_tds , nuovo_valore_V_grezza_processato_tds);
  630.                     } else {
  631.                         ESP_LOGI("sensore_TDS", "Numero di volte che TUTTE le letture vengono calcolate fuori soglia: %d", (conteggio_cicli_con_valore_tds_tutti_fuori_media + 1));
  632.                         conteggio_cicli_con_valore_tds_tutti_fuori_media++; // Incrementa il contatore di cicli fuori media
  633.                         if (conteggio_cicli_con_valore_tds_tutti_fuori_media == 5) {
  634.                             ESP_LOGI("sensore_TDS", "Superati i 5 cicli con tutte le letture fuori media!");
  635.                             id(invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_tds).execute(); //Manda la notifica sul cellulare
  636.                             conteggio_cicli_con_valore_tds_tutti_fuori_media = 0; // Reset della variabile
  637.                             nuovo_valore_V_grezza_processato_tds = media_provvisoria_V_grezze_tds; // Prende per buono il valore grezzo medio
  638.                             ESP_LOGI("sensore_TDS", "Utilizzato come valore di fallback il valore grezzo medio: %.3f V", nuovo_valore_V_grezza_processato_tds);
  639.                         } else {
  640.                             nuovo_valore_V_grezza_processato_tds =  ultimo_valore_V_grezza_processato_tds; // Ripropone la misurazione grezza precedente
  641.                             ESP_LOGI("sensore_TDS", "Utilizzato come valore di fallback la misurazione grezza precedente: %.3f V", nuovo_valore_V_grezza_processato_tds);
  642.                         }
  643.                     }
  644.                 } else {
  645.                     ESP_LOGI("sensore_TDS", "Questo è il primo giro della giostra!!");
  646.                     ESP_LOGI("sensore_TDS", "Utilizzato il valore della media provvisoria grezza: %.3f V", media_provvisoria_V_grezze_tds);
  647.                     nuovo_valore_V_grezza_processato_tds = media_provvisoria_V_grezze_tds; // Prende il valore grezzo medio, non avendo, allo stato, altri dati a disposizione
  648.                 }
  649.  
  650.                 ///////////////////////////////////////////////////////////////////////
  651.                 // CONTROLLO RISPETTO TOLLERANZA DI SOGLIA CON LA LETTURA PRECEDENTE //
  652.                 ///////////////////////////////////////////////////////////////////////
  653.                 ///////////////////////////////////////////////////////////////////////
  654.                 //  DA NON FARE NEL PERIODO TRA  IL RABBOCCO E LA PRIMA IRRIGAZIONE  //
  655.                 ///////////////////////////////////////////////////////////////////////
  656.  
  657.                 auto now = id(homeassistant_time).now(); // Ottieni l'orario corrente
  658.                 if (now.hour >= 3 && now.hour < 6) {
  659.                   ESP_LOGI("pHmetro", "FASCIA ORARIA INERDETTA AL CONTROLLO DEL RISPETTO DELLA SOGLIA CON LA LETTURA PRECEDENTE.");
  660.                 } else {
  661.                   ESP_LOGI("sensore_TDS","CONTROLLO DEL RISPETTO DELLA TOLLERANZA DI SOGLIA FINALE");
  662.                   ESP_LOGI("sensore_TDS", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_tds , nuovo_valore_V_grezza_processato_tds);
  663.                   if (fabs(ultimo_valore_V_grezza_processato_tds) > 0.0001) { // Non primo giro N.B. utilizzato fabs e il numero float a causa delle piccole grandezze in gioco
  664.                       ESP_LOGI("sensore_TDS", "Valore di scarto %.3f V Soglia impostata: %.3f V", fabs(nuovo_valore_V_grezza_processato_tds - ultimo_valore_V_grezza_processato_tds) / ultimo_valore_V_grezza_processato_tds, id(soglia_differenza_nuova_lettura_grezza_ammessa_tds));
  665.                       if ((fabs(nuovo_valore_V_grezza_processato_tds - ultimo_valore_V_grezza_processato_tds) / ultimo_valore_V_grezza_processato_tds) > id(soglia_differenza_nuova_lettura_grezza_ammessa_tds)) { //Soglia NON rispettata)
  666.                           ESP_LOGI("sensore_TDS", "Il nuovo valore misurato è fuori dalla soglia impostata rispetto al valore precedente!!");
  667.                           ESP_LOGI("sensore_TDS", "Numero di volte che il valore viene calcolato fuori soglia: %d", conteggio_cicli_con_valore_tds_fuori_media + 1);
  668.                           conteggio_cicli_con_valore_tds_fuori_media++; // incrementa valore letture fuori media
  669.                           if (conteggio_cicli_con_valore_tds_fuori_media == 5) {
  670.                               ESP_LOGI("sensore_TDS", "Superati i 5 cicli con la lettura fuori media!");
  671.                               conteggio_cicli_con_valore_tds_fuori_media = 0; // resetta la variabile
  672.                               id(invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_tds).execute(); //Manda la notifica sul cellulare
  673.                               // fa passare il valore attuale di nuovo_valore_V_grezza_processato_tds
  674.                           } else {
  675.                               nuovo_valore_V_grezza_processato_tds = ultimo_valore_V_grezza_processato_tds;
  676.                               ESP_LOGI("sensore_TDS", "Utilizzato come valore di fallback la misurazione grezza precedente: %.3f V", nuovo_valore_V_grezza_processato_tds);
  677.                               // Fa passare il valore precedente)
  678.                           }
  679.                       } else {
  680.                           ESP_LOGI("sensore_TDS", "Il nuovo valore misurato %.3f V rientra nella soglia impostata rispetto al valore precedente.", nuovo_valore_V_grezza_processato_tds);
  681.                           conteggio_cicli_con_valore_tds_fuori_media = 0; // resetta la variabile perchè i cicli devono essere CONSECUTIVI
  682.                       }
  683.                   } else {
  684.                       ESP_LOGI("sensore_TDS", "Questo è il primo giro della giostra!!");
  685.                       ESP_LOGI("sensore_TDS", "Utilizzato la misurazione grezza attuale: %.3f V", nuovo_valore_V_grezza_processato_tds);
  686.                   }
  687.                 }
  688.                 ESP_LOGI("sensore_TDS", "Ultimo valore grezzo processato: %.3f V ==> Nuovo valore grezzo processato: %.3f V",ultimo_valore_V_grezza_processato_tds, nuovo_valore_V_grezza_processato_tds);
  689.                 ultimo_valore_V_grezza_processato_tds = nuovo_valore_V_grezza_processato_tds;
  690.                
  691.  
  692.                 //////////////////////////////////////////////////////////////////////////////////////
  693.                 //                        TRASFORMAZIONE DEI VOLT IN TDS                            //
  694.                 //           NEL NOSTRO CONTESTO DI FUNZIONAMENTO DELLO STRUMENTO ABBIAMO:         //
  695.                 //               RANGE TDS: 0~1000ppm E UN SEGNALE DI USCITA: 0~2,3V                //
  696.                 // QUINDI TDS= (TENSIONE (V) /2,3 (V)) * 1000ppm ==> TENSIONE(V) * (1000ppm/2,3(V)) //
  697.                 //                             TDS= TENSIONE (V) * 435                              //
  698.                 //////////////////////////////////////////////////////////////////////////////////////
  699.  
  700.                 id(nuovo_valore_tds_grezzo_processato) = nuovo_valore_V_grezza_processato_tds * 435.0 ;
  701.                 ESP_LOGI("sensore_TDS", "Valore TDS calcolato dalla tensione: %.1fppm", id(nuovo_valore_tds_grezzo_processato));
  702.  
  703.                 /////////////////////////////////////////////////////////////////////////////////////////////////////
  704.                 //             PONDERAZIONE DEL VALORE DEL TDS IN RELAZIONE ALLA TEMPERATURA DEL FLUIDO            //
  705.                 //             LA TEMPERATURA INFLUISCE SULLA  CONDUTTIVITA' ELETTRICA E QUINDI SUL TDS            //
  706.                 //                            LA FORMULA CORRENTEMENTE UTILIZZATA E':                             //
  707.                 //      TDScompensato= TDSmisurato * (1 + (fattore di compensazione *(Tattuale-Triferimento))      //
  708.                 // DOVE: Triferimento= 25° e fattore di compensazione = 0,019 (VALORE DI USO COMUNE IN IDROPONICA) //
  709.                 /////////////////////////////////////////////////////////////////////////////////////////////////////
  710.  
  711.                 if (id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  712.                 id(nuovo_valore_tds_grezzo_processato) *= (1+(0.019*(id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).state -25)));
  713.                 ESP_LOGI("sensore_TDS", "Valore TDS ponderato con la temperatura: %.1fppm Temperatura rilevata: %.1f°C", id(nuovo_valore_tds_grezzo_processato), id(lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8).state);
  714.                 } else {
  715.                 ESP_LOGI("sensore_TDS", "ATTENZIONE !! Valore TDS NON ponderato con la temperatura il cui valore non è allo stato disponibile.");
  716.                 }
  717.  
  718.                 // AGGIUNGE IL VALORE DI COMPENSAZIONE PROVENIENTE DA HOME ASSISTANT
  719.                 if (id(ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  720.                   id(nuovo_valore_tds_grezzo_processato) +=  id(ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8).state;
  721.                   ESP_LOGI("sensore_TDS", "Valore TDS ponderato con la compensazione da Home Assistant: %.1f ppm Valore correttivo: %.1fppm", id(nuovo_valore_tds_grezzo_processato), id(ha_compensazionetdssoluzionefertilizzantepostazioneidroponica8).state);
  722.                 }
  723.                 // Verifica che il TDS sia valido
  724.                 if (isnan(id(nuovo_valore_tds_grezzo_processato)) || id(nuovo_valore_tds_grezzo_processato) < 0.0 || id(nuovo_valore_tds_grezzo_processato) > 1000) {
  725.                 ESP_LOGI("sensore_TDS", "Valore TDS non valido: %.1f", id(nuovo_valore_tds_grezzo_processato));
  726.                 id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).state);  // Ripubblica il valore precendete
  727.                 } else {
  728.                 ESP_LOGI("sensore_TDS", "Valore TDS finale: %.2f", id(nuovo_valore_tds_grezzo_processato));
  729.                 id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).publish_state(id(nuovo_valore_tds_grezzo_processato)); // Pubblica il valore corretto
  730.                 }
  731.                 }
  732.  
  733.   - platform: hx711
  734.     id: lastricosolare_volumedellasoluzionefertilizzantepostazioneidroponica8
  735.     name: "Litri di soluzione fertilizzante nella postazione idroponica numero 8"
  736.     dout_pin: GPIO21
  737.     clk_pin: GPIO22
  738.     gain: 64
  739.     accuracy_decimals: 0
  740.     update_interval: 10s
  741.     filters:
  742.         - calibrate_linear:
  743.             method: exact
  744.             datapoints:
  745.         - offset:
  746.         - lambda: |-
  747.             ESP_LOGI("Cella di carico", "Valore peso grezzo letto: %dKg ", (int)x);
  748.             static int ultimo_valore_peso_valido = 0;      // Ultimo valore letto
  749.             if ((int)(abs((int)x - (int)id(offset_tara_cella_di_carico) - (int)ultimo_valore_peso_valido) >= (int)id(sensibilita_cella_di_carico)) && !isnan(x)) { // Controlla se la variazione rispetto all'ultimo valore supera la sensibilità dello strumento
  750.                 if (((int)x - (int)id(offset_tara_cella_di_carico)) < 0 || ((int)x - (int)id(offset_tara_cella_di_carico)) > (int)(id(capacita_massima_vasca))) { // Se il valore è negativo o maggiore della capacità impostata, lo ignora
  751.                     ESP_LOGI("Cella di carico", "Valore peso ponderato forzato al precedente: %dKg perchè il valore netto risultante è fuori range!!", ultimo_valore_peso_valido);
  752.                 } else {
  753.                     ultimo_valore_peso_valido = (int)x - (int)id(offset_tara_cella_di_carico); // Aggiorna il valore
  754.                     ESP_LOGI("Cella di carico", "Valore peso ponderato: %dKg con tara di: %dKg ACCETTATO!!", ultimo_valore_peso_valido, (int)id(offset_tara_cella_di_carico));
  755.                 }
  756.             } else {
  757.                 ESP_LOGI("Cella di carico", "Valore peso ponderato: %dKg con tara di: %dKg SCARTATO!!", ultimo_valore_peso_valido, (int)id(offset_tara_cella_di_carico));
  758.             }
  759.             return (int)ultimo_valore_peso_valido;
  760. #            return (((int)ultimo_valore_peso_valido * 2)/1.02); // doppia cisterna più compensazione peso specifico per ottenere i litri
  761.        
  762.    
  763.    
  764.    #####################################################################################
  765.    # SENSORI NECESSARI PER ESPORTARE I VALORI DEI SENSORI DA ESPHOME IN HOME ASSISTANT #
  766.    #####################################################################################
  767.  
  768.   - platform: template
  769.     id: lastricosolare_valoretemperaturaponderatasoluzionefertilizzantepostazioneidroponica8
  770.     name: "Valore ponderato della temperatura della soluzione fertilizzante nella postazione idroponica numero 8"
  771.     internal: false # questo sensore verrà esportato in home assistant
  772.     #unit_of_measurement: "°C"
  773.     icon: "mdi:thermometer-water"
  774.     #device_class: "temperature"
  775.     #state_class: "measurement"
  776.     accuracy_decimals: 1
  777.     lambda: |-
  778.       if (id(ha_compensazionetemperaturasoluzionefertilizzantepostazioneidroponica8).has_state()) { // solo se ha un valore valido
  779.         return id(lastricosolare_temperaturagrezzasoluzionefertilizzantepostazioneidroponica8).state + id(ha_compensazionetemperaturasoluzionefertilizzantepostazioneidroponica8).state;
  780.       } else {
  781.         return id(lastricosolare_temperaturagrezzasoluzionefertilizzantepostazioneidroponica8).state;
  782.       }
  783.  
  784.   - platform: template
  785.     id: lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8
  786.     name: "Valore ponderato del pH della soluzione fertilizzante nella postazione idroponica numero 8"
  787.     internal: false # questo sensore verrà esportato in home assistant
  788.     icon: "mdi:ph"
  789.     device_class: "ph"
  790.     state_class: "measurement"
  791.     accuracy_decimals: 1
  792.     lambda: |-
  793.       // Restituisce semplicemente il valore che è stato passato dal sensore fisico
  794.       return (int(id(lastricosolare_valorephponderatosoluzionefertilizzantepostazioneidroponica8).state));
  795.      
  796.   - platform: template
  797.     id: lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8
  798.     name: "Valore ponderato del TDS della soluzione fertilizzante nella postazione idroponica numero 8"
  799.     internal: false # questo sensore verrà esportato in home assistant
  800.     #unit_of_measurement: "ppm"
  801.     state_class: "measurement"
  802.     accuracy_decimals: 0
  803.     lambda: |-
  804.       // Restituisce semplicemente il valore che è stato passato dal sensore fisico
  805.       return (int(id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).state));
  806.  
  807.   - platform: template
  808.     id: lastricosolare_conducibilitasoluzionefertilizzantepostazioneidroponica8
  809.     name: "Conducibilità della soluzione fertilizzante nella postazione idroponica numero 8"
  810.     internal: false # questo sensore verrà esportato in home assistant
  811.     #unit_of_measurement: "µS/cm"
  812.     state_class: "measurement"
  813.     accuracy_decimals: 0
  814.     lambda: |-
  815.       return (int(id(lastricosolare_valoretdsponderatosoluzionefertilizzantepostazioneidroponica8).state / id(fattore_conversione_tds_conducibilita)));
  816.  
  817.  
  818. binary_sensor:
  819.    ###########################################################################################
  820.    # BINARY_SENSOR NECESSARI PER IMPORTARE I VALORI DEI SENSORI DA HOME ASSISTANT IN ESPHOME #
  821.    ###########################################################################################
  822.    
  823.    ####################################
  824.    # BINARY_SENSOR PROPRI DELL'ESP-32 #
  825.    ####################################
  826.   - platform: template
  827.     name: "L'ESP32 della postazione idroponica 8 è connesso al WiFi"
  828.     id: esp32_postazione_idroponica_8_connesso_wifi
  829.     lambda: 'return id(sono_connesso_al_wifi);'
  830.     icon: 'mdi:wifi'
  831.    
  832.    ###########################################################################################
  833.    # BINARY_SENSOR NECESSARI PER ESPORTARE I VALORI DEI SENSORI DA ESPHOME IN HOME ASSISTANT #
  834.    ###########################################################################################
  835.  
  836. text_sensor:
  837.    #########################################################################################
  838.    # TEXT_SENSOR NECESSARI PER IMPORTARE I VALORI DEI SENSORI DA HOME ASSISTANT IN ESPHOME #
  839.    #########################################################################################
  840.  
  841.    ##################################
  842.    # TEXT_SENSOR PROPRI DELL'ESP-32 #
  843.    ##################################
  844.    
  845.   - platform: wifi_info
  846.     ssid:
  847.       name: "WiFi SSID postazione idroponica 8"
  848.  
  849.      
  850.    #########################################################################################
  851.    # TEXT_SENSOR NECESSARI PER ESPORTARE I VALORI DEI SENSORI DA ESPHOME IN HOME ASSISTANT #
  852.    #########################################################################################
  853.  
  854. script:
  855.     - id: invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_ph
  856.       then:
  857.         - homeassistant.service:
  858.             service: notify.mobile_app_cellulare_claudio
  859.             data:
  860.               title: "PROBLEMA CON IL SENSORE DEL pH"
  861.               message: "Il pHmetro ha superato i 5 cicli consecutivi con letture sempre fuori soglia!"
  862.  
  863.     - id: invia_notifica_superati_5_cicli_consecutivi_di_letture_fuori_media_tds
  864.       then:
  865.         - homeassistant.service:
  866.             service: notify.mobile_app_cellulare_claudio
  867.             data:
  868.               title: "PROBLEMA CON IL SENSORE DELLA CONDUCIBILITA'"
  869.               message: "Il conducimetro ha superato i 5 cicli consecutivi con letture sempre fuori soglia!"
Tags: ESP32
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement