esphome:
  name: relaisboard
  friendly_name: relaisboard
  on_boot:
  - priority: 900.0
    then:
      - lambda: |-
          id(cpu_speed) = ESP.getCpuFreqMHz();
  
logger:
  level: DEBUG
#  baud_rate: 0

esp32:
  board: esp32dev
  framework:
    type: arduino

# Wifi 
wifi:
  ssid: "xxxxx"
  password: "xxxxxx"
  reboot_timeout: 5min

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Relaisboard"
    password: ""

  # Optional manual IP
#  manual_ip:
#    static_ip: 10.0.0.166
#    gateway: 10.0.0.138
#    subnet: 255.255.255.0
#    dns1: 10.0.0.138
#    dns2: 8.8.8.8

captive_portal:

# Webserver
web_server:
  port: 80

# Enable Home Assistant API
api:
  encryption:
    key: "xxxxxxxxxxxxxxxxxxxxxxxx"
  reboot_timeout: 0s
ota:
  password: "xxxxxxxxxxxxxxxxxxxxxxxx"

globals:
  - id: cpu_speed
    type: int
    restore_value: no
    initial_value: "0"

# blinking led
interval:
  - interval: 1000ms
    then:
      - output.turn_on: led
      - delay: 500ms
      - output.turn_off: led

# Dallas Sensoren
dallas:
  - pin: GPIO16
    update_interval: 20s

# 1wire Temperatur Sensor
sensor:
  - platform: dallas
    address: 0x0e164b201864ff28
    name: Warmwasser
    id: warmwasser
    unit_of_measurement: "°C"
  - platform: template
    name: "AMIS Saldo"
    id: saldo
    unit_of_measurement: "W"
    update_interval: 5s
    #Device UPTIME
  - platform: uptime
    name: ESP Laufzeit
    id: sys_uptime
    update_interval: 60s
    #Device CPU Speed
  - platform: template
    name: "ESP Cpu Takt"
    accuracy_decimals: 0
    unit_of_measurement: Mhz
    lambda: |-
      return (id(cpu_speed));
    entity_category: "diagnostic"
    #Device Memory
  - platform: template
    id: esp_memory
    icon: mdi:memory
    name: ESP freier Ram
    lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
    unit_of_measurement: "kB"
    state_class: measurement
    entity_category: "diagnostic"
    #Device Temperature
  - platform: template
    id: sys_esp_temperature
    name: ESP Temperatur
    lambda: return temperatureRead();
    unit_of_measurement: "°C"
    device_class: TEMPERATURE
    update_interval: 60s
    #Device RSSI
  - platform: wifi_signal
    name: ESP Wifi Signalstärke
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"

# Display
i2c:
  sda: GPIO13
  scl: GPIO14
#  frequency: 200kHz

display:
  - platform: lcd_pcf8574
    dimensions: 20x4
    address: 0x27
    id: lcd
    update_interval: 1s
    lambda: |-
      it.printf(0,0,"PV-Heizstabsteuerung");
      it.printf(0,1,"IP: %s", id(relaisboard_ip).state.c_str());
      it.printf(0,2,"SM: %.0fW", id(saldo).state);   
      it.printf(13,2,"T: %.0fC", id(warmwasser).state);
      it.print(0,3,"R1:  R2:  R3:  R4:");
      if (id(relay_1).state){
        it.print(3,3,"1");
      } else {
        it.print(3,3, "0");
      }
      if (id(relay_2).state){
        it.print(8,3,"1");
      } else {
        it.print(8,3, "0");
      }
      if (id(relay_3).state){
        it.print(13,3,"1");
      } else {
        it.print(13,3, "0");
      }
      if (id(relay_4).state){
        it.print(18,3,"1");
      } else {
        it.print(18,3, "0");
      }

# In/Outputs
output:
  - platform: gpio
    pin: GPIO23
    id: led
  - platform: gpio
    pin: GPIO32
    id: relay_pin_1
  - platform: gpio
    pin: GPIO33
    id: relay_pin_2
  - platform: gpio
    pin: GPIO25
    id: relay_pin_3
  - platform: gpio
    pin: GPIO26
    id: relay_pin_4

