Älykkäämpää suunnittelua

Home Assistant ESP32 Robotti-imurin käynnistys releellä

https://youtu.be/1ggEFDM_PC0

ESP32n koodi:

esphome:
  name: robot2

esp32:
  board: mhetesp32minikit
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "T8lbN/mj+xxJcGRnYcdVCWDh4aGOUBKAA+1y8+ut8wM="

ota:
  - platform: esphome
    password: "f76aa4ecb929327969ea7c0567839087"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.110
    gateway: 192.168.1.1
    subnet: 255.255.255.0
    
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Robot2 Fallback Hotspot"
    password: "5Lf8XVYmqCl4"

captive_portal:

switch:
  - platform: gpio
    name: "KYTKINR2"
    pin: 16
    inverted: False
    restore_mode: RESTORE_DEFAULT_OFF

Imurin automaatiot:

- id: '1742839773020'
  alias: Robot 2 Start to vacum
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - input_button.start_vacuum
    from:
  conditions: []
  actions:
  - sequence:
    - type: turn_on
      device_id: f46a1851c8924e532596ac5cfc4f8356
      entity_id: 7dba5e29c23b5cde41d06ef8e28ff155
      domain: switch
    - delay:
        hours: 0
        minutes: 0
        seconds: 1
        milliseconds: 0
    - action: switch.turn_off
      metadata: {}
      data: {}
      target:
        entity_id: switch.kytkinr2
  mode: single
- id: '1742840644556'
  alias: Robot 2 time to clean
  description: ''
  triggers:
  - trigger: time
    at: input_datetime.robot_2_time
  conditions:
  - condition: template
    value_template: '{{ now().weekday() in [3, 5] }}'
  actions:
  - action: automation.trigger
    metadata: {}
    data:
      skip_condition: true
    target:
      entity_id: automation.robot_2_start_to_vacum
  mode: single
Home Assistant ESP32 Liesituuletin

Huomasin jälkeenpäin, että sisääntulot on paras eristää optisesti. Liesikuvun rajakytkin ehti rikkoa suoraan kytketyn inputin, vaikka painike toimi moitteetta. Syynä on ilmeisesti mikrokytkimen huono suojaus ja siitä syntyvät ylijännitepiikit; pelkkä pulldown-vastus ei auttanut. Lisäsin sisääntulojen eteen releet, eikä häiriö enää pääse vaurioittamaan elektroniikkaa. Laitan myöhemmin kuvan kytkennästä.

https://youtu.be/bBfUzBJguxY

https://youtu.be/3ZkpkSAF66E

ESP32n koodi:

esphome:
  name: liesituuletin
  friendly_name: Liesituuletin

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "wb9G2GeoRdi0f6yKWphQqolwfEqhGLkw3Ar9pFWo0Uk="

ota:
  - platform: esphome
    password: "8751b2228cd287410e301b0aa7b91460"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.112
    gateway: 192.168.1.1
    subnet: 255.255.255.0
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Liesituuletin Fallback Hotspot"
    password: "dlRviN1IILuN"

captive_portal:


switch:
  - platform: gpio
    name: "LT-Valo"
    pin: 32
    inverted: False
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: gpio
    name: "LT-T1"
    pin: 33
    inverted: False
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: gpio
    name: "LT-T2"
    pin: 25
    inverted: False
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: gpio
    name: "LT-T3"
    pin: 26
    inverted: False
    restore_mode: RESTORE_DEFAULT_OFF

binary_sensor:
  - platform: gpio
    pin:
      number: 19
      mode: INPUT_PULLUP
    name: "Huuva"
    device_class: opening
    filters:
      - invert:
      - delayed_on: 50ms
      - delayed_off: 50ms
  - platform: gpio
    pin:
      number: 5
      mode: INPUT_PULLUP
    name: "Power"
    device_class: opening
    filters:
      - invert:
      - delayed_on: 50ms
      - delayed_off: 50ms
sensor:
  - platform: dht
    pin: 21
    model: DHT22
    temperature:
      name: "Lämpötila Huuva"
    humidity:
      name: "Kosteus Huuva"
    update_interval: 6s

Liesituulettimen Automaatiot:

- id: '1745089202276'
  alias: LIESI - Valo
  description: ''
  triggers:
  - type: opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
    domain: binary_sensor
    trigger: device
  - type: not_opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
    domain: binary_sensor
    trigger: device
  conditions: []
  actions:
  - if:
    - type: is_open
      condition: device
      device_id: 1bec4ae8ee9a09c1148d7e626234df49
      entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
      domain: binary_sensor
    then:
    - type: turn_on
      device_id: 1bec4ae8ee9a09c1148d7e626234df49
      entity_id: a01b8a72147e981776abc67366f8f237
      domain: switch
    else:
    - type: turn_off
      device_id: 1bec4ae8ee9a09c1148d7e626234df49
      entity_id: a01b8a72147e981776abc67366f8f237
      domain: switch
  mode: single
- id: '1745091641469'
  alias: LIESI - Syötön päälle laitto
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - binary_sensor.liesituuletin_huuva
    from:
  - trigger: state
    entity_id:
    - timer.liesi_aika
    to: idle
  - type: opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: 7d55476b80cf26df67250d12886baa9d
    domain: binary_sensor
    trigger: device
  - type: not_opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: 7d55476b80cf26df67250d12886baa9d
    domain: binary_sensor
    trigger: device
  conditions: []
  actions:
  - if:
    - condition: and
      conditions:
      - condition: state
        entity_id: binary_sensor.liesituuletin_huuva
        state: 'on'
      - type: is_temperature
        condition: device
        device_id: 1bec4ae8ee9a09c1148d7e626234df49
        entity_id: f57c06e691a2238beff9a2ecafa6cf2d
        domain: sensor
        below: 80
      - condition: or
        conditions:
        - condition: state
          entity_id: timer.liesi_aika
          state: active
        - type: is_open
          condition: device
          device_id: 1bec4ae8ee9a09c1148d7e626234df49
          entity_id: 7d55476b80cf26df67250d12886baa9d
          domain: binary_sensor
    then:
    - action: switch.turn_on
      metadata: {}
      data: {}
      target:
        entity_id: switch.liesi
    else:
    - action: switch.turn_off
      metadata: {}
      data: {}
      target:
        entity_id: switch.liesi
  mode: single
- id: '1745091959952'
  alias: LIESI - TIMERI
  description: ''
  triggers:
  - type: opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
    domain: binary_sensor
    trigger: device
  conditions: []
  actions:
  - action: timer.start
    metadata: {}
    data: {}
    target:
      entity_id: timer.liesi_aika
  mode: single
- id: '1745093289166'
  alias: LIESI - Kokkaaminen liian kallista, ylilämpö tai PALO
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - sensor.nordpool_kwh_fi_eur_10_10_0255
    from:
  - trigger: state
    entity_id:
    - sensor.liesituuletin_l_mp_tila_huuva
  conditions: []
  actions:
  - if:
    - condition: or
      conditions:
      - condition: numeric_state
        entity_id: sensor.nordpool_kwh_fi_eur_10_10_0255
        above: 0.2
      - type: is_temperature
        condition: device
        device_id: 1bec4ae8ee9a09c1148d7e626234df49
        entity_id: f57c06e691a2238beff9a2ecafa6cf2d
        domain: sensor
        above: 60
      - condition: and
        conditions:
        - type: is_temperature
          condition: device
          device_id: 1bec4ae8ee9a09c1148d7e626234df49
          entity_id: f57c06e691a2238beff9a2ecafa6cf2d
          domain: sensor
          above: 60
        - type: is_humidity
          condition: device
          device_id: 1bec4ae8ee9a09c1148d7e626234df49
          entity_id: ab2fcf8c37206288024c8462112f52bf
          domain: sensor
          below: 1
        alias: PALO
    then:
    - action: automation.turn_off
      metadata: {}
      data:
        stop_actions: true
      target:
        entity_id:
        - automation.liesi_paalle_laitto
        - automation.liesi_timeri
    - action: switch.turn_off
      metadata: {}
      data: {}
      target:
        entity_id: switch.liesi
    else:
    - action: automation.turn_on
      metadata: {}
      data: {}
      target:
        entity_id:
        - automation.liesi_paalle_laitto
        - automation.liesi_timeri
  mode: single
