본문 바로가기
Hardware/Home Assistant

Sonoff Pow R2로 세탁기 상태 확인 및 종료 알림

by lovey25 2020. 11. 11.

작년에 삼성 건조기를 구입했었는데 스마트싱스(스마트띵즈?)가 지원되는 모델이었습니다. 아내분께서 건조가 끝나면 핸드폰으로 알림이 온다며 너무 좋다며 침이 마르도록 칭찬을 했었죠. 그리고 그 참에 세탁기도 새로 살걸 이라며 아쉬워한 적이 있었습니다. 와이파이가 없는 구형 세탁기의 상태도 핸드폰으로 확인할 수 있으면 좋을 텐데 오늘은 그 방법에 대해서 정리해 보겠습니다.

요즘은 "Home Assistant"(HA)를 알아가는데 많은 시간을 보내고 있는데 역시나 HA에는 모든 답이 있었습니다. 게다가 제가 원하는 그 기능 그대로를 구현한 예제가 있어서 한번 적용해 봤습니다. 아래 링크입니다.

 

Gio-dot/Washing-Machine-Sonoff-Pow-R2-Esphome

Contribute to Gio-dot/Washing-Machine-Sonoff-Pow-R2-Esphome development by creating an account on GitHub.

github.com

Sonoff Pow R2라는 스마트 스위치를 세탁기 전원코드에 연결해서 사용하는 예제입니다. Sonoff Pow R2는 연결된 제품이 사용하는 전력량을 모니터링 할 수 있는 기능이 있습니다. 그래서 세탁기가 세탁코스별로 사용하는 전력량이 다른 점을 이용해서 우회적으로 세탁기 상태를 모니터링하는 방법입니다.

우선 준비물을 준비합니다.

USB to TTL Adapter

Sonoff와 컴퓨터를 연결해줄 USB To TTL 아답터가 필요합니다. 3.3V레벨이 사용가능해야 합니다. 

그리고 가장 중요한 Sonoff Pow R2를 펌웨어를 지운 상태로 하나 준비합니다. Sonoff Pow R2제품에 대해서는 이전 글에서 소개를 했었는데 펌웨어 작업에 대한 상세한 내용은 여기를 참고해주세요. 

그리고 전기선 연결작업하는데 필요한 드라이버, 칼 등등 준비합니다.

그리고 콘센트와 플러그 각 1구씩 준비를 하는데 세탁기 전원코드를 잘라서 Sonoff를 직결해도 되겠지만 역시나 고가의 전자제품에 손대는 건 조심스러워서 Sonoff가 연결된 연장 케이블 형태로 만들려고 합니다. 그래서 조립식 콘센트와 플러그도 구매했습니다.

Sonoff Pow R2 펌웨어 업로드

Sonoff Pow에 세탁기의 소모전력에 따라 상태를 파악해주는 펌웨어를 올려보겠습니다. 위에 링크된 Github페이지로 가서 "sonoff_pow_r2_w_machine.yaml" 파일 내용을 복사합니다.

그리고 HA의 ESPHome 메뉴를 열고 새로운 노드를 생성해 줍니다. 저는 이름을 "laundry_machine" 이라고 했습니다. 

더보기
esphome:
  name: laundry_machine
  platform: ESP8266
  board: esp12e

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Laundry Machine Fallback Hotspot"
    password: !secret wifi_password

captive_portal:

# Enable logging
logger:
  baud_rate: 0

uart:
  rx_pin: RX
  baud_rate: 4800

# Enable Home Assistant API
api:
  password: !secret ota_password

ota:
  password: !secret ota_password

time:
  - platform: sntp
    id: my_time
    
################################################################################

binary_sensor:
  - platform: gpio
    pin:
      number: GPIO0
      mode: INPUT_PULLUP
      inverted: True
    name: "Sonoff POW Button"
    internal: true
    on_press:
      - switch.toggle: relay

