Skip to content

jsapede/boilervolume

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 

Repository files navigation

precision :

  • extraction eau chaude par le haut
  • appoint eau froide par le bas
  • 5 sondes dallas a 0% 25%, 50% 75% et 100% de hauteur
  • stratification des tempétaures + chauffage en partie basse du chauffe eau => en phase de chauffe si le bas se rechauffe plus vite que le haut il n'est pourtant pas exploitable => ajout de filtres sur les valeurs de temperatures aux niveaux superieurs pour éviter de comptabiliser ces volumes lors des phases de chauffe.
  • L'appoint réseau est considéré a 15°C sauf si la mesure au niveau zero donne une valeur inférieure
  • on calcule d'abord le volume d'eau utile c'edt à dire tout le volume dont la T° est >= 40°C
  • on calcule ensuite le volume exploitable, c'est à dire le volume équivalent dilué utilisable à 40°C (mitigeur), en considérant une dilution à l'eau du reseau

Stratégie de calcul :

  • on commence par le point le plus haut et on descend : l'eau chaude est soutirée en hauteur et l'appoint froid se fait en bas
  • pour chaque section de volume :
  • si la temperature du niveau le plus haut est < 40°C alors le volume n'est pas utile, ni exploitable
  • si la temperature du niveau le plus haut ET la temperature du niveau le plus bas sont >= 40°C alors tout le volume est utile et le volume exploitable est calulé à partie de la valeur moyenne de temperature sur la tranche
  • si la temperature du niveau le plus haut est >=40°C ET la temperature du niveau le plus bas <40°C alors on in interpole les temperatures et on calcule la proportion de la tranche de volume utile et exploitable