- id: '1234567890'
  alias: LIESI - LT1-3
  description: Kytkee tuuletinnopeudet tarkkojen kosteustasojen mukaan
  triggers:
  - entity_id: sensor.liesituuletin_kosteus_huuva
    trigger: state
  - type: opened
    device_id: 1bec4ae8ee9a09c1148d7e626234df49
    entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
    domain: binary_sensor
    trigger: device
  conditions: []
  actions:
  - if:
    - type: is_open
      condition: device
      device_id: 1bec4ae8ee9a09c1148d7e626234df49
      entity_id: cf2a5d78b221d1c674e4e7bc65f11d23
      domain: binary_sensor
    then:
    - choose:
      - conditions:
        - condition: numeric_state
          entity_id: sensor.liesituuletin_kosteus_huuva
          below: 48.9
        sequence:
        - action: switch.turn_off
          metadata: {}
          data: {}
          target:
            entity_id:
            - switch.liesituuletin_lt_t1
            - switch.liesituuletin_lt_t2
            - switch.liesituuletin_lt_t3
      - conditions:
        - condition: numeric_state
          entity_id: sensor.liesituuletin_kosteus_huuva
          above: 49
          below: 69.9
        sequence:
        - target:
            entity_id: switch.liesituuletin_lt_t1
          action: switch.turn_on
          data: {}
        - action: switch.turn_off
          metadata: {}
          data: {}
          target:
            entity_id:
            - switch.liesituuletin_lt_t2
            - switch.liesituuletin_lt_t3
      - conditions:
        - condition: numeric_state
          entity_id: sensor.liesituuletin_kosteus_huuva
          above: 70
          below: 89.9
        sequence:
        - target:
            entity_id: switch.liesituuletin_lt_t2
          action: switch.turn_on
          data: {}
        - action: switch.turn_off
          metadata: {}
          data: {}
          target:
            entity_id:
            - switch.liesituuletin_lt_t1
            - switch.liesituuletin_lt_t3
      - conditions:
        - condition: numeric_state
          entity_id: sensor.liesituuletin_kosteus_huuva
          above: 90
        sequence:
        - target:
            entity_id: switch.liesituuletin_lt_t3
          action: switch.turn_on
          data: {}
        - action: switch.turn_off
          metadata: {}
          data: {}
          target:
            entity_id:
            - switch.liesituuletin_lt_t1
            - switch.liesituuletin_lt_t2
    else:
    - action: switch.turn_off
      metadata: {}
      data: {}
      target:
        entity_id:
        - switch.liesituuletin_lt_t2
        - switch.liesituuletin_lt_t1
        - switch.liesituuletin_lt_t3
  mode: single
Home Assistant ESP32 Liesituuletin ilman assistanttia Standalone

Tällä liesituuletin toimii ilman Home Assistanttia. Eli:

  • Liesituuletin menee kosteuden mukaan eri asetuksiin
  • Valo menee päälle, kun huuvan aukaisee ja menee pois päältä 60 minuutin päästä
  • Lieden syöttö kannattaa tässä laittaa päälle, kun valo on päällä & huuva on auki & lämpötila on alle 50
  • Tai jos haluat helpottaa asiaa, niin lieden syöttö on silloin päällä, kun valo on päällä.

https://youtu.be/VLxtS6g5gSk

esphome:
  name: heatmoisture32
  friendly_name: HeatMoisture32

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "sxMeMDktASd3HbXHg2+vI/9JgA7p4oJ7sgck5WV5s0Q="

ota:
  - platform: esphome
    password: "5d16be6948890fbcb045b4bbc3d34695"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.116
    gateway: 192.168.1.1
    subnet: 255.255.255.0
  ap:
    ssid: "Heatmoisture32 Fallback Hotspot"
    password: "pogulGFhDJuj"

captive_portal:

# --- Muokkaa näitä arvoja yhdestä paikasta ---
globals:
  - id: temp_threshold
    type: float
    initial_value: '21.0'
  - id: humidity_threshold
    type: float
    initial_value: '60.0'
  - id: temp_hysteresis
    type: float
    initial_value: '0.1'
  - id: humidity_hysteresis
    type: float
    initial_value: '0.1'
# ------------------------------------------------

switch:
  - platform: gpio
    name: "vara"
    pin: 17
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: vara_switch

  - platform: gpio
    name: "Kompura"
    pin: 15
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: kompura_switch

  - platform: gpio
    name: "Heat"
    pin: 18
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: heat_switch

  - platform: gpio
    name: "Start"
    pin: 19
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: start_switch

  - platform: template
    name: "EN"
    id: en_switch
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF

sensor:
  - platform: dht
    pin: 21
    model: DHT22
    update_interval: 6s
    temperature:
      id: lampotila_HM
      name: "Lämpötila HM"
    humidity:
      id: kosteus_HM
      name: "Kosteus HM"

interval:
  - interval: 6s
    then:
      - lambda: |-
          const float temp = id(lampotila_HM).state;
          const float hum  = id(kosteus_HM).state;

          const bool valid_temp = !isnan(temp);
          const bool valid_hum  = !isnan(hum);

          if (!id(en_switch).state) {
            id(start_switch).turn_off();
            id(kompura_switch).turn_off();
            id(heat_switch).turn_off();
            return;
          }

          // HEAT: hysteresis
          if (valid_temp) {
            if (temp < (id(temp_threshold) - id(temp_hysteresis))) {
              id(heat_switch).turn_on();
            } else if (temp >= id(temp_threshold)) {
              id(heat_switch).turn_off();
            }
          } else {
            id(heat_switch).turn_off();
          }

          // KOMPURA: hysteresis
          if (valid_hum) {
            if (hum > (id(humidity_threshold) + id(humidity_hysteresis))) {
              id(kompura_switch).turn_on();
            } else if (hum <= id(humidity_threshold)) {
              id(kompura_switch).turn_off();
            }
          } else {
            id(kompura_switch).turn_off();
          }

          // START: päälle vain jos molemmat anturit kelvollisia ja HEAT tai KOMPURA on päällä
          if (valid_temp && valid_hum && (id(heat_switch).state || id(kompura_switch).state)) {
            id(start_switch).turn_on();
          } else {
            id(start_switch).turn_off();
          }
Home Assistant ESP32, kosteuden poistaja ja lämmitin. Automaatio ESP:ssä ja lupa HomeAssistantista.

ESP32 wroom

esphome:
  name: heatmoisture32
  friendly_name: HeatMoisture32

esp32:
  board: esp32dev
  framework:
    type: esp-idf

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "sxMeMDktASd3HbXHg2+vI/9JgA7p4oJ7sgck5WV5s0Q="

ota:
  - platform: esphome
    password: "5d16be6948890fbcb045b4bbc3d34695"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.116
    gateway: 192.168.1.1
    subnet: 255.255.255.0
  ap:
    ssid: "Heatmoisture32 Fallback Hotspot"
    password: "pogulGFhDJuj"

captive_portal:

# --- Muokkaa näitä arvoja yhdestä paikasta ---
globals:
  - id: temp_threshold
    type: float
    initial_value: '21.0'
  - id: humidity_threshold
    type: float
    initial_value: '60.0'
  - id: temp_hysteresis
    type: float
    initial_value: '0.1'
  - id: humidity_hysteresis
    type: float
    initial_value: '0.1'
# ------------------------------------------------

switch:
  - platform: gpio
    name: "vara"
    pin: 17
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: vara_switch

  - platform: gpio
    name: "Kompura"
    pin: 15
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: kompura_switch

  - platform: gpio
    name: "Heat"
    pin: 18
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: heat_switch

  - platform: gpio
    name: "Start"
    pin: 19
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    id: start_switch

  - platform: template
    name: "EN"
    id: en_switch
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF

sensor:
  - platform: dht
    pin: 21
    model: DHT22
    update_interval: 6s
    temperature:
      id: lampotila_HM
      name: "Lämpötila HM"
    humidity:
      id: kosteus_HM
      name: "Kosteus HM"

interval:
  - interval: 6s
    then:
      - lambda: |-
          const float temp = id(lampotila_HM).state;
          const float hum  = id(kosteus_HM).state;

          const bool valid_temp = !isnan(temp);
          const bool valid_hum  = !isnan(hum);

          if (!id(en_switch).state) {
            id(start_switch).turn_off();
            id(kompura_switch).turn_off();
            id(heat_switch).turn_off();
            return;
          }

          // HEAT: hysteresis
          if (valid_temp) {
            if (temp < (id(temp_threshold) - id(temp_hysteresis))) {
              id(heat_switch).turn_on();
            } else if (temp >= id(temp_threshold)) {
              id(heat_switch).turn_off();
            }
          } else {
            id(heat_switch).turn_off();
          }

          // KOMPURA: hysteresis
          if (valid_hum) {
            if (hum > (id(humidity_threshold) + id(humidity_hysteresis))) {
              id(kompura_switch).turn_on();
            } else if (hum <= id(humidity_threshold)) {
              id(kompura_switch).turn_off();
            }
          } else {
            id(kompura_switch).turn_off();
          }

          // START: päälle vain jos molemmat anturit kelvollisia ja HEAT tai KOMPURA on päällä
          if (valid_temp && valid_hum && (id(heat_switch).state || id(kompura_switch).state)) {
            id(start_switch).turn_on();
          } else {
            id(start_switch).turn_off();
          }

Sitten pitää antaa ESP:een EN-switchille vain käsky HomeAssistantista, että se voi mennä päälle. Itse tein vain automaation, että kun sähkön hinta on kaikkinensa alle 0,15 senttiä, niin laite saa mennä päälle.

- id: '1761507912269'
  alias: Kylpyhuoneen HM
  description: ''
  triggers:
  - trigger: state
    entity_id:
    - sensor.nordpool_kwh_fi_eur_10_10_0255
  conditions: []
  actions:
  - if:
    - condition: numeric_state
      entity_id: sensor.nordpool_kwh_fi_eur_10_10_0255
      below: 0.15
    then:
    - type: turn_on
      device_id: b00e27d77c9db2aa7f59fdbf30a7ef90
      entity_id: a9b3d54df472cb0b4e12e6271041a1d7
      domain: switch
    else:
    - type: turn_off
      device_id: b00e27d77c9db2aa7f59fdbf30a7ef90
      entity_id: a9b3d54df472cb0b4e12e6271041a1d7
      domain: switch
  mode: single
- id: '1761774163581'
  alias: Restart
  description: ''
  triggers:
  - trigger: time
    at: '23:30:00'
    weekday:
    - sun
    - mon
    - tue
    - wed
    - thu
    - fri
    - sat
  conditions: []
  actions:
  - action: hassio.host_reboot
    metadata: {}
    data: {}
  mode: single
Home Assistant ESP32, WC, Standalone

Home Assistant ESP32 vessan automatisointi)(YOUTUBE-LINKKI)
esphome:
  name: wc1k
  friendly_name: WC1k

  on_boot:
    priority: -100
    then:
      - delay: 10s
      - lambda: |-
          id(boot_ready) = true;

esp32:
  board: esp32dev
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "dwTs6psCg6DptpESE9X592cmp/rju67fizVilVBQCLw="

ota:
  - platform: esphome
    password: "4dc33851fc30d99628d02d6086cd701d"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Wc1K Fallback Hotspot"
    password: "Zesoxt9B6l4u"

captive_portal:

i2c:
  sda: 21
  scl: 22
  scan: true
  id: bus_a

####################
# GLOBALS
####################
globals:
  - id: boot_ready
    type: bool
    restore_value: no
    initial_value: 'false'

  - id: wc_kosteus
    type: float
    restore_value: no
    initial_value: '0.0'

  - id: wc_valo
    type: float
    restore_value: no
    initial_value: '0.0'

  - id: wc_ultra_osumat
    type: int
    restore_value: no
    initial_value: '0'

  - id: pistorasia_paalla
    type: bool
    restore_value: no
    initial_value: 'false'

####################
# SENSORIT
####################
sensor:
  - platform: bme680
    i2c_id: bus_a
    address: 0x77
    update_interval: 10s

    temperature:
      name: "WC Lämpötila"
      on_value:
        then:
          - if:
              condition:
                lambda: |-
                  return x < 22.0;
              then:
                - switch.turn_on: lattialammitys
              else:
                - switch.turn_off: lattialammitys

    pressure:
      name: "WC Ilmanpaine"

    humidity:
      name: "WC Kosteus"
      on_value:
        then:
          - lambda: |-
              id(wc_kosteus) = x;
          - script.execute: paivita_pistorasia
          - if:
              condition:
                lambda: |-
                  return x > 70.0;
              then:
                - switch.turn_on: poistopuhallus
              else:
                - switch.turn_off: poistopuhallus

    gas_resistance:
      name: "WC Kaasu"

  - platform: adc
    pin: 35
    id: wc_valaistus_raw
    name: "WC Valaistus RAW"
    attenuation: 11db
    update_interval: 100ms
    filters:
      - sliding_window_moving_average:
          window_size: 3

    on_value:
      then:
        - lambda: |-
            id(wc_valo) = x;
        - script.execute: paivita_pistorasia

        - if:
            condition:
              lambda: |-
                return !id(boot_ready);
            then:
              - switch.turn_off: musa1_chopinrain
              - switch.turn_off: musa6_rain

        - if:
            condition:
              lambda: |-
                return id(boot_ready) && x > 0.5;
            then:
              - switch.turn_off: musa1_chopinrain
              - switch.turn_off: musa6_rain

        - if:
            condition:
              lambda: |-
                return id(boot_ready) && x <= 0.5;
            then:
              - if:
                  condition:
                    switch.is_on: valo
                  then:
                    - switch.turn_off: musa6_rain
                    - switch.turn_on: musa1_chopinrain
                  else:
                    - switch.turn_off: musa1_chopinrain
                    - switch.turn_on: musa6_rain

  - platform: pulse_width
    pin: 34
    id: wc_echo_raw
    name: "WC Ultrasonic Echo Raw"
    update_interval: 200ms

  - platform: template
    id: wc_echo_avg
    name: "WC Ultrasonic Echo AVG"
    update_interval: 200ms
    lambda: |-
      if (!id(wc_echo_raw).has_state()) return NAN;
      float x = id(wc_echo_raw).state;
      if (x < 0.0006 || x > 0.0030) return NAN;
      return x;
    filters:
      - median:
          window_size: 5
      - sliding_window_moving_average:
          window_size: 3
          send_every: 1

    on_value:
      then:
        - if:
            condition:
              lambda: |-
                return id(boot_ready) && x < 0.0024;
            then:
              - lambda: |-
                  id(wc_ultra_osumat)++;
            else:
              - lambda: |-
                  id(wc_ultra_osumat) = 0;

        - if:
            condition:
              lambda: |-
                return id(wc_ultra_osumat) >= 3;
            then:
              - lambda: |-
                  id(wc_ultra_osumat) = 0;
              - script.execute: valo_1min

####################
# ULTRAÄÄNI – TRIG
####################
interval:
  - interval: 200ms
    then:
      - lambda: |-
          id(jsn_trig).turn_on();
          delayMicroseconds(10);
          id(jsn_trig).turn_off();

####################
# SCRIPTIT
####################
script:
  - id: valo_1min
    mode: restart
    then:
      - switch.turn_on: valo
      - delay: 60s
      - switch.turn_off: valo

  - id: paivita_pistorasia
    mode: queued
    then:
      - lambda: |-
          if (!id(boot_ready)) return;

          if (!id(pistorasia_paalla)) {
            if (id(wc_kosteus) < 63.0 && id(wc_valo) < 0.4) {
              id(pistorasia_paalla) = true;
              id(pistorasia).turn_on();
            }
          } else {
            if (id(wc_kosteus) > 67.0 || id(wc_valo) > 0.5) {
              id(pistorasia_paalla) = false;
              id(pistorasia).turn_off();
            }
          }

