# "I" Only - Input Only
# "O" Only - Output Only 
# "IO"     - Can be used as both an Input or Output 
# "X"      - Special functions

# ESP8266 Port Layout
# D0 - IO - Unused
# D1 - X  - SCL
# D2 - X  - SDA
# D3 - IO - Unused
# D4 - IO - Unused
# D5 - IO - Unused
# D6 - I  - Global Switch 1
# D7 - IO - Unused
# D8 - IO - Unused
# A0 - IO - Unused

# mcp23017 Port Layout
# PGA 0-7:
#  0 - I  - Window 1 "Open" Sensor
#  1 - I  - Window 1 "Closed" Sensor
#  2 - I  - Window 2 "Open" Sensor 
#  3 - I  - Window 2 "Closed" Sensor
#  4 - I  - Window 3 "Open" Sensor 
#  5 - I  - Window 3 "Closed" Sensor
#  6 - I  - Global Switch 1
#  7 - IO - Relay Control Window 1 Open
# PGB 0-7:
#  8 - IO - Relay Control Window 1 Closed
#  9 - IO - Relay Control Window 1 Stop
# 10 - IO - Relay Control Window 2 Open
# 11 - IO - Relay Control Window 2 Closed
# 12 - IO - Relay Control Window 2 Stop
# 13 - IO - Relay Control Window 3 Open
# 14 - IO - Relay Control Window 3 Closed
# 15 - IO - Relay Control Window 3 Stop

# H1 Exposed
# MCPA - O  - Interrupt output from pin INTA see mcp23017's datasheet
# MCPB - O  - Interrupt output from pin INTB see mcp23017's datasheet
# MCPR - I  - Reset pin see mcp23017's datasheet
#  RST - I  - Reset pin see NodeMCU's datasheet
#   D0 - IO - Unused
#   D3 - IO - Unused
#   D4 - IO - Unused
#   D5 - IO - Unused
#   D7 - IO - Unused
#   D8 - IO - Unused
#   A0 - IO - Unused

esphome:
  name: windowscontrol
  platform: ESP8266
  board: nodemcuv2
  on_boot:
    then:
      #Let reset all interlcoks and put all the draperies into a safe location (closed)
      - switch.turn_off: open_window_front
      - switch.turn_off: stop_window_front
      - switch.turn_off: window_dark
      - switch.turn_on: close_window_front
      - switch.turn_off: man_open_dinning_wondow
      - switch.turn_off: man_close_dinning_wondow
      - switch.turn_off: man_open_front_wondow
      - switch.turn_off: man_close_front_wondow
      - switch.turn_off: open_window_dinning
      - switch.turn_off: stop_window_dinning
      - switch.turn_on: close_window_dinning
      - delay: 1s
      - switch.turn_off: close_window_dinning
      - switch.turn_off: close_window_front
      - delay: 30s
      #Let Check if we need to engage night mode
      - if:
          condition:
            - sun.is_above_horizon:
          then:
            - logger.log: Sun is above horizon!
            - switch.turn_off: window_dark
          else:
            - switch.turn_on: window_dark
      - switch.turn_off: close_window_front
      - switch.turn_off: close_window_dinning
      #Let force the ESPHome Covers to set there interanl state to this new location
      - cover.control: 
          id: my_front_window
          position: 0%
      - cover.control: 
          id: dinning_window
          position: 0%

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  #manual_ip:
    # Set this to the IP of the ESP
    #static_ip: <IP>
    # Set this to the IP address of the router. Often ends with .1
    #gateway: <GW>
    # The subnet of the network. 255.255.255.0 works for most home networks.
    #subnet: 255.255.255.0
    #dns1: 8.8.8.8
    #dns2: 8.8.4.4

api:
  password: !secret API_password
  reboot_timeout: 1h

# Enable logging
logger:

ota:

web_server:
   port: 80

mcp23017:
  - id: 'mcp23017_hub'
    address: 0x20
i2c:
  sda: D2
  scl: D1
  scan: True
  id: bus_a

time:
  - platform: sntp
    id: sntp_time