################################################################################
#                               Machine running                                #
################################################################################
  - platform: template
    name: "RUN"
    id: machine_running
    filters:
      - delayed_on: 60s # MINIMUM TIME TO AVOID FALSE POSITIVES
      - delayed_off: 300s
    lambda: |-
      if (isnan(id(power).state)) {
        return {};
      } else if (id(power).state > 4) {
        // Running
        return true;
      } else {
        // Not running
        return false;
      }
    on_press:
      then: # at cycle start i reset all binary sensors
        - lambda: |-  
            {
              id(machine_end).publish_state(false);
              id(minimum_working_time).publish_state(false);
              id(cycle_centrifughe).publish_state(false);
              id(cycle_drain).publish_state(false);
            }
        - light.turn_on: led
    on_release:
      then: # at the end of cycle turn on end cycle
        - lambda: |-  
            {
              id(machine_end).publish_state(true);
            }        
################################################################################
#                           Minimum duration cycle                             #
################################################################################
  - platform: template
    name: "Washing Machine Minimum time"
    internal: true # minimum working time 30m
    id: minimum_working_time 
    filters:
      - delayed_on: 30min
      - delayed_off: 180s
    lambda: |-
      if (isnan(id(power).state)) {
        return {};
      } else if (id(power).state > 4) {
        // Running
        return true;
      } else {
        // Not running (le due graffe significa che non fa nulla)
        return {};
      }
################################################################################
#                                Centrifuge                                    #
################################################################################
  - platform: template
    name: "CENTRIFUGE"
    id: cycle_centrifughe
    filters:
      - delayed_on: 60s
    # >< 90W-400W for 60s (centrifuge)  010520 changed threshold to 100W
    lambda: |-  
      if (isnan(id(power).state)) {
        return {};
      } else if ( (id(power).state > 100)&&(id(power).state < 400)&&(id(minimum_working_time).state) ){
        // Running
        return true;
      } else {
        // Not running (le due graffe significa che non fa nulla)
        return {};
      }
################################################################################
#                                Water drain                                   #
################################################################################
  - platform: template
    name: "DRAIN"
    id: cycle_drain
    filters:
      - delayed_on: 60s
    # >< 15W-50W for 60s (drain pump)  
    lambda: |-  
      if (isnan(id(power).state)) {
        return {};
      } else if ( (id(power).state > 15) && (id(power).state < 60) && (id(cycle_centrifughe).state) ){
        // Running
        return true;
      } else {
        // Not running (le due graffe significa che non fa nulla)
        return {};
      }                             
################################################################################
#                                 Machine end                                  #
################################################################################
  - platform: template
    name: "END"
    id: machine_end
    on_press:
      - light.turn_off: led     
      
################################################################################

switch:
  - platform: gpio
    id: relay
    pin: GPIO12
    name: "Sonoff POW Relay"
    restore_mode: ALWAYS_ON

output:
  - platform: esp8266_pwm
    id: pow_blue_led
    pin:
      number: GPIO13
      inverted: True

light:
  - platform: monochromatic
    name: "Sonoff POW Blue LED"
    internal: true
    output: pow_blue_led
    id: led

sensor:
  - platform: wifi_signal
    name: "Sonoff POW WiFi Signal"
    update_interval: 60s
  - platform: uptime
    name: "Sonoff POW Uptime"
  - platform: cse7766
    update_interval: 2s
    current:
      name: "Sonoff POW Current"
      id: curr
      internal: true
    voltage:
      name: "Sonoff POW Voltage"
      id: volt
      internal: true
    power:
      name: "Sonoff POW Power"
      id: power
      internal: true
      # on_value_range:
      #   - above: 4.0
      #     then:
      #       - light.turn_on: led
      #   - below: 3.0
      #     then:
      #       - delay: 60s
      #       - light.turn_off: led
  - platform: total_daily_energy ############################
    name: "Sonoff POW R2 Total Daily Energy"
    power_id: power 
    filters:
        # Multiplication factor from W to kW is 0.001
      - multiply: 0.001
    unit_of_measurement: kWh
    accuracy_decimals: 1      