####################
# KYTKIMET
####################
switch:
  - platform: gpio
    id: jsn_trig
    internal: true
    pin: 12

  - platform: gpio
    id: valo
    name: "Valo"
    pin: 25
    restore_mode: RESTORE_DEFAULT_OFF

  - platform: gpio
    id: pistorasia
    name: "Pistorasia"
    pin: 26
    restore_mode: ALWAYS_OFF

  - platform: gpio
    id: lattialammitys
    name: "Lattialämmitys"
    pin: 32

  - platform: gpio
    id: poistopuhallus
    name: "Poistopuhallus"
    pin: 33

  ####################
  # MUSIIKIT (KAIKKI)
  ####################
  - platform: gpio
    id: musa1_chopinrain
    name: "musa1_ChopinRain"
    pin: 4
    inverted: true

  - platform: gpio
    id: musa2_dune
    name: "musa2_DUNE"
    pin: 5
    inverted: true

  - platform: gpio
    id: musa3_goddune
    name: "musa3_GODdune"
    pin: 16
    inverted: true

  - platform: gpio
    id: musa4_interstellar
    name: "musa4_Interstellar"
    pin: 17
    inverted: true

  - platform: gpio
    id: musa5_creepremix
    name: "musa5_CreepRemix"
    pin: 18
    inverted: true

  - platform: gpio
    id: musa6_rain
    name: "musa6_RAIN"
    pin: 19
    inverted: true

  - platform: gpio
    id: musa7_teknobathroom
    name: "musa7_Teknobathroom2069"
    pin: 23
    inverted: true

  - platform: gpio
    id: musa8_tyler
    name: "musa8_TylerPhilosophy"
    pin: 27
    inverted: true
Home Assistant Kello

https://youtu.be/cNV1U8Yh31M

Laita Configuration.yaml tiedostoon, niin saat kellon toimimaan:

  - platform: time_date
    display_options:
      - 'time'
      - 'date'
      - 'date_time'
      - 'date_time_utc'
      - 'date_time_iso'
      - 'time_date'
      - 'time_utc'
      - 'beat'
Home Assistant sähkön kustannussensori

https://youtu.be/EFs0I8Yw9Y0

Tällä saadaan päiväsähkö, yösähkö, ALV ja sähkön marginaali:

template:
  - sensor:
      - name: "Hetkellinen sähkön kustannus"
        unit_of_measurement: "€/h"
        state: >
          {% set alv_kerroin = (states('input_number.alv') | float(25.5)) / 100 + 1 %}
          {% set hinta = (states('sensor.nordpool_kwh_fi_eur_3_10_0') | float(0)) * alv_kerroin %}
          {% set teho = states('sensor.p1_meter_power') | float(0) %}
          {% set siirtohinta = states('input_number.yosahko') | float(0.035) 
                                if now().hour >= 22 or now().hour < 6 
                                else states('input_number.paivasahko') | float(0.045) %}
          {% set marginaalihinta = (states('input_number.sahkon_marginaalihinta') | float(0)) * alv_kerroin %}
          {{ ((hinta + siirtohinta + marginaalihinta) * teho) | round(4) }}
        icon: mdi:currency-eur
Sähkön kaikki hinnat
Home Assistant APEX-kortti 48h Nordpool näkymä
type: custom:apexcharts-card
graph_span: 48h
apex_config:
  chart:
    height: 170px
show:
  last_updated: true
experimental:
  color_threshold: true
header:
  title: NordPool+Siirto/kWh 48 h
  show: true
  show_states: true
  colorize_states: true
span:
  start: day
now:
  show: true
  label: Nyt
series:
  - entity: sensor.nordpool_kwh_fi_eur_10_10_0255
    show:
      extremas: true
      in_header: raw
      header_color_threshold: true
    type: column
    data_generator: |
      const today = entity.attributes.raw_today.map((start, index) => {
        return [new Date(start["start"]).getTime(), Math.round(entity.attributes.raw_today[index]["value"] * 1000) / 1000];
      });
      const tomorrow = entity.attributes.raw_tomorrow
        ? entity.attributes.raw_tomorrow.map((start, index) => {
            return [new Date(start["start"]).getTime(), Math.round(entity.attributes.raw_tomorrow[index]["value"] * 1000) / 1000];
          })
        : [];
      return [...today, ...tomorrow];
    float_precision: 3
    color_threshold:
      - value: 0
        color: darkgreen
        opacity: 1
      - value: 0.1
        color: goldenrod
      - value: 0.32
        color: darkred
yaxis:
  - id: Hinta
    min: ~0
    decimals: 2
    align_to: 0.05
    show: true
Home Assistant RPI_GPIO HAT Raspberry pi

Tässä Raspberry pi:n 8 releiselle boardille

switch:
  - platform: rpi_gpio
    switches:
      - port: 5
        name: "KIUAS"
        invert_logic: true
      - port: 6
        name: "LIESI"
        invert_logic: true
      - port: 13 
        name: "3-VAIHEPISTORASIA"
        invert_logic: true
      - port: 16
        name: "ET 6 kW"
        invert_logic: true
      - port: 19 
        name: "ET 5,1 kW"
        invert_logic: true
      - port: 20
        name: "ET 3,6 kWy"
        invert_logic: true
      - port: 21 
        name: "LVV"
        invert_logic: true
      - port: 26
        name: "Öljypoltin"
        invert_logic: true
Home Assistant Kustannussensori

Tässä templetti jossa yhdistetään kaikki kulut

template:
  - sensor:
      - name: "Hetkellinen sähkön kustannus"
        unit_of_measurement: "€/h"
        state: >
          {% set alv_kerroin = (states('input_number.alv') | float(25.5)) / 100 + 1 %}
          {% set hinta = (states('sensor.nordpool_kwh_fi_eur_3_10_0') | float(0)) * alv_kerroin %}
          {% set teho = states('sensor.p1_meter_power') | float(0) %}
          {% set siirtohinta = states('input_number.yosahko') | float(0.035) 
                                if now().hour >= 22 or now().hour < 6 
                                else states('input_number.paivasahko') | float(0.045) %}
          {% set marginaalihinta = (states('input_number.sahkon_marginaalihinta') | float(0)) * alv_kerroin %}
          {{ ((hinta + siirtohinta + marginaalihinta) * teho) | round(4) }}
        icon: mdi:currency-eur

Silloin saat tuon uuden Hetkellisen sähkön kustannuksen ja luo nuo 4 eri helpperiä, että saat numerot templateen.
– input_number.paivasahko
– input_number.yosahko
– input_number.alv
– input_number.sahkon_marginaalihinta

Image
Home Assistant ESP32 Pannun pumppujen ohjaus

Tässä templetti jossa yhdistetään kaikki kulut