sun:
  latitude: !secret latitude
  longitude: !secret longitude
  on_sunrise:
    - then:
        - logger.log: Good morning!
    # Custom elevation, will be called shortly after the trigger above.
    - elevation: 10°
      then:
        - logger.log: Good morning 2!
        - switch.turn_off: window_dark

  on_sunset:
    - then:
        - logger.log: sunset   
        - switch.turn_on: window_dark
    - elevation: 10°
      then:
        - logger.log: Good evening!   
        - switch.turn_on: window_dark
sensor:
  - platform: sun
    name: Windows Sun Elevation
    type: elevation
    
binary_sensor:
  - platform: gpio
    id: sensor_window_front_open
    internal: False
    name: "Temp Front Window Open Sensor"
    pin:
        mcp23017: mcp23017_hub
        number: 0
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: INPUT
        inverted: False
  - platform: gpio
    id: sensor_window_front_closed
    name: "Temp Front Window Closed Sensor"
    internal: False
    pin:
        mcp23017: mcp23017_hub
        number: 1
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: INPUT
        inverted: False
  - platform: gpio
    id: sensor_dinning_open
    name: "Temp Dinning Open Sensor"
    internal: False
    pin:
        mcp23017: mcp23017_hub
        number: 2
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: INPUT
        inverted: False
  - platform: gpio
    id: sensor_dinning_closed
    name: "Temp Dinning Closed Sensor"
    internal: False
    pin:
        mcp23017: mcp23017_hub
        number: 3
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: INPUT
        inverted: False
switch:
## Windows 1
## Front room Window
  - platform: gpio
    id: open_window_front
    restore_mode: ALWAYS_OFF
    name: "Force Front Window Open"
    pin: 
        mcp23017: mcp23017_hub
        number: 8
        #Bar has been inverted
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: &interlock_fw [open_window_front, close_window_front, stop_window_front]
  - platform: gpio
    id: close_window_front
    name: "Force Front Window Closed"
    restore_mode: ALWAYS_OFF
    pin: 
        mcp23017: mcp23017_hub
        number: 7
        #Bar has been inverted
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: *interlock_fw
  - platform: gpio
    id: stop_window_front
    name: "Force Front Window Stop"
    restore_mode: ALWAYS_OFF
    pin: 
        mcp23017: mcp23017_hub
        number: 9
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: *interlock_fw
### Window two
### Dining Romm Window
  - platform: gpio
    id: open_window_dinning
    restore_mode: ALWAYS_OFF
    name: "Force Dinning Room Window Open"
    pin: 
        mcp23017: mcp23017_hub
        number: 10
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: &interlock_fw_2 [open_window_dinning, close_window_dinning, stop_window_dinning]
  - platform: gpio
    id: close_window_dinning
    name: "Force Dinning Room Window Closed"
    restore_mode: ALWAYS_OFF
    pin: 
        mcp23017: mcp23017_hub
        number: 11
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: *interlock_fw_2
  - platform: gpio
    id: stop_window_dinning
    name: "Force Dinning Room Window Stop"
    restore_mode: ALWAYS_OFF
    pin: 
        mcp23017: mcp23017_hub
        number: 12
        # One of INPUT, INPUT_PULLUP or OUTPUT
        mode: OUTPUT
        inverted: True
    interlock: *interlock_fw_2
    
  
  - platform: restart
    name: "Windows Control Restart"
  - platform: template
    name: "Windows Locked Closed - Night"
    id: window_dark
    optimistic: true
    on_turn_on:
      - cover.control: 
          id: my_front_window
          position: 0%
      - cover.control: 
          id: dinning_window
          position: 0%
#safty interlock for night time mode
  - platform: template
    name: "Windows Locked Closed"
    id: window_locked
    optimistic: true
    on_turn_on:
      - cover.control: 
          id: my_front_window
          position: 0%
      - cover.control: 
          id: dinning_window
          position: 0%