################################################################################
#                         Slow sensors for Home assistant                      #
################################################################################

  - platform: template #########################
    name: "Sonoff Pow Current Slow"
    lambda: |-
      if (id(curr).state) {
        return (id(curr).state);
      } else {
        return 0;
      }
    unit_of_measurement: A
    icon: "mdi:alpha-a-circle"
    update_interval: 90s
  
  - platform: template #########################
    name: "Sonoff Pow Voltage Slow"
    lambda: |-
      if (id(volt).state) {
        return (id(volt).state);
      } else {
        return 0;
      }
    unit_of_measurement: V
    icon: "mdi:alpha-v-circle"
    update_interval: 90s
  
  - platform: template #########################
    name: "Sonoff Pow Power Slow"
    lambda: |-
      if (id(power).state) {
        return (id(power).state);
      } else {
        return 0;
      }
    unit_of_measurement: W 
    icon: "mdi:alpha-w-circle"
    update_interval: 90s
  
text_sensor:
  - platform: version
    name: "Sonoff POW ESPHome Version"

원래 코드에서 수정한 부분은 4행입니다. 펌웨어가 사용될 보드의 종류를 지정하는 부분인데 펌웨어의 용량이 크지않기 때문에 수정하지 않아도 될 것 같은데 전 Sonoff Pow R2의 메모리는 4MB이기 때문에 거기에 비슷한 설정인 esp12e로 수정해 봤습니다. 그리고 WIFI네트워크 접속 정보와 사용할 각종 비밀번호도 수정해서 "SAVE"합니다.

새로 만든 노드의 추가메뉴에서 "Complie"을 눌러서 펌웨어의 바이너리 파일을 생성합니다.

 

네트워크와 센세등 여러 가지 기능이 포함된 펌웨어라 그런지 컴파일에 시간이 오래 걸리네요. 위 화면과 같이 컴파일이 끝나고 나면 하단에 "Download binary"를 눌러서 펌웨어를 다운로드합니다. 이제 이 파일을 Sonoff pow에 올려주면 됩니다.

esptool.py --p COM5 write_flash -fs 4MB -fm dout 0x0 laundry_machine.bin

명령 프롬포트창을 하나 열어서 위 명령어로 펌웨어를 올려줍니다.

배선 연결

이제 컴퓨터와 연결된 선은 제거하고 전원선을 연결해 보겠습니다.

입력과 출력 각각 3개의 전선이 연결되는 구조입니다. 접지, 중성선(N), 활선(L)으로 구분되는데 접지는 녹색, 중성선은 하늘색, 활선은 갈색으로 맞추었습니다. 각 배선 위치는 직접 확인하시고 연결하는 게 좋은데 집마다 활선과 중선선의 위치가 다른 경우도 있다고 합니다. 그리고 Sonoff Pow가 동작하는데 접지가 꼭 필요한지는 확인해 보지 않았는데 세탁기에서 따로 접지를 하지 않고 있기 때문에 접지선까지 매뉴얼대로 잘 연결해 주었습니다.

일단 Sonoff pow는 세탁기옆 콘센트 벽에 붙였습니다. 매번 느끼는 건데 선정리가 가장 어려워요.. 콘센트 길이를 너무 짧게 잡아서 어떻게 고정하지 못하고 달랑거리는 상태가 되었는데 나중에 선을 좀 더 길게 잡아서 옆에 다시 붙여줘야겠어요. 선 지저분하다고 또 한소리 듣게 생겼네요.

HA 설정

이제 HA에서 마무리 작업만 남았습니다. ESPHome 기반이기 때문에 정상적으로 동작을하고 있다면 HA 서버에서 자동으로 신규 장비로 인식하여 알림을 보내줍니다.

체키라웃~ 눌러주면 비밀번호를 넣으라고 나오는데 당황하지 말고 앞에서 펌웨어 만들때 yaml파일에서 지정한 비번을 넣어줍니다. 전 언제부터 계속 admin이라고 습관처럼 쓰고 있네요

설정 >> 기기 >> laundry_machine 메뉴로 이동해서 인식된 구성요소를 확인합니다.