# =========================================================
# SÄÄDETTÄVÄT ASETUKSET
# Muuta näitä arvoja tarpeen mukaan - ei tarvitse koskea
# alempana olevaan logiikkaan.
# =========================================================
substitutions:
  # Absoluuttiset lämpötilarajat (pumpun pakko-ohjaus)
  on_limit: "26.0"          # °C - tämän yli pumppu AINA päälle
  off_limit: "23.0"         # °C - tämän alle pumppu saa mennä pois (jos turvallista)

  # Nopea, lyhyen ikkunan nousuntunnistus (esim. äkillinen liekki)
  rise_threshold_fast: "0.5"      # °C
  rise_window_fast_ms: "60000"    # 60 000 ms = 1 min

  # Hidas/herkkä nousuntunnistus - KÄYNNISTÄÄ PUMPUN AIKAISEMMIN
  # Esim. 0.3 astetta 2 minuutissa -> pumppu käynnistyy heti kun
  # nousu ylittyy, ei tarvitse odottaa koko ikkunan täyttymistä.
  rise_threshold_slow: "0.3"      # °C
  rise_window_slow_ms: "120000"   # 120 000 ms = 2 min

  # Pumpun käyntiaika kun se laukeaa ajastimella
  pump_runtime_ms: "2700000"      # 2 700 000 ms = 45 min

  # Kuinka kauan anturivian jälkeen odotetaan ennen kuin
  # OFF-ehto sallitaan uudelleen (turvamarginaali)
  recovery_hold_ms: "120000"      # 120 000 ms = 2 min

  # Kuinka kauan ilman kelvollista lukemaa ennen kuin
  # anturi tulkitaan vikaantuneeksi
  sensor_timeout_ms: "30000"      # 30 000 ms = 30 s

  # Kuinka kauan lämpötila saa pysyä alle off_limit-rajan
  # (eikä pumpun ajastin ole käynnissä) ennen kuin annetaan
  # "lisää puuta pannuun" -ilmoitus (VIIMEINEN VARMISTIN,
  # laukeaa vasta kun tuli on jo aika lailla hiipunut)
  low_temp_alert_delay_ms: "300000"   # 300 000 ms = 5 min

  # AIKAINEN VAROITUS: jos lämpötila laskee tämän verran
  # tämän ikkunan sisällä, annetaan "lisää puuta" -ilmoitus
  # HETI - riippumatta absoluuttisesta lämpötilasta. Näin
  # ilmoitus tulee jo silloin kun tuli alkaa hiipua, ei vasta
  # kun lämpötila on ehtinyt pudota off_limit-rajan alle.
  fall_threshold: "0.3"           # °C
  fall_window_ms: "5400000"        # 300 000 ms = 5 min

  # PYSÄHTYMISEN (STAGNAATION) TUNNISTUS
  # Jos lämpötila pysyy tämän kaistan sisällä (ei nouse eikä laske
  # merkittävästi) yhtäjaksoisesti tämän ajan, pumppu SAMMUTETAAN
  # vaikka lämpötila olisi vielä yli off_limit-rajan. Tulkitaan,
  # ettei lämpöä ole enää tulossa lisää (tuli hiipunut / paluuvesi
  # tasaantunut), joten latausta ei ole enää järkevää jatkaa.
  stagnation_band: "0.2"           # °C - tämän sisällä pysyminen tulkitaan "ei muutosta"
  stagnation_window_ms: "900000"   # 900 000 ms = 15 min

esphome:
  name: ljh
  friendly_name: LJH

esp32:
  board: esp32dev
  framework:
    type: esp-idf

logger:

api:
  encryption:
    key: "1OCwTSndJs/8IwX/reO04WD3t6FW16xjrcxnScqiSG8="

ota:
  - platform: esphome
    password: "f12a8c146de656db334a794b85325e43"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Ljh Fallback Hotspot"
    password: "JK9awEWfXFxR"

captive_portal:

i2c:
  sda: 21
  scl: 22
  scan: true
  id: bus_a

# =========================================================
# HÄLYTYKSET
# =========================================================
binary_sensor:
  - platform: template
    id: lisaapuut
    name: "Lisää puuta pannuun"

  - platform: template
    id: anturi_vika
    name: "Lämpötila-anturi vika"

# =========================================================
# GLOBAALIT
# =========================================================
globals:
  - id: last_ok_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

  # Nopea (fast) nousuntunnistus - checkpoint
  - id: temp_fast_checkpoint
    type: float
    restore_value: no
    initial_value: '0'

  - id: temp_fast_checkpoint_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

  # Hidas (slow) nousuntunnistus - checkpoint
  - id: temp_slow_checkpoint
    type: float
    restore_value: no
    initial_value: '0'

  - id: temp_slow_checkpoint_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

  - id: pump_until
    type: unsigned long
    restore_value: no
    initial_value: '0'

  - id: sensor_fault
    type: bool
    restore_value: no
    initial_value: 'false'

  - id: fault_recovery_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

  # "Lisää puuta pannuun" -ilmoituksen ajastus:
  # merkitsee ajanhetken, josta lähtien lämpötila on ollut
  # jatkuvasti alle off_limit-rajan (ilman pumpun ajastinta)
  - id: low_temp_since
    type: unsigned long
    restore_value: no
    initial_value: '0'

  # Laskevan trendin varhainen tunnistus - seuraa viimeisintä
  # huippulukemaa (peak) ja verrataan siihen, kuinka paljon
  # lämpötila on siitä pudonnut.
  - id: temp_fall_checkpoint
    type: float
    restore_value: no
    initial_value: '0'

  - id: temp_fall_checkpoint_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

  # Stagnaation (pysähtymisen) tunnistus - referenssiarvo, josta
  # mitataan onko lämpötila pysynyt paikallaan riittävän kauan.
  - id: temp_stagnation_checkpoint
    type: float
    restore_value: no
    initial_value: '0'

  - id: temp_stagnation_checkpoint_time
    type: unsigned long
    restore_value: no
    initial_value: '0'