# Define the switches based on the relay pins
switch:
  - platform: output
    id: relay_1
    name: "Heizstab (Phase1) Relais 1"
    output: relay_pin_1
  - platform: output
    id: relay_2
    name: "Heizstab (Phase2) Relais 2"
    output: relay_pin_2
  - platform: output
    id: relay_3
    name: "Heizstab (Phase3) Relais 3"
    output: relay_pin_3
  - platform: output
    id: relay_4
    name: "Heizstab (Reserve) Relais 4"
    output: relay_pin_4
  - platform: template
    name: "Heizen auf Mindesttemperatur"
    id: "HeizenMindestTemp"
    optimistic: True
  - platform: template
    name: "Heizen von 6:00-17:59 (OFF) bzw 11:00-17:59 (ON)"
    id: "AbMittag"
    optimistic: True
    restore_mode: RESTORE_DEFAULT_OFF
button:
  - platform: template
    name: "AMIS Lesekopf RestApi abfragen"
    on_press:
      - http_request.get:
          url: !lambda |-
            return ((std::string) esphome::to_string(id(ip_amis).state));
          headers:
            Content-Type: application/json
          verify_ssl: false
          on_response:
            then:
              - lambda: |-
                  json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
                    id(saldo).publish_state(root["saldo"]);
                  });
text:
  - platform: template
    name: "Maximale Warmwassertemperatur"
    id: Temp_max
    optimistic: true
    min_length: 0
    max_length: 3
    mode: text
    restore_value : true
    initial_value : "55"
  - platform: template
    name: "Maximale Warmwassertemperatur (Montag; Legionellen)"
    id: TempLegi_max
    optimistic: true
    min_length: 0
    max_length: 3
    mode: text
    restore_value : true
    initial_value : "60"
  - platform: template
    name: "Mindest Warmwassertemperatur"
    id: Temp_mindest
    optimistic: true
    min_length: 0
    max_length: 3
    mode: text
    restore_value : true
    initial_value : "45"
  - platform: template
    name: "Hysterese Warmwassertemperatur"
    id: Temp_hysterese
    optimistic: true
    min_length: 0
    max_length: 2
    mode: text
    restore_value : true
    initial_value : "2"    
  - platform: template
    name: "Einspeiseleistung für EIN"
    id: LeistungEin
    optimistic: true
    min_length: 0
    max_length: 5
    mode: text
    restore_value : true
    initial_value : "-1000"
  - platform: template
    name: "Bezugsleistung für AUS"
    id: LeistungAus
    optimistic: true
    min_length: 0
    max_length: 5
    mode: text
    restore_value : true
    initial_value : "250"
  - platform: template
    name: "AMIS RestAPI Adresse"
    id: ip_amis
    mode: text
    optimistic: true
    initial_value: "http://10.0.0.152/rest"
    restore_value : true
    min_length: 10
    max_length: 40
text_sensor:
  - platform: wifi_info
    ip_address:
      name: ESP IP Adresse
      id: relaisboard_ip

# Lese AMIS Reader
http_request:
  useragent: esphome/device
  timeout: 1s
  id: http_request_data