다양한 정보들이 올라오고 있지만 대부분 불필요한 정보들입니다. 꼭 알아야 하는건 세탁기가 지금 돌아가고 있는지 아닌지 그러고 더 나가서 지금 탈수가 시작됐는지 뭐 그런 정보이겠죠. 상태 정보 중 마지막에 있는 Run, End, Drain, Centrifuge의 엔티티가 그 상태를 표시하는 부분인데요. 저는 "state_filter" 옵션을 이용해서 "on"상태인 엔티티만 카드로 표시되도록 만들어봤습니다. 그리고 저 많은 정보 값이 아까워서 지난 3시간의 전력량 변화 그래프를 표시하는 카드도 옆에 추가하였습니다. 아 그리고 영어로 된 이름은 친숙하지 않아서 "세탁기 시작, 세탁기 배수, 세탁기 탈수, 세탁기 종료"로 이름을 고쳤어요.

type: horizontal-stack
cards:
  - card:
      type: glance
      show_icon: true
      show_state: false
    type: entity-filter
    name: 상태
    entities:
      - binary_sensor.run
      - binary_sensor.end
      - binary_sensor.centrifuge
      - binary_sensor.darin
    state_filter:
      - 'on'
  - type: sensor
    graph: line
    entity: sensor.sonoff_pow_power_slow
    name: 전력사용량
    hours_to_show: 3

lovelace카드의 설정은 위와 같이 만들어봤습니다.

현재 탈수 중인 상태이고 곧 세탁이 완료될 예정인데 HA에서도 그 상태를 잘 인식하고 있네요. 다만 잔여시간 등은 확인할 방법이 없으니 이부분은 꼼수가 없을지 고민 좀 해 봐야 할 것 같습니다. 그런데 시작 상태와 탈수 상태가 동시에 올라와 있습니다.

사용한 예제에서는 사용전력이 4W이상이면 RUN 상태가 활성화되고 15~60W는 DRAIN, 100~400W는 CENTRIFUGE 상태가 활성화되도록 프로그램되어 있습니다. 그렇다 보니 동작 상태가 겹치게 표시되기 때문에 "entity-filter"로만 표시하기에는 한계가 있습니다. 이 부분은 수정을 해야 할 것 같네요.

아래는 2번의 세탁과정에서 각 상태의 활성여부를 확인한 결과입니다.

세탁기의 시작과 종료는 정확하게 인식이 되는데, 탈수 및 배수를 인식한 시점이 좀 이상하죠? 로직에 수정이 필요해 보입니다.

그런데 전력값 범위로 세탁, 탈수, 배수 등을 구분하기에는 무리가 좀 있어 보입니다. 첫 번째 세탁코스에서는 온수를 사용해서 2000W에 육박하는 전력사용량이 기록되긴 했으나 두 번째 세탁코스는 냉수만 사용했기 때문에 오히려 탈수 때보다 전기 사용량이 더 적은 모습입니다. 따라서 세탁코스를 인식하기 위해서는 전력 범위보다는 전력 패턴을 인식하도록 수정하는 게 타당해 보입니다. 적어도 탈수 시 단계적으로 전력량이 증가하는 패턴은 사용할 수 있을 것 같네요.

이제 마지막으로 세탁기가 종료되면 핸드폰으로 알림이 오도록 자동화 설정해 보겠습니다. automation.yaml 설정은 아래와 같습니다.

- id: '1604707676988'
  alias: 세탁끝 알림
  description: 세탁기 종료 센서가 센싱되면 메시지 전송
  trigger:
  - type: turned_on
    platform: device
    device_id: c3390ac20872ff75dca6b150d8781ce5
    entity_id: binary_sensor.end
    domain: binary_sensor
  condition: []
  action:
  - service: notify.mobile_app_k
    data:
      message: 빨래가 끝났습니다. 건조기에 옮겨주세요.
  mode: single

이제 세탁기가 종료되면 핸드폰으로 알림을 받을 수 있습니다. 가끔 세탁기가 끝나고 건조기로 옮기는걸 까먹어서 다음날 쉰내 나는 빨래를 다시 돌리는 참사가 있기도 했는데 이제 그런 일은 피할 수 있을 것 같습니다. 

 

끝!

728x90

댓글2