sensor:
  - platform: bme680
    i2c_id: bus_a
    address: 0x77
    update_interval: 10s

    temperature:
      id: bme_temp
      name: "BME680 Lampotila"

      on_value:
        then:

          - lambda: |-

              const float ON_LIMIT = ${on_limit};
              const float OFF_LIMIT = ${off_limit};

              const float RISE_THRESHOLD_FAST = ${rise_threshold_fast};
              const unsigned long RISE_WINDOW_FAST = ${rise_window_fast_ms};

              const float RISE_THRESHOLD_SLOW = ${rise_threshold_slow};
              const unsigned long RISE_WINDOW_SLOW = ${rise_window_slow_ms};

              const unsigned long PUMP_RUNTIME = ${pump_runtime_ms};
              const unsigned long RECOVERY_HOLD = ${recovery_hold_ms};
              const unsigned long LOW_TEMP_ALERT_DELAY = ${low_temp_alert_delay_ms};

              const float FALL_THRESHOLD = ${fall_threshold};
              const unsigned long FALL_WINDOW = ${fall_window_ms};

              const float STAGNATION_BAND = ${stagnation_band};
              const unsigned long STAGNATION_WINDOW = ${stagnation_window_ms};

              unsigned long now = millis();

              // =====================================================
              // 1. ANTURIN VALIDIOINTI
              // =====================================================
              bool valid = !(isnan(x) || x < -40 || x > 200);

              if (!valid) {
                id(sensor_fault) = true;
                id(anturi_vika).publish_state(true);

                id(P1).turn_on();
                id(P2).turn_on();

                return;
              }

              // =====================================================
              // 2. PALAUTUMINEN
              // =====================================================
              if (id(sensor_fault)) {
                id(sensor_fault) = false;
                id(anturi_vika).publish_state(false);

                id(fault_recovery_time) = now;

                id(temp_fast_checkpoint) = x;
                id(temp_fast_checkpoint_time) = now;

                id(temp_slow_checkpoint) = x;
                id(temp_slow_checkpoint_time) = now;

                id(temp_fall_checkpoint) = x;
                id(temp_fall_checkpoint_time) = now;

                id(temp_stagnation_checkpoint) = x;
                id(temp_stagnation_checkpoint_time) = now;

                // vian aikana ei voida tietää oliko kylmä - nollataan
                id(low_temp_since) = 0;
              }

              id(last_ok_time) = now;

              // KORJAUS: julkaistaan anturi_vika-tila joka kierroksella,
              // ei vain silloin kun se muuttuu. Aiemmin sensori jäi
              // "unknown"-tilaan pysyvästi, jos vikaa ei koskaan
              // tapahtunut - koska publish_state() ei tullut kutsutuksi
              // kertaakaan ennen ensimmäistä vikaa tai palautumista.
              id(anturi_vika).publish_state(false);

              bool unsafe_period = (now - id(fault_recovery_time)) < RECOVERY_HOLD;

              // =====================================================
              // 3. LÄMPÖNOUSUN TUNNISTUS (JATKUVA, LIUKUVA IKKUNA)
              //
              // Nousu tarkistetaan JOKA mittauksella (ei vain kun
              // ikkuna on täynnä). Näin pumppu käynnistyy heti kun
              // kynnys ylittyy, vaikka se tapahtuisi nopeamminkin
              // kuin asetettu ikkuna-aika.
              //
              // KORJAUS: checkpointia EI enää nollata nykyiseen
              // arvoon pelkän ikkunan umpeutumisen takia. Se
              // aiheutti "sahalaitabugin", jossa tasainen mutta
              // hidas nousu (esim. juuri alle kynnyksen joka
              // ikkunassa) ei koskaan päässyt kertymään, koska
              // lähtötaso raahattiin jatkuvasti ylöspäin.
              //
              // Uusi sääntö: lähtötaso (checkpoint) siirretään
              // eteenpäin VAIN kun löytyy uusi, matalampi pohja-
              // lukema (todellinen paikallinen minimi), tai kun
              // ikkuna umpeutuu EIKÄ noustu ollenkaan sitten
              // viimeisimmän tarkistuksen. Näin nousu pääsee
              // kertymään usean mittausvälin yli oikein.
              // =====================================================

              // --- Nopea tunnistus ---
              if (id(temp_fast_checkpoint_time) == 0) {
                id(temp_fast_checkpoint) = x;
                id(temp_fast_checkpoint_time) = now;
              } else {
                float rise_fast = x - id(temp_fast_checkpoint);

                if (rise_fast >= RISE_THRESHOLD_FAST) {
                  id(P2).turn_on();
                  id(pump_until) = now + PUMP_RUNTIME;

                  id(temp_fast_checkpoint) = x;
                  id(temp_fast_checkpoint_time) = now;
                }
                else if (x < id(temp_fast_checkpoint)) {
                  // uusi, matalampi pohjalukema -> siirretään lähtötasoa
                  id(temp_fast_checkpoint) = x;
                  id(temp_fast_checkpoint_time) = now;
                }
                else if (now - id(temp_fast_checkpoint_time) >= RISE_WINDOW_FAST) {
                  // ikkuna umpeutui eikä noussut riittävästi eikä uutta
                  // pohjaa löytynyt -> nollataan vasta nyt
                  id(temp_fast_checkpoint) = x;
                  id(temp_fast_checkpoint_time) = now;
                }
              }

              // --- Hidas / herkkä tunnistus (esim. 0.3 astetta / 2 min) ---
              if (id(temp_slow_checkpoint_time) == 0) {
                id(temp_slow_checkpoint) = x;
                id(temp_slow_checkpoint_time) = now;
              } else {
                float rise_slow = x - id(temp_slow_checkpoint);

                if (rise_slow >= RISE_THRESHOLD_SLOW) {
                  id(P2).turn_on();
                  id(pump_until) = now + PUMP_RUNTIME;

                  id(temp_slow_checkpoint) = x;
                  id(temp_slow_checkpoint_time) = now;
                }
                else if (x < id(temp_slow_checkpoint)) {
                  // uusi, matalampi pohjalukema -> siirretään lähtötasoa
                  id(temp_slow_checkpoint) = x;
                  id(temp_slow_checkpoint_time) = now;
                }
                else if (now - id(temp_slow_checkpoint_time) >= RISE_WINDOW_SLOW) {
                  // ikkuna umpeutui eikä noussut riittävästi eikä uutta
                  // pohjaa löytynyt -> nollataan vasta nyt
                  id(temp_slow_checkpoint) = x;
                  id(temp_slow_checkpoint_time) = now;
                }
              }

              // --- Laskevan trendin varhainen tunnistus (lisaapuut) ---
              // Seurataan viimeisintä huippulukemaa (peak). Jos lämpötila
              // on pudonnut siitä FALL_THRESHOLD verran FALL_WINDOW:n
              // sisällä, annetaan "lisää puuta" -ilmoitus HETI, vaikka
              // absoluuttinen lämpötila olisi vielä reilusti yli
              // off_limit-rajan. Tämä antaa varoituksen jo silloin kun
              // tuli alkaa hiipua, ei vasta kun se on jo sammunut.
              bool early_fuel_warning = false;

              if (id(temp_fall_checkpoint_time) == 0) {
                id(temp_fall_checkpoint) = x;
                id(temp_fall_checkpoint_time) = now;
              } else {
                float drop = id(temp_fall_checkpoint) - x;

                if (drop >= FALL_THRESHOLD) {
                  early_fuel_warning = true;

                  id(temp_fall_checkpoint) = x;
                  id(temp_fall_checkpoint_time) = now;
                }
                else if (x > id(temp_fall_checkpoint)) {
                  // uusi huippulukema -> siirretään huippu ylemmäs
                  id(temp_fall_checkpoint) = x;
                  id(temp_fall_checkpoint_time) = now;
                }
                else if (now - id(temp_fall_checkpoint_time) >= FALL_WINDOW) {
                  // ikkuna umpeutui eikä pudonnut riittävästi eikä uutta
                  // huippua löytynyt -> nollataan vasta nyt
                  id(temp_fall_checkpoint) = x;
                  id(temp_fall_checkpoint_time) = now;
                }
              }

              // --- Stagnaation (pysähtymisen) tunnistus ---
              // Jos lämpötila pysyy STAGNATION_BAND:n sisällä
              // referenssiarvosta, kello ei nollaudu - se kertoo
              // kuinka kauan lämpötila on ollut käytännössä paikallaan.
              // Heti kun poikkeama ylittää kaistan (nousu TAI lasku),
              // referenssi ja kello nollautuvat, koska liikettä on
              // taas havaittu.
              if (id(temp_stagnation_checkpoint_time) == 0) {
                id(temp_stagnation_checkpoint) = x;
                id(temp_stagnation_checkpoint_time) = now;
              } else if (fabs(x - id(temp_stagnation_checkpoint)) >= STAGNATION_BAND) {
                id(temp_stagnation_checkpoint) = x;
                id(temp_stagnation_checkpoint_time) = now;
              }

              bool stagnant = (now - id(temp_stagnation_checkpoint_time)) >= STAGNATION_WINDOW;

              // =====================================================
              // 4. AJASTIN
              // =====================================================
              if (id(pump_until) > 0 && now >= id(pump_until)) {
                id(pump_until) = 0;
              }

              // =====================================================
              // 5. PRIORITEETTILOGIIKKA (TÄRKEIN KORJAUS)
              //
              // HUOM: P2 (latauspumppu) on KRIITTINEN pumppu - se ei
              // saa koskaan sammua vikatilanteessa. Tästä syystä
              // sensor_fault-tarkistus on aina ensimmäinen ja siitä
              // palataan (return) ennen kuin mikään myöhempi ehto
              // pääsee sammuttamaan sen.
              // =====================================================

              // 1. KRIITTINEN FAILSAFE - P2 pysyy päällä, ei poikkeuksia
              if (id(sensor_fault)) {
                id(P2).turn_on();
                return;
              }

              // 2. LÄMMITYS ON
              if (x >= ON_LIMIT) {
                id(P2).turn_on();
                id(low_temp_since) = 0;
                id(temp_fall_checkpoint) = x;
                id(temp_fall_checkpoint_time) = now;
                id(temp_stagnation_checkpoint) = x;
                id(temp_stagnation_checkpoint_time) = now;
                id(lisaapuut).publish_state(false);
                return;
              }

              // 3. AJASTIN ON
              if (id(pump_until) > 0) {
                id(P2).turn_on();
                id(low_temp_since) = 0;
                id(temp_fall_checkpoint) = x;
                id(temp_fall_checkpoint_time) = now;
                id(temp_stagnation_checkpoint) = x;
                id(temp_stagnation_checkpoint_time) = now;
                id(lisaapuut).publish_state(false);
                return;
              }

              // 4. OFF EHTO (AINOASTAAN VARMA TILA)
              //
              // Pumppu sammuu jos JOMPI KUMPI pätee:
              // a) lämpötila on alle off_limit-rajan (klassinen ehto), TAI
              // b) lämpötila on pysynyt käytännössä paikallaan
              //    (STAGNATION_BAND:n sisällä) yhtäjaksoisesti
              //    STAGNATION_WINDOW:n ajan - tulkitaan ettei lämpöä
              //    enää tule lisää, vaikka absoluuttinen lämpötila
              //    olisikin vielä yli off_limit-rajan.
              if (!unsafe_period && (x < OFF_LIMIT || stagnant)) {
                id(P2).turn_off();
              }

              // =====================================================
              // 6. "LISÄÄ PUUTA PANNUUN" -ILMOITUS
              //
              // KORJAUS: hälytys sallitaan VAIN silloin kun latauspumppu
              // P2 ON käynnissä. Jos P2 on pois päältä, hälytystä ei
              // koskaan näytetä - riippumatta muista ehdoista alempana.
              // (Aiemmin ehto oli päinvastoin: hälytys estyi kun P2 oli
              // päällä, ja sallittiin kun P2 oli pois päältä.)
              // =====================================================
              if (!id(P2).state) {
                id(lisaapuut).publish_state(false);
                return;
              }

              // Kaksi laukaisutapaa, kumpi tahansa riittää:
              //
              // A) VARHAINEN: early_fuel_warning on true heti kun
              //    lämpötila on pudonnut FALL_THRESHOLD verran
              //    FALL_WINDOW:n sisällä (osiossa 3 laskettu) -
              //    reagoi jo hiipuvaan tuleen, ennen kuin lämpötila
              //    on edes lähelläkään off_limit-rajaa.
              //
              // B) VARMISTIN: jos lämpötila on pysynyt yhtäjaksoisesti
              //    alle off_limit-rajan LOW_TEMP_ALERT_DELAY:n ajan
              //    (esim. jos lasku on ollut niin tasainen/hidas ettei
              //    A koskaan laukea), ilmoitus annetaan silti.
              //
              // Ilmoitus nollautuu heti kun lämpötila nousee takaisin
              // off_limit-rajan yli, tai kun ON_LIMIT/ajastin laukeaa
              // (nollaukset tehty osioissa 2 ja 3 yllä).
              // =====================================================
              if (early_fuel_warning) {
                id(lisaapuut).publish_state(true);
              }

              if (x < OFF_LIMIT) {
                if (id(low_temp_since) == 0) {
                  id(low_temp_since) = now;
                }
                else if (now - id(low_temp_since) >= LOW_TEMP_ALERT_DELAY) {
                  id(lisaapuut).publish_state(true);
                }
              } else {
                id(low_temp_since) = 0;
                if (!early_fuel_warning) {
                  id(lisaapuut).publish_state(false);
                }
              }

    pressure:
      name: "BME680 Paine"

    humidity:
      name: "BME680 Kosteus"

    gas_resistance:
      name: "BME680 Kaasu"