time:
  - platform: sntp
    id: sntp_time
    timezone: Europe/Vienna
    servers:
     - time.metrologie.at
     - time1.utanet.at
     - ts1.univie.ac.at
    on_time: 
      # Jede paar Sekunden den AMIS Reader abfragen 
      - seconds: /5
        then:
          - http_request.get:
              url: !lambda |-
                return ((std::string) esphome::to_string(id(ip_amis).state));
              headers:
                Content-Type: application/json
              verify_ssl: false
              on_response:
                then:
                  - lambda: |-
                      json::parse_json(id(http_request_data).get_string(), [](JsonObject root) {
                        id(saldo).publish_state(root["saldo"]);
                      });
      # 6-17:59 Uhr
      - seconds: /15
        hours: 6-17
        minutes: 0-59 
        days_of_week: 1,3,4,5,6,7
        then:
        - if:
            condition:
              lambda: |-
                return (not(id(AbMittag).state)) and (id(relay_2).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
            then:
            - logger.log: "Relais3 ein"
            - switch.turn_on: relay_3
            - delay: 15s          
            else:
              - if:
                  condition:
                    lambda: |-
                      return (not(id(AbMittag).state)) and (id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                  then:
                  - logger.log: "Relais2 ein"
                  - switch.turn_on: relay_2
                  - delay: 15s
                  else:  
                    - if:      
                        condition:
                          lambda: |-
                            return (not(id(AbMittag).state)) and (not id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                        then:
                        - logger.log: "Relais1 ein"
                        - switch.turn_on: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 6-17
        minutes: 0-59 
        days_of_week: 1,3,4,5,6,7
        then:
        - if:
            condition:
              lambda: |-
                return (not(id(AbMittag).state)) and (id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
            then:
            - logger.log: "Relais3 aus"
            - switch.turn_off: relay_3
            - delay: 15s
            else:
              - if:
                  condition:
                    lambda: |-
                      return (not(id(AbMittag).state)) and (not id(HeizenMindestTemp).state) and (not id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
                  then:
                  - logger.log: "Relais2 aus"
                  - switch.turn_off: relay_2
                  - delay: 15s
                  else:
                    - if:
                        condition:
                          lambda: |-
                            return (not(id(AbMittag).state)) and (not id(HeizenMindestTemp).state) and (not id(relay_2).state) and (not id(relay_3).state) and (id(relay_1).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
                        then:
                        - logger.log: "Relais1 aus"
                        - switch.turn_off: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 6-17
        minutes: 0-59 
        days_of_week: 2               # 2=Montag
        then:
        - if:
            condition:
              lambda: |-
                return (not(id(AbMittag).state)) and (id(relay_2).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
            then:
            - logger.log: "Relais3 ein"
            - switch.turn_on: relay_3
            - delay: 15s          
            else:
              - if:
                  condition:
                    lambda: |-
                      return (not(id(AbMittag).state)) and (id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                  then:
                  - logger.log: "Relais2 ein"
                  - switch.turn_on: relay_2
                  - delay: 15s
                  else:  
                    - if:      
                        condition:
                          lambda: |-
                            return (not(id(AbMittag).state)) and (not id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                        then:
                        - logger.log: "Relais1 ein"
                        - switch.turn_on: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 6-17
        minutes: 0-59 
        days_of_week: 2             # 2=Montag
        then:
        - if:
            condition:
              lambda: |-
                return (not(id(AbMittag).state)) and (id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
            then:
            - logger.log: "Relais3 aus"
            - switch.turn_off: relay_3
            - delay: 15s
            else:
              - if:
                  condition:
                    lambda: |-
                      return (not(id(AbMittag).state)) and (not id(HeizenMindestTemp).state) and (not id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
                  then:
                  - logger.log: "Relais2 aus"
                  - switch.turn_off: relay_2
                  - delay: 15s
                  else:
                    - if:
                        condition:
                          lambda: |-
                            return (not(id(AbMittag).state)) and (not id(HeizenMindestTemp).state) and (not id(relay_2).state) and (not id(relay_3).state) and (id(relay_1).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
                        then:
                        - logger.log: "Relais1 aus"
                        - switch.turn_off: relay_1
                        - delay: 15s    
      # 11-17:59 Uhr
      - seconds: /15
        hours: 11-17
        minutes: 0-59 
        days_of_week: 1,3,4,5,6,7
        then:
        - if:
            condition:
              lambda: |-
                return (id(AbMittag).state) and (id(relay_2).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
            then:
            - logger.log: "Relais3 ein"
            - switch.turn_on: relay_3
            - delay: 15s          
            else:
              - if:
                  condition:
                    lambda: |-
                      return (id(AbMittag).state) and (id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                  then:
                  - logger.log: "Relais2 ein"
                  - switch.turn_on: relay_2
                  - delay: 15s
                  else:  
                    - if:      
                        condition:
                          lambda: |-
                            return (id(AbMittag).state) and (not id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(Temp_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                        then:
                        - logger.log: "Relais1 ein"
                        - switch.turn_on: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 11-17
        minutes: 0-59 
        days_of_week: 1,3,4,5,6,7
        then:
        - if:
            condition:
              lambda: |-
                return (id(AbMittag).state) and (id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
            then:
            - logger.log: "Relais3 aus"
            - switch.turn_off: relay_3
            - delay: 15s
            else:
              - if:
                  condition:
                    lambda: |-
                      return (id(AbMittag).state) and (not id(HeizenMindestTemp).state) and (not id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
                  then:
                  - logger.log: "Relais2 aus"
                  - switch.turn_off: relay_2
                  - delay: 15s
                  else:
                    - if:
                        condition:
                          lambda: |-
                            return (id(AbMittag).state) and (not id(HeizenMindestTemp).state) and (not id(relay_2).state) and (not id(relay_3).state) and (id(relay_1).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(Temp_max).state.c_str()));
                        then:
                        - logger.log: "Relais1 aus"
                        - switch.turn_off: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 11-17
        minutes: 0-59 
        days_of_week: 2               # 2=Montag
        then:
        - if:
            condition:
              lambda: |-
                return (id(AbMittag).state) and (id(relay_2).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
            then:
            - logger.log: "Relais3 ein"
            - switch.turn_on: relay_3
            - delay: 15s          
            else:
              - if:
                  condition:
                    lambda: |-
                      return (id(AbMittag).state) and (id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                  then:
                  - logger.log: "Relais2 ein"
                  - switch.turn_on: relay_2
                  - delay: 15s
                  else:  
                    - if:      
                        condition:
                          lambda: |-
                            return (id(AbMittag).state) and (not id(relay_1).state) and (id(saldo).state < atoi(id(LeistungEin).state.c_str())) and (id(warmwasser).state < (atoi(id(TempLegi_max).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
                        then:
                        - logger.log: "Relais1 ein"
                        - switch.turn_on: relay_1
                        - delay: 15s
      - seconds: /15
        hours: 11-17
        minutes: 0-59 
        days_of_week: 2             # 2=Montag
        then:
        - if:
            condition:
              lambda: |-
                return (id(AbMittag).state) and (id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
            then:
            - logger.log: "Relais3 aus"
            - switch.turn_off: relay_3
            - delay: 15s
            else:
              - if:
                  condition:
                    lambda: |-
                      return (id(AbMittag).state) and (not id(HeizenMindestTemp).state) and (not id(relay_3).state) and (id(relay_2).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
                  then:
                  - logger.log: "Relais2 aus"
                  - switch.turn_off: relay_2
                  - delay: 15s
                  else:
                    - if:
                        condition:
                          lambda: |-
                            return (id(AbMittag).state) and (not id(HeizenMindestTemp).state) and (not id(relay_2).state) and (not id(relay_3).state) and (id(relay_1).state) and (id(saldo).state > atoi(id(LeistungAus).state.c_str()) or id(warmwasser).state >= atoi(id(TempLegi_max).state.c_str()));
                        then:
                        - logger.log: "Relais1 aus"
                        - switch.turn_off: relay_1
                        - delay: 15s    
      # Relais 1,2 ein bzw ausschalten
      - seconds: '*'
        minutes: '*'
        hours: 18,19,20,21    
        then:
        # Relais 1,2 ein bzw ausschalten
        - if:
            condition:
              lambda: |-
                return (not id(relay_1).state) and (id(warmwasser).state < (atoi(id(Temp_mindest).state.c_str())-atoi(id(Temp_hysterese).state.c_str())));
            then:
            - logger.log: "Relais1/2 ein"
            - switch.turn_on: relay_1
            - switch.turn_on: relay_2
            - switch.turn_on: HeizenMindestTemp
            - delay: 30s
        - if:
            condition:
              lambda: |-
                return (id(warmwasser).state >= atoi(id(Temp_mindest).state.c_str()));
            then:
            - logger.log: "Relais1/2 aus"
            - switch.turn_off: relay_1
            - switch.turn_off: relay_2
            - switch.turn_off: HeizenMindestTemp
            - delay: 30s
      # Relais 1,2 um 22:01 ausschalten
      - seconds: 1,2,3,4,5
        minutes: 1
        hours: 22    
        then:
        - logger.log: "Relais1/2 aus"
        - switch.turn_off: relay_1
        - switch.turn_off: relay_2
        - switch.turn_off: HeizenMindestTemp
        - delay: 30s