Washing Machine

From Tyrel's Wiki

I copied a lot from Grandebro on Reddit

Bill of Materials

ESPHome

I didn't use the substitutions code, as I didn't feel like getting that working, so my copy of the code is:

esphome:
  name: power_monitor_plug_washingmachine
  platform: ESP8266
  board: esp01_1m
  esp8266_restore_from_flash: yes
  on_boot:
    then:
      - lambda: id(text_last_run).publish_state(id(last_run));
          id(text_last_run_time).publish_state(id(last_run_time));
          if (id(prev_running))
          {
          id(text_status).publish_state("Running");
          }
          else
          {
          id(text_status).publish_state("Idle");
          }

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: washingmachine_s31
    password: !secret wifi_ap_password

captive_portal:

logger:
  baud_rate: 0

uart:
  rx_pin: RX
  baud_rate: 4800

api:

ota:

time:
  - platform: homeassistant
    id: ha_time
    timezone: America/Chicago

globals:
  - id: duration
    type: int
    restore_value: yes
    initial_value: "0"
  - id: last_run_time
    type: char[28]
    restore_value: yes
  - id: prev_running
    type: int
    restore_value: yes
    initial_value: "0"
  - id: last_run
    type: char[12]
    restore_value: yes
script:
  - id: record
    then:
      - lambda:
          snprintf(id(last_run), 12, "%02d/%02d %2d:%2d", id(ha_time).now().month, id(ha_time).now().day_of_month,  id(ha_time).now().hour,  id(ha_time).now().minute);
          id(text_last_run).publish_state(id(last_run));
          id(duration) = id(ha_time).now().timestamp - id(duration);
          if (id(duration) / 3600)
          {
          snprintf(id(last_run_time), 28, "%d hour%s and %d minute%s", ((id(duration) / 3600)>442570)?1:(id(duration) / 3600), ((id(duration) / 3600) > 1) ? "s":"", (id(duration) / 60) % 60, (((id(duration) / 60) % 60) != 1)? "s":"");
          }
          else if (id(duration) / 60)
          {
          snprintf(id(last_run_time), 28, "%d minute%s and %d second%s", id(duration) / 60, ((id(duration) / 60) > 1) ? "s":"", id(duration) % 60, ((id(duration) % 60) != 1)? "s":"");
          }
          else
          {
          snprintf(id(last_run_time), 28, "%d second%s", id(duration) % 60, ((id(duration) % 60) != 1)? "s":"");
          }
          id(text_last_run_time).publish_state(id(last_run_time));
          id(prev_running) = 0;
          id(text_status).publish_state("Finished");
switch:
  - platform: gpio
    name: Power Monitor Plug washingmachine
    pin: GPIO12
    id: plug
    icon: "mdi:power-plug"
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_off:
      - if:
          condition:
            - text_sensor.state:
                id: text_status
                state: "Running"
          then:
            - script.execute: record
sensor:
  - platform: cse7766
    update_interval: 3s
    power:
      id: power
      icon: "mdi:flash-circle"
      name: Power Monitor Plug washingmachine
      filters:
        - lambda: if (id(plug).state) {
            return x;
            } else {
            return 0;
            }
      on_value_range:
        - above: 105
          then:
            - if:
                condition:
                  not:
                    - text_sensor.state:
                        id: text_status
                        state: "Running"
                then:
                  - lambda: id(duration) = id(ha_time).now().timestamp;
                      id(prev_running) = 1;
                      id(text_status).publish_state("Running");

      on_value:
        - if:
            condition:
              and:
                - text_sensor.state:
                    id: text_status
                    state: "Running"
                - for:
                    time: 21s
                    condition:
                      sensor.in_range:
                        id: power
                        below: 20
            then:
              - script.execute: record
        - if:
            condition:
              and:
                - text_sensor.state:
                    id: text_status
                    state: "Finished"
                - for:
                    time: 10min
                    condition:
                      switch.is_off: plug
                - for:
                    time: 10min
                    condition:
                      sensor.in_range:
                        id: power
                        below: 20
            then:
              - lambda: id(text_status).publish_state("Idle");
        - if:
            condition:
              and:
                - or:
                    - text_sensor.state:
                        id: text_status
                        state: "Idle"
                    - text_sensor.state:
                        id: text_status
                        state: "Finished"
                - for:
                    time: 10min
                    condition:
                      switch.is_on: plug
                - for:
                    time: 10min
                    condition:
                      sensor.in_range:
                        id: power
                        below: 20
            then:
              - switch.turn_off: plug
text_sensor:
  - platform: template
    name: Power Monitor Plug washingmachine Status
    id: text_status
    lambda: |-
      return {};
  - platform: template
    name: Power Monitor Plug washingmachine Last Run Time
    icon: "mdi:timelapse"
    id: text_last_run_time
    lambda: |-
      return {};
  - platform: template
    name: Power Monitor Plug washingmachine Last Run
    id: text_last_run
    icon: "mdi:clock-outline"
    lambda: |-
      return {};
output:
  - platform: esp8266_pwm
    id: led
    pin:
      number: GPIO13
      inverted: True
light:
  - platform: monochromatic
    id: status_led
    output: led
    restore_mode: ALWAYS_OFF
binary_sensor:
  - platform: status
    id: connection_status
    on_press:
      then:
        - light.turn_on: status_led
    on_release:
      then:
        - light.turn_off: status_led
  - platform: gpio
    pin:
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: True
    id: button
    on_press:
      then:
        - switch.toggle: plug


Lovelace

Washing machine dashboard.png

For this I made a full Panel Lovelace Dashboard

type: entities
entities:
  - entity: sensor.power_monitor_plug_washingmachine
    name: Watts
  - entity: sensor.power_monitor_plug_washingmachine_last_run
    name: Last Run Date
  - entity: sensor.power_monitor_plug_washingmachine_last_run_time
    name: Duration of Last Run
    secondary_info: last-changed
  - entity: sensor.power_monitor_plug_washingmachine_status
    name: Currently Running?
title: Washing Machine
show_header_toggle: false
state_color: true
header:
  type: graph
  entity: sensor.power_monitor_plug_washingmachine
  hours_to_show: 1
  detail: 2