# =========================================================
# ANTURIN VALVONTA
# =========================================================
interval:
  - interval: 30s
    then:
      - lambda: |-

          const unsigned long SENSOR_TIMEOUT = ${sensor_timeout_ms};

          if (millis() - id(last_ok_time) > SENSOR_TIMEOUT) {

            id(sensor_fault) = true;
            id(anturi_vika).publish_state(true);

            id(P1).turn_on();
            id(P2).turn_on();
          }

# =========================================================
# RELEET
#
# P1 = Pattereiden kiertovesi
#      EI kriittinen. Ohjataan päälle turvatoimena vikatilanteissa
#      (auttaa purkamaan lämpöä patteriverkostoon jos anturi vikaantuu).
#
# P2 = Energiatankin latauspumppu
#      KRIITTINEN. Tämä EI SAA sammua vikatilanteessa tai bootin
#      yhteydessä. restore_mode: ALWAYS_ON varmistaa, että pumppu on
#      aina päällä heti käynnistyksen jälkeen, ennen kuin ensimmäinen
#      kelvollinen lämpötilalukema on edes saatu (esim. sähkökatkon
#      tai WiFi-ongelman jälkeen).
# =========================================================
switch:

  - platform: gpio
    id: P1
    name: "Pattereiden kiertovesi"
    pin: 25
    restore_mode: ALWAYS_ON

  - platform: gpio
    id: P2
    name: "Energiatankin latauspumppu"
    pin: 26
    restore_mode: ALWAYS_ON

Home Assistant ESP32 Growatt invertterin Modbus

Growatt MOD 8000TL3-HU (käytetty DIN asenteista ESP32 laitetta, jossa oma rele)

esphome:
  name: solar
  friendly_name: Solar

esp32:
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf

logger:
  level: DEBUG

api:
  encryption:
    key: "WqbVi/yIvgpeu62sCdnbNCZ7S4IML6f4r1VwvlhviUA="

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  ap:
    ssid: "Solar Fallback Hotspot"
    password: "NHfyvtxKVdvN"

captive_portal:


# ============================================================
# WAVESHARE ESP32-S3-RELAY-1CH
# ============================================================
#
# RS485:
# GPIO17 = TX
# GPIO18 = RX
# GPIO21 = RS485 direction / flow control
#
# Relay:
# GPIO47 = Relay
#
# ============================================================


# ============================================================
# UART / RS485
# ============================================================

uart:
  id: mod_uart

  tx_pin: GPIO17
  rx_pin: GPIO18

  # Growatt MOD 8000TL3-HU
  baud_rate: 9600

  data_bits: 8
  parity: NONE
  stop_bits: 1

  rx_buffer_size: 256


# ============================================================
# MODBUS
# ============================================================

modbus:
  id: mod_bus
  uart_id: mod_uart

  # Waveshare ESP32-S3-Relay-1CH RS485 direction control
  flow_control_pin: GPIO21

  # send_wait_time = kuinka kauan odotetaan vastauksen alkua
  # turnaround_time = tauko vastauksen jalkeen ennen seuraavaa komentoa
  send_wait_time: 2s
  turnaround_time: 1s


# ============================================================
# GROWATT MOD 8000TL3-HU
# ============================================================
#
# Rekisteriosoitteet:
# ESPHomessa kaytetaan raakaa input-rekisteriosoitetta.
# Esimerkiksi dokumentaation 33000 = ESPHomessa 3000.
#
# ============================================================

modbus_controller:
  - id: growatt

    # Default Growatt Modbus address
    address: 0x01

    modbus_id: mod_bus

    setup_priority: -10

    # Read every 5 seconds
    update_interval: 5s

    offline_skip_updates: 2

    on_online:
      then:
        - logger.log: "Growatt Modbus ONLINE"

    on_offline:
      then:
        - logger.log: "Growatt Modbus OFFLINE"


# ============================================================
# WAVESHARE RELAY
# ============================================================

switch:

  - platform: gpio
    name: "Solar Relay"
    id: solar_relay

    pin:
      number: GPIO47
      inverted: false

    restore_mode: ALWAYS_OFF


# ============================================================
# TEST OUTPUT GPIO1
# ============================================================

  - platform: gpio
    name: "Solar Test GPIO1"
    id: test_gpio1

    pin:
      number: GPIO1
      inverted: false

    restore_mode: ALWAYS_OFF


# ============================================================
# TEST OUTPUT GPIO2
# ============================================================

  - platform: gpio
    name: "Solar Test GPIO2"
    id: test_gpio2

    pin:
      number: GPIO2
      inverted: false

    restore_mode: ALWAYS_OFF


# ============================================================
# GROWATT STATUS
# ============================================================

text_sensor:

  - platform: template
    name: "Growatt Inverter Status"
    id: growatt_status_text

    update_interval: 5s

    lambda: |-
      if (!id(growatt_status_code).has_state()) {
        return {"Unknown"};
      }

      switch ((int) id(growatt_status_code).state) {
        case 0:
          return {"Waiting"};

        case 1:
          return {"Normal"};

        case 3:
          return {"Fault"};

        default:
          return {"Unknown"};
      }