#Simple switch for use with automation, interface and google hub control
  - platform: template
    name: "Front Window Open"
    id: man_open_front_wondow
    optimistic: true
    restore_state: no
    assumed_state: false
    on_turn_on:
      then:
        - logger.log: "man_open_front_wondow: Open has been requested"
        - if:
            condition:
              lambda: 'return !id(window_dark).state;'
            then:
              - logger.log: "Windows are opening"
              - cover.control: 
                  id: my_front_window
                  position: 100%
            else:
              - cover.control: 
                  id: my_front_window
                  position: 0%
              - logger.log: "Windows are remaining closed based on night"
              # Notifiy the home user that we recived your open request but setting prevent it
              - homeassistant.service:
                  service: tts.google_say
                  data:
                    message: "Living Room draperies are remaining closed based on it being nighttime or privacy lock being engaged. Please use app to override"
                    entity_id: media_player.living_room_display
        - switch.turn_off: man_open_front_wondow
        - switch.turn_off: man_close_front_wondow
        - logger.log: "man_open_front_wondow: Done: Open has been requested"
  - platform: template
    name: "Front Window Close"
    id: man_close_front_wondow
    restore_state: no
    assumed_state: false
    optimistic: true
    on_turn_on:
      - cover.control: 
          id: my_front_window
          position: 0%
      - switch.turn_off: man_open_front_wondow
      - switch.turn_off: man_close_front_wondow

  - platform: template
    name: "Dinning Room Window Open"
    id: man_open_dinning_wondow
    optimistic: true
    restore_state: no
    assumed_state: false
    on_turn_on:
      then:
        - logger.log: "man_open_dinning_wondow: Open has been requested"
        - if:
            condition:
              lambda: 'return !id(window_dark).state;'
            then:
              - logger.log: "Windows are opening"
              - cover.control: 
                  id: dinning_window
                  position: 100%
            else:
              - logger.log: "Windows are remaining closed based on night"
              - homeassistant.service:
                  service: tts.google_say
                  data:
                    message: "Dinning Room draperies are remaining closed based on it being nighttime or privacy lock being engaged. Please use app to override"
                    entity_id: media_player.living_room_speaker
              - cover.control: 
                  id: dinning_window
                  position: 0%
        - switch.turn_off: man_open_dinning_wondow
        - switch.turn_off: man_close_dinning_wondow
        - logger.log: "man_open_dinning_wondow: Done: Open has been requested"
  - platform: template
    name: "Dinning Room Window Close"
    id: man_close_dinning_wondow
    optimistic: true
    restore_state: no
    assumed_state: false
    on_turn_on:
      - cover.control: 
          id: dinning_window
          position: 0%
      - switch.turn_off: man_open_dinning_wondow
      - switch.turn_off: man_close_dinning_wondow
cover:
- platform: time_based
  name: "Front Window"
  id: my_front_window
  device_class: "curtain"
  open_action:
    then:
      - logger.log: "my_front_window: Open has been requested"
      - if:
          condition:
            lambda: 'return id(window_locked).state || id(window_dark).state;'
          then:
            - switch.turn_on: close_window_front
            - delay: 1s
            - switch.turn_off: close_window_front
            - logger.log: "Windows are locked closed based on safety interlock"
          else:
            - switch.turn_on: open_window_front
            - delay: 1s
            - switch.turn_off: open_window_front
  open_duration: 28s
  close_action:
    - switch.turn_on: close_window_front
    - delay: 1s
    - switch.turn_off: close_window_front
  close_duration: 28s
  stop_action:
    - switch.turn_on: stop_window_front
    - switch.turn_off: man_open_front_wondow
    - switch.turn_off: man_close_front_wondow
    - switch.turn_off: open_window_front
    - switch.turn_off: close_window_front
    - delay: 1s
    - switch.turn_off: stop_window_front
- platform: time_based
  name: "Dinning Room Window"
  id: dinning_window
  device_class: "curtain"
  open_action:
    then:
      - logger.log: "dinning_window: Open has been requested"
      - if:
          condition:
            lambda: 'return id(window_locked).state or id(window_dark).state;'
          then:
            - switch.turn_on: close_window_dinning
            - delay: 1s
            - switch.turn_off: close_window_dinning
            - logger.log: "Windows are locked closed based on safety interlock"
          else:
            - switch.turn_on: open_window_dinning
            - delay: 1s
            - switch.turn_off: open_window_dinning
  open_duration: 5s
  close_action:
    - switch.turn_on: close_window_dinning
    - delay: 1s
    - switch.turn_off: close_window_dinning
  close_duration: 5s
  stop_action:
    - switch.turn_on: stop_window_dinning
    - switch.turn_off: open_window_dinning
    - switch.turn_off: close_window_dinning
    - switch.turn_off: man_open_dinning_wondow
    - switch.turn_off: man_close_dinning_wondow
    - delay: 1s
    - switch.turn_off: stop_window_dinning