Sondes : Les sondes sont collées à la surface de la cuve, et leur mesure est faussée. On rajoute une calibration linéeaire en 2 points :

  • la temperature au niveau zero, stabilisée, quand le chauffe eau est a moitié chaud est égale à la température mesurée au réseau (prélèvement d'eau froide au robinet) => 14.9°C lu par la sonde en paroi et 10.9°c lu par la sonde dans le prélevement d'eau froide
  • La température au niveau 100 est la tempréture de soutirage deau chaude au robinet => 46.5°C lus par la sonde en paroi et 54.5°c lu par la sonde dans un prelevement d'eau chaude

il suffit de prélever dans un thermos et y tremper la sonde dallas

NB : les addressages des sodnes dallas "address: 0xbd3335d446b8a228" sont propres à chaque sonde, il faut checker dans les logs de l'esp pour avoir la bonne valeur

image


substitutions:
  device_name: "Chauffe Eau"
  dallas_hub_1_pin: GPIO13
  dallas_hub_2_pin: GPIO12
  dallas_hub_3_pin: GPIO14
  dallas_hub_4_pin: GPIO15
  dallas_hub_5_pin: GPIO4

esphome:
  name: "chauffe-eau"
  min_version: 2024.11.2
  build_path: build/chauffe-eau

esp32:
  board: esp32dev
  framework:
    type: arduino

# WiFi Configuration
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "${device_name}"
    password: !secret temp_chauffe_eau_admin

# Enable Web Server for local access
web_server:
  local: true
  port: 80

# Enable API for Home Assistant integration
api:
  encryption:
    key: !secret temp_chauffe_eau_api_key

# Logger Configuration
logger:
  level: DEBUG

# OTA (Over-the-Air) updates
ota:
  - platform: esphome
    password: !secret temp_chauffe_eau_admin

# Time Configuration (sync with Home Assistant)
time:
  - platform: homeassistant
    timezone: "Europe/Paris"
    id: homeassistant_time

# Binary Sensor for device status
binary_sensor:
  - platform: status
    name: "${device_name} Status"

# Button to restart the device
button:
  - platform: restart
    name: "${device_name} Restart"

# One-wire temperature sensors
one_wire:
  - platform: gpio
    id: dallas_hub_1
    pin: ${dallas_hub_1_pin}
  - platform: gpio
    id: dallas_hub_2
    pin: ${dallas_hub_2_pin}
  - platform: gpio  
    id: dallas_hub_3
    pin: ${dallas_hub_3_pin}
  - platform: gpio  
    id: dallas_hub_4
    pin: ${dallas_hub_4_pin}
  - platform: gpio  
    id: dallas_hub_5
    pin: ${dallas_hub_5_pin}




# Dallas Temperature Sensors
sensor:
  - platform: dallas_temp
    one_wire_id: dallas_hub_1
    address: 0xbd3335d446b8a228
    id: sensor_1
    name: "Temperature Niveau 75%"
    update_interval: 10s
    resolution: 12
    device_class: "temperature"
    state_class: "measurement"
    unit_of_measurement: "°C"
    icon: mdi:thermometer
    filters:
      - calibrate_linear:
         method: least_squares
         datapoints:
          # Map 0.0 (from sensor) to 1.0 (true value)
          - 14.9 -> 10.9
          - 46.5 -> 54.5

  - platform: dallas_temp
    one_wire_id: dallas_hub_2
    address: 0xcf79ddd446e17728
    id: sensor_2
    name: "Temperature Niveau 50%"
    update_interval: 10s
    resolution: 12
    device_class: "temperature"
    state_class: "measurement"
    unit_of_measurement: "°C"
    icon: mdi:thermometer
    filters:
      - calibrate_linear:
         method: least_squares
         datapoints:
          # Map 0.0 (from sensor) to 1.0 (true value)
          - 14.9 -> 10.9
          - 46.5 -> 54.5


  - platform: dallas_temp
    one_wire_id: dallas_hub_3
    address: 0xef1ff7d446a22628
    id: sensor_3
    name: "Temperature Niveau 25%"
    update_interval: 10s
    resolution: 12
    device_class: "temperature"
    state_class: "measurement"
    unit_of_measurement: "°C"
    icon: mdi:thermometer
    filters:
      - calibrate_linear:
         method: least_squares
         datapoints:
          # Map 0.0 (from sensor) to 1.0 (true value)
          - 14.9 -> 10.9
          - 46.5 -> 54.5


  - platform: dallas_temp
    one_wire_id: dallas_hub_4
    address: 0xe13ce10457ac2128
    id: sensor_4
    name: "Temperature Niveau 100%"
    update_interval: 10s
    resolution: 12
    device_class: "temperature"
    state_class: "measurement"
    unit_of_measurement: "°C"
    icon: mdi:thermometer
    filters:
      - calibrate_linear:
         method: least_squares
         datapoints:
          # Map 0.0 (from sensor) to 1.0 (true value)
          - 14.9 -> 10.9
          - 46.5 -> 54.5
      - clamp:
          min_value: 5
          max_value: 65
          ignore_out_of_range: true
      - sliding_window_moving_average:
          window_size: 5
          send_every: 6

  - platform: dallas_temp
    one_wire_id: dallas_hub_5
    address: 0x12839fb30a646128
    id: sensor_5
    name: "Temperature Niveau 0%"
    update_interval: 10s
    resolution: 12
    device_class: "temperature"
    state_class: "measurement"
    unit_of_measurement: "°C"
    icon: mdi:thermometer
    filters:
      - calibrate_linear:
         method: least_squares
         datapoints:
          # Map 0.0 (from sensor) to 1.0 (true value)
          - 14.9 -> 10.9
          - 46.5 -> 54.5


  - platform: template
    name: "Volume utile (> 40°C)"
    unit_of_measurement: "L"
    icon: mdi:gauge
    device_class: "volume"
    update_interval: 10s
    accuracy_decimals: 1
    lambda: |-
      float temp_ref = 40.0;
      float vol_ref = 25.0;
      float temp_reseau = 15.0;
      float temp_reseau_ref = 15.0;
      float vol_total = 300;
      float temp_75 = id(sensor_1).state;
      float temp_50 = id(sensor_2).state;
      float temp_25 = id(sensor_3).state;
      float temp_100 = id(sensor_4).state;
      float temp_0 = id(sensor_5).state;
      float tangente_100_75 = (temp_75 - temp_100) / vol_ref;
      float tangente_75_50 = (temp_50 - temp_75) / vol_ref;
      float tangente_50_25 = (temp_25 - temp_50) / vol_ref;
      float tangente_25_0 = (temp_0 - temp_25) / vol_ref;
      float temp_moy_100_75 = (temp_100 + temp_75) / 2.0;
      float temp_moy_75_50 = (temp_75 + temp_50) / 2.0;
      float temp_moy_50_25 = (temp_50 + temp_25) / 2.0;
      float temp_moy_25_0 = (temp_25 + temp_0) / 2.0;
      float vol_utile_100_75 = 0.0;
      float vol_utile_75_50 = 0.0;
      float vol_utile_50_25 = 0.0;
      float vol_utile_25_0 = 0.0;
      float vol_utile = 0.0;

      if (temp_0 < temp_reseau_ref) {
        temp_reseau = temp_0;
      } else {
        temp_reseau = temp_reseau_ref;
      }

      if (temp_100 >= temp_ref) {
        if (temp_75 >= temp_ref) {
          vol_utile_100_75 = vol_ref;
        } else {
          vol_utile_100_75 = (temp_ref-temp_100)/tangente_100_75;
          }
      } else {
        vol_utile_100_75 = 0.0;
        }

      if (temp_100 >=temp_ref) {
        if (temp_75 >= temp_ref) {
          if (temp_50 >= temp_ref) {
            vol_utile_75_50 = vol_ref;
          } else {
            vol_utile_75_50 = (temp_ref-temp_75)/tangente_75_50;
          }
        } else {
          vol_utile_75_50 = 0.0;
        }
      } else {
          vol_utile_75_50 = 0.0;
      }  

      if (temp_75 >= temp_ref and temp_100 >=temp_ref) {
        if (temp_50 >= temp_ref) {
          if (temp_25 >= temp_ref) {
            vol_utile_50_25 = vol_ref;
          } else {
            vol_utile_50_25 = (temp_ref-temp_50)/tangente_50_25;
          }
        } else {
          vol_utile_50_25 = 0.0;
        }
      } else {
          vol_utile_50_25 = 0.0;
      }      

      if (temp_50 >= temp_ref and temp_75 >= temp_ref and temp_100 >=temp_ref) {
        if (temp_25 >= temp_ref) {
          if (temp_0 >= temp_ref) {
            vol_utile_25_0 = vol_ref;
          } else {
            vol_utile_25_0 = (temp_ref-temp_25)/tangente_25_0;
          }
        } else {
          vol_utile_25_0 = 0.0;
        }
      } else {
          vol_utile_25_0 = 0.0;
      }

      vol_utile = (vol_utile_100_75 + vol_utile_75_50 + vol_utile_50_25 + vol_utile_25_0)*vol_total/100.0;
      return vol_utile;




  - platform: template
    name: "Volume exploitable (eq. 40°C)"
    unit_of_measurement: "L"
    icon: mdi:gauge
    device_class: "volume"
    update_interval: 10s
    accuracy_decimals: 1
    lambda: |-
      float temp_ref = 40.0;
      float vol_ref = 25.0;
      float temp_reseau = 15.0;
      float temp_reseau_ref = 15.0;
      float vol_total = 300;
      float temp_75 = id(sensor_1).state;
      float temp_50 = id(sensor_2).state;
      float temp_25 = id(sensor_3).state;
      float temp_100 = id(sensor_4).state;
      float temp_0 = id(sensor_5).state;
      float tangente_100_75 = (temp_75 - temp_100) / vol_ref;
      float tangente_75_50 = (temp_50 - temp_75) / vol_ref;
      float tangente_50_25 = (temp_25 - temp_50) / vol_ref;
      float tangente_25_0 = (temp_0 - temp_25) / vol_ref;
      float temp_moy_100_75 = (temp_100 + temp_75) / 2.0;
      float temp_moy_75_50 = (temp_75 + temp_50) / 2.0;
      float temp_moy_50_25 = (temp_50 + temp_25) / 2.0;
      float temp_moy_25_0 = (temp_25 + temp_0) / 2.0;
      float vol_expl_100_75 = 0.0;
      float vol_expl_75_50 = 0.0;
      float vol_expl_50_25 = 0.0;
      float vol_expl_25_0 = 0.0;
      float vol_expl = 0.0;

      if (temp_0 < temp_reseau_ref) {
        temp_reseau = temp_0;
      } else {
        temp_reseau = temp_reseau_ref;
      }

      if (temp_100 >= temp_ref) {
        if (temp_75 >= temp_ref) {
          vol_expl_100_75 = vol_ref * (1 + (temp_moy_100_75 - temp_ref)/(temp_ref - temp_reseau));
        } else {
          vol_expl_100_75 = ((temp_ref-temp_100)/tangente_100_75) * (1 + (temp_moy_100_75 - temp_ref)/(temp_ref - temp_reseau));
          }
      } else {
        vol_expl_100_75 = 0.0;
        }

      if (temp_100 >=temp_ref) {
        if (temp_75 >= temp_ref) {
          if (temp_50 >= temp_ref) {
            vol_expl_75_50 = vol_ref * (1 + (temp_moy_75_50 - temp_ref)/(temp_ref - temp_reseau));
          } else {
            vol_expl_75_50 = ((temp_ref-temp_75)/tangente_75_50) * (1 + (temp_moy_75_50 - temp_ref)/(temp_ref - temp_reseau));
          }
        } else {
          vol_expl_75_50 = 0.0;
        }
      } else {
          vol_expl_75_50 = 0.0;
      }

      if (temp_75 >= temp_ref and temp_100 >=temp_ref) {
        if (temp_50 >= temp_ref) {
          if (temp_25 >= temp_ref) {
            vol_expl_50_25 = vol_ref * (1 + (temp_moy_50_25 - temp_ref)/(temp_ref - temp_reseau));
          } else {
            vol_expl_50_25 = ((temp_ref-temp_50)/tangente_50_25) * (1 + (temp_moy_50_25 - temp_ref)/(temp_ref - temp_reseau));
          }
        } else {
          vol_expl_50_25 = 0.0;
        }
      } else {
          vol_expl_50_25 = 0.0;
      }


      if (temp_50 >= temp_ref and temp_75 >= temp_ref and temp_100 >=temp_ref) {
        if (temp_25 >= temp_ref) {
          if (temp_0 >= temp_ref) {
            vol_expl_25_0 = vol_ref * (1 + (temp_moy_25_0 - temp_ref)/(temp_ref - temp_reseau));
          } else {
            vol_expl_25_0 = ((temp_ref-temp_25)/tangente_25_0) * (1 + (temp_moy_25_0 - temp_ref)/(temp_ref - temp_reseau));
          }
        } else {
          vol_expl_25_0 = 0.0;
        }
      } else {
          vol_expl_25_0 = 0.0;
      }

      vol_expl = (vol_expl_100_75 + vol_expl_75_50 + vol_expl_50_25 + vol_expl_25_0)*vol_total/100.0;
      return vol_expl;



text_sensor:
  - platform: wifi_info
    ip_address:
      name: "${device_name} IP Address"
    mac_address:
      name: "${device_name} Mac Address"
    ssid:
      name: "${device_name} Wifi SSID"
    bssid:
      name: "${device_name} Wifi BSSID"




About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published