# ============================================================
# CONNECTION TEST
# ============================================================

  - platform: template
    name: "Growatt Modbus Connection"
    id: growatt_modbus_connection

    update_interval: 10s

    lambda: |-
      if (id(growatt_status_code).has_state()) {
        return {"ONLINE - Modbus responds"};
      }

      return {"NO MODBUS RESPONSE"};


# ============================================================
# SENSORS
# ============================================================

sensor:


# ============================================================
# STATUS CODE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3000

    name: "Growatt Status Code"
    id: growatt_status_code

    register_type: read

    value_type: U_WORD

    accuracy_decimals: 0


# ============================================================
# TOTAL PV POWER
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3001

    name: "PV Input Power"
    id: pv_input_power

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# PV1 VOLTAGE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3003

    name: "PV1 Voltage"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# PV1 CURRENT
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3004

    name: "PV1 Current"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# PV1 POWER
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3005

    name: "PV1 Power"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# PV2 VOLTAGE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3007

    name: "PV2 Voltage"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# PV2 CURRENT
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3008

    name: "PV2 Current"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# PV2 POWER
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3009

    name: "PV2 Power"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# AURINKOTUOTANTO
# ============================================================
#
# Growatt AC Output Power
#
# Hetkellinen aurinkotuotanto watteina.
#
# Home Assistant:
# sensor.solar_aurinkotuotanto
#
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3023

    name: "Aurinkotuotanto"
    id: solar_power

    register_type: read

    value_type: S_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# AC FREQUENCY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3025

    name: "AC Frequency"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "Hz"
    device_class: frequency
    state_class: measurement

    accuracy_decimals: 2

    filters:
      - multiply: 0.01


# ============================================================
# AC VOLTAGE L1
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3026

    name: "AC Voltage L1"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC CURRENT L1
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3027

    name: "AC Current L1"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC POWER L1
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3028

    name: "AC Power L1"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "VA"
    device_class: apparent_power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# AC VOLTAGE L2
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3030

    name: "AC Voltage L2"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC CURRENT L2
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3031

    name: "AC Current L2"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC POWER L2
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3032

    name: "AC Power L2"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "VA"
    device_class: apparent_power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# AC VOLTAGE L3
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3034

    name: "AC Voltage L3"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC CURRENT L3
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3035

    name: "AC Current L3"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "A"
    device_class: current
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# AC POWER L3
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3036

    name: "AC Power L3"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "VA"
    device_class: apparent_power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# LINE VOLTAGE L1-L2
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3038

    name: "AC Voltage L1-L2"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# LINE VOLTAGE L2-L3
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3039

    name: "AC Voltage L2-L3"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# LINE VOLTAGE L3-L1
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3040

    name: "AC Voltage L3-L1"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# OSTO VERKOSTA
# ============================================================
#
# Growatt AC Power To User
#
# Hetkellinen verkosta otettava teho watteina.
#
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3041

    name: "Osto verkosta"
    id: grid_import_power

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# VIENTI VERKKOON
# ============================================================
#
# Growatt AC Power To Grid
#
# Hetkellinen verkkoon syotettava teho watteina.
#
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3043

    name: "Vienti verkkoon"
    id: grid_export_power

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# KULUTUS JÄRJESTELMÄSSÄ
# ============================================================
#
# Growatt AC Power To Load
#
# Hetkellinen jarjestelman/kodin kulutus watteina.
#
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3045

    name: "Kulutus järjestelmässä"
    id: load_power

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"
    device_class: power
    state_class: measurement

    filters:
      - multiply: 0.1


# ============================================================
# TOTAL OPERATING TIME
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3047

    name: "Inverter Operating Time"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "s"
    state_class: total_increasing

    filters:
      - multiply: 0.5


# ============================================================
# AC ENERGY TODAY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3049

    name: "AC Energy Today"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# TOTAL AC ENERGY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3051

    name: "AC Energy Lifetime"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# TOTAL PV ENERGY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3053

    name: "PV Energy Total"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# PV1 ENERGY TODAY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3055

    name: "PV1 Energy Today"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# PV1 ENERGY TOTAL
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3057

    name: "PV1 Energy Total"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# PV2 ENERGY TODAY
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3059

    name: "PV2 Energy Today"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# PV2 ENERGY TOTAL
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3061

    name: "PV2 Energy Total"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    filters:
      - multiply: 0.1


# ============================================================
# PV INSULATION
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3087

    name: "PV Insulation"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "kOhm"

    accuracy_decimals: 0


# ============================================================
# INVERTER IPM TEMPERATURE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3093

    name: "Inverter IPM Temperature"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# INVERTER TEMPERATURE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3094

    name: "Inverter Temperature"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# BOOST TEMPERATURE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3095

    name: "Boost Temperature"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# COMMUNICATION BOARD TEMPERATURE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3097

    name: "Communication Board Temperature"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "°C"
    device_class: temperature
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# P BUS VOLTAGE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3098

    name: "P Bus Voltage"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# N BUS VOLTAGE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3099

    name: "N Bus Voltage"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "V"
    device_class: voltage
    state_class: measurement

    accuracy_decimals: 1

    filters:
      - multiply: 0.1


# ============================================================
# POWER FACTOR
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3100

    name: "Inverter Power Factor"

    register_type: read

    value_type: U_WORD

    device_class: power_factor

    accuracy_decimals: 2


# ============================================================
# OUTPUT POWER %
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3101

    name: "Output Power Percent"

    register_type: read

    value_type: U_WORD

    unit_of_measurement: "%"

    accuracy_decimals: 0


# ============================================================
# MAX OUTPUT POWER LIMIT
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3102

    name: "Output Power Limit"

    register_type: read

    value_type: U_DWORD

    unit_of_measurement: "W"

    filters:
      - multiply: 0.1


# ============================================================
# FAULT CODE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3105

    name: "Growatt Fault Code"

    register_type: read

    value_type: U_WORD

    accuracy_decimals: 0


# ============================================================
# WARNING CODE
# ============================================================

  - platform: modbus_controller
    modbus_controller_id: growatt

    address: 3106

    name: "Growatt Warning Code"

    register_type: read

    value_type: U_WORD

    accuracy_decimals: 0


# ============================================================
# HOME ASSISTANT ENERGY
# ============================================================
#
# Nämä muuttavat hetkellisen tehon (W) energiaksi (kWh).
#
# Home Assistant Energy Dashboard voi käyttää näitä:
#
# Aurinkotuotanto yhteensä
# Osto verkosta yhteensä
# Vienti verkkoon yhteensä
# Kulutus järjestelmässä yhteensä
#
# ============================================================


# ============================================================
# AURINKOTUOTANTO YHTEENSÄ
# ============================================================

  - platform: integration
    name: "Aurinkotuotanto yhteensä"
    id: solar_energy_total

    sensor: solar_power

    time_unit: h
    integration_method: trapezoid
    restore: true

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    accuracy_decimals: 3

    filters:
      - multiply: 0.001


# ============================================================
# OSTO VERKOSTA YHTEENSÄ
# ============================================================

  - platform: integration
    name: "Osto verkosta yhteensä"
    id: grid_import_energy

    sensor: grid_import_power

    time_unit: h
    integration_method: trapezoid
    restore: true

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    accuracy_decimals: 3

    filters:
      - multiply: 0.001


# ============================================================
# VIENTI VERKKOON YHTEENSÄ
# ============================================================

  - platform: integration
    name: "Vienti verkkoon yhteensä"
    id: grid_export_energy

    sensor: grid_export_power

    time_unit: h
    integration_method: trapezoid
    restore: true

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    accuracy_decimals: 3

    filters:
      - multiply: 0.001


# ============================================================
# KULUTUS JÄRJESTELMÄSSÄ YHTEENSÄ
# ============================================================

  - platform: integration
    name: "Kulutus järjestelmässä yhteensä"
    id: load_energy_total

    sensor: load_power

    time_unit: h
    integration_method: trapezoid
    restore: true

    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing

    accuracy_decimals: 3

    filters:
      - multiply: 0.001