Smartifying a Dehumidifier with ESPHome

I was using a power monitoring smart plug to turn my dehumidifier on and off but decided to make it a bit smarter. I wanted full control of all the functions and feedback of all the states (including the FULL tank alert).

After a bit of poking about with a multimeter on the display board I found that the logic was 5V CMOS, which is excellent as this is compatible with 3.3V TTL that the ESP boards use.

The switches were a different matter. They worked on shorting segments of a resistive ladder. So five open collector output drivers were made up on Veroboard using GP BJTs.

There were just enough GPIOs on an ESP32 mini board (making sure not to use GPIOs that can interfere with the boot process).

Display board fitted back in the dehumidifier:

Plenty of room for the ESP:

Result:

Custom button card:

Screenshot_2021-05-18 Overview - Home Assistant

Initially I was using template text sensors in ESPHome but found I had to use an update interval of at least a second. I don’t like spamming my network with this sort of traffic so I changed the binary sensor ids to names so they would show up in home assistant (states only sent on change) and made some template sensors in home assistant.

The switches were configured in ESPHome to turn themselves off as they are momentary switches.

ESPHome config:

esphome:
  name: lounge-dehumidifier-conrol
  platform: ESP32
  board: mhetesp32minikit

wifi:
  ssid: 'WAPLO'
  password: !secret wifi_pwd
  manual_ip:
    static_ip: 10.1.1.195
    gateway: 10.1.1.1
    subnet: 255.255.255.0

api:
  encryption:
    key: !secret api_encryption_key

logger:

ota:
  password: !secret esp_pwd

binary_sensor:
  - platform: status
    name: "Lounge Dehumidifier Control Status"

  - platform: gpio
    name: Lounge Dehumidifier Check
    pin:
      number: GPIO36

  - platform: gpio
    name: Lounge Dehumidifier Full
    pin:
      number: GPIO39

  - platform: gpio
    name: lounge_dehumidifier_auto_mode
    pin:
      number: GPIO35

  - platform: gpio
    name: lounge_dehumidifier_low_mode
    pin:
      number: GPIO33

  - platform: gpio
    name: lounge_dehumidifier_high_mode
    pin:
      number: GPIO34

  - platform: gpio
    name: lounge_dehumidifier_saving
    pin:
      number: GPIO32
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_turbo
    pin:
      number: GPIO27
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_up
    pin:
      number: GPIO26
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_front
    pin:
      number: GPIO25
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_wide
    pin:
      number: GPIO23
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_2h
    pin:
      number: GPIO22
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_4h
    pin:
      number: GPIO21
      mode: INPUT_PULLDOWN

  - platform: gpio
    name: lounge_dehumidifier_8h
    pin:
      number: GPIO19
      mode: INPUT_PULLDOWN

button:
  - platform: output
    name: 'Lounge Dehumidifier On/Off'
    output: on_off
    icon: "mdi:power"
    duration: 500ms

  - platform: output
    name: 'Lounge Dehumidifier Dry Mode'
    output: dry_mode
    icon: "mdi:air-filter"
    duration: 500ms

  - platform: output
    name: 'Lounge Dehumidifier Laundry Mode'
    output: laundry_mode
    icon: "mdi:tshirt-crew"
    duration: 500ms

  - platform: output
    name: 'Lounge Dehumidifier Swing'
    output: swing
    icon: "mdi:arrow-top-right-bottom-left"
    duration: 500ms

  - platform: output
    name: 'Lounge Dehumidifier Timer'
    output: timer
    icon: "mdi:timer-outline"
    duration: 500ms

output:
  - platform: gpio
    pin: GPIO18
    id: on_off

  - platform: gpio
    pin: GPIO17
    id: dry_mode

  - platform: gpio
    pin: GPIO16
    id: laundry_mode

  - platform: gpio
    pin: GPIO13
    id: swing

  - platform: gpio
    pin: GPIO4
    id: timer

sensor:
  - platform: wifi_signal
    name: "Lounge Dehumidifier Control WiFi Signal"
    update_interval: 15s
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15
          send_first_at: 1
    icon: mdi:wifi

switch:

  - platform: restart
    name: "Lounge Dehumidifier Control Restart"

Home Assistant template sensors:

template:
  - sensor:
      - name: "Lounge Dehumidifier Dry Mode"
        unique_id: faabb2ad-3b63-4258-b81c-47efa5abff5a
        icon: "mdi:air-filter"
        state: >
          {% if is_state('binary_sensor.lounge_dehumidifier_auto_mode', 'on') %}
            Auto
          {% elif is_state('binary_sensor.lounge_dehumidifier_low_mode', 'on') %}
            Low
          {% elif is_state('binary_sensor.lounge_dehumidifier_high_mode', 'on') %}
            High
          {% else %}
            Off
          {% endif %}

      - name: "Lounge Dehumidifier Laundry Mode"
        unique_id: a12cd9ba-44c9-4134-9c2b-982b297ea3db
        icon: "mdi:tshirt-crew"
        state: >
          {% if is_state('binary_sensor.lounge_dehumidifier_saving', 'on') %}
            Saving
          {% elif is_state('binary_sensor.lounge_dehumidifier_turbo', 'on') %}
            Turbo
          {% else %}
            Off
          {% endif %}

      - name: "Lounge Dehumidifier Swing"
        unique_id: b33687a9-ad54-4983-a2fe-989e12943db5
        icon: "mdi:arrow-top-right-bottom-left"
        state: >
          {% if is_state('binary_sensor.lounge_dehumidifier_up', 'on') %}
            Up
          {% elif is_state('binary_sensor.lounge_dehumidifier_front', 'on') %}
            Front
          {% elif is_state('binary_sensor.lounge_dehumidifier_wide', 'on') %}
            Wide
          {% else %}
            Off
          {% endif %}

      - name: "Lounge Dehumidifier Timer"
        unique_id: 7d5e630f-59da-41ee-8e94-c46b19556e42
        icon: "mdi:timer-outline"
        state: >
          {% if is_state('binary_sensor.lounge_dehumidifier_2h', 'on') %}
            2 Hours
          {% elif is_state('binary_sensor.lounge_dehumidifier_4h', 'on') %}
            4 Hours
          {% elif is_state('binary_sensor.lounge_dehumidifier_8h', 'on') %}
            8 Hours
          {% else %}
            Off
          {% endif %}

And a template switch:

- platform: template
  switches:
    lounge_dehumidifier_power:
      friendly_name: Lounge Deumidifier
      unique_id: c916928d-5009-458d-886c-68ffe5646471
      value_template: >-
        {{ not ( is_state('sensor.lounge_dehumidifier_dry_mode', 'Off') and
                  is_state('sensor.lounge_dehumidifier_laundry_mode', 'Off') and
                  is_state('binary_sensor.lounge_dehumidifier_full', 'off')) }}
      turn_on:
      - choose:
        - conditions:
          - condition: state
            entity_id: switch.lounge_dehumidifier_power
            state: 'off'
          sequence:
          - service: button.press
            entity_id: button.lounge_dehumidifier_on_off
      turn_off:
      - choose:
        - conditions:
          - condition: state
            entity_id: switch.lounge_dehumidifier_power
            state: 'on'
          sequence:
          - service: button.press
            entity_id: button.lounge_dehumidifier_on_off
      availability_template: >-
        {{ not ( is_state('sensor.lounge_dehumidifier_dry_mode', 'unavailable') or
                  is_state('sensor.lounge_dehumidifier_laundry_mode', 'unavailable') or
                  is_state('binary_sensor.lounge_dehumidifier_full', 'unavailable')) }}
      icon_template: >
        {% if is_state('switch.lounge_dehumidifier_power', 'on') %}
          mdi:air-humidifier
        {% else %}
          mdi:air-humidifier-off
        {% endif %}

Button Card:

entities:
  - card_type: horizontal-stack
    cards:
      - entity: switch.lounge_dehumidifier_power
        name: Power
        template: switch_button
        type: custom:button-card
      - color_type: blank-card
        type: custom:button-card
      - color_type: blank-card
        type: custom:button-card
      - color_type: blank-card
        type: custom:button-card
    type: custom:hui-element
  - card_type: horizontal-stack
    cards:
      - entity: sensor.lounge_dehumidifier_dry_mode
        template: dehum_button
        tap_action:
          action: call-service
          service: button.press
          service_data:
            entity_id: button.lounge_dehumidifier_dry_mode
        type: custom:button-card
      - entity: sensor.lounge_dehumidifier_laundry_mode
        template: dehum_button
        tap_action:
          action: call-service
          service: button.press
          service_data:
            entity_id: button.lounge_dehumidifier_laundry_mode
        type: custom:button-card
      - entity: sensor.lounge_dehumidifier_swing
        template: dehum_button
        tap_action:
          action: call-service
          service: button.press
          service_data:
            entity_id: button.lounge_dehumidifier_swing
        type: custom:button-card
      - entity: sensor.lounge_dehumidifier_timer
        template: dehum_button
        tap_action:
          action: call-service
          service: button.press
          service_data:
            entity_id: button.lounge_dehumidifier_timer
        type: custom:button-card
    type: custom:hui-element
show_header_toggle: false
title: Lounge Dehumidifier
type: entities

Button Card Template:

button_card_templates:
  dehum_button:
    aspect_ratio: 4/3
    color_type: icon
    hold_action:
      action: more-info
      haptic: selection
    show_label: false
    show_name: true
    show_state: true
    state:
      - styles:
          card:
            - border: solid 1px var(--primary-color)
            - box-shadow: none
          icon:
            - color: var(--button-card-light-color)
        value: 'Off'
      - icon: 'mdi:alert'
        label: Lost
        styles:
          card:
            - border: 'solid 1px #7f7f7f'
            - box-shadow: none
          icon:
            - color: '#ff0000'
            - opacity: 0.6
          label:
            - color: '#7f7f7f'
          name:
            - color: '#7f7f7f'
        value: unavailable
    styles:
      card:
        - border: solid 1px var(--paper-item-icon-active-color)
        - box-shadow: 0px 0px 10px 3px var(--paper-item-icon-active-color)
        - border-radius: 10px
        - padding: 6px 6px 6px 6px
        - margin: 0% 0% 0% 0%
        - '--ha-card-background': 'rgba(0, 0, 0, 0)'
      grid:
        - grid-template-areas: '"i s s" "n n n"'
        - grid-template-rows: 33% auto
        - grid-template-columns: 33% auto
      icon:
        - color: var(--paper-item-icon-active-color)
        - width: 28px
        - padding: 0px 0px 0px 0px
      name:
        - justify-self: middle
        - align-self: end
        - font-size: 14px
        - padding: 0px 0px 0px 0px
        - color: var(--primary-text-color)
        - white-space: normal
      state:
        - font-size: 12px
        - justify-self: right
        - padding: 0px 0px 0px 0px
        - color: var(--secondary-text-color)

Wiring:

Function      Colour     GPIO
+5	          Red        VCC
Gnd           Black      GND
Check         Brown 1    39
Full          Brown 2    36
Auto	      Orange 1   35
High	      Orange 2   34
Low           Orange 3   33
Saving        Purple 1   32
Turbo         Purple 2   27
Up            White 1    26
Front         White 2    25
Wide          White 3    23
2H            Yellow 1   22
4H            Yellow 2   21
8H            Yellow 3   19
On/Off        Blue 0     18
Dry Mode      Blue 1     17
Laundry Mode  Blue 2     16
Swing         Blue 3     13
Timer         Blue 4     4

EDIT: Updated to use ESPHome Template buttons.

11 Likes

Awesome!

I am planning a similar hack for my old ducted A/C but have put it off since winter is upon us. I’ll be able to track / set modes but not temperature / fan speed as the temp / fan speed adjustment is via a dial and I can’t see a good way of interfacing to it without affecting the standard circuitry (and no space for a rotary encoder).

What sort of dial?

Rotary Switch?

Potentiometer?

This is one of the coolest things I’ve seen.

Can I ask you, how did you create a “blueprint” for your solution?

Like, you have a control board, that goes to a micro controller of some sort that runs a driver which in its turn then provide power to the motor and heating/cooling element. Right?

But here my understanding of how to control something like this is weak. It’s of course easy to jump into a cable going from say a temperature button to the microcontroller. But then what? How do you know what to write into the configuration for the esp32?

Like I got a kitchen fan that I want to turn smart.

I can cut in between the control board and the PIC microcontroller. But then what?

I connected GPIOs configured as binary sensors in ESPHome to the display led drivers on the control board (CMOS shift registers) and ESPHome GPIOs configured as momentary switches to home made open collector drivers that were connected in parallel with the existing switches. All of this was on the display board. I didn’t go near the control board (other than to check it could supply enough current for the ESP). I did not cut anything. All connections were in parallel with the existing circuit.

In your case you need to identify the following:

  1. What voltage does the PIC operate on?
  2. What control signals are present (speed control, on-off, etc
).
  3. What output display options it has.
1 Like

I think I understand, but just to be sure, what is “home made open collector drivers”?

oXJya

Inspiring work @tom_l ! Looks like a super neat solution you’ve done there.

Out of interest what is the theme that you are using in the screenshot you posted of your custom card? - It looks really nice!

https://community.home-assistant.io/t/day-and-night/116232/29

1 Like

I haven’t fully inspected it yet to find out. At a guess I’d say it will be a potentiometer.

I am super interested in this concept. I have just bought the Smart Ultimate Dehumidifier from Breville - Its not ESP32 smart, but is suitable for our larger room sizes!

With your solution Tom, I think your ‘open collectors’ are NPN transisters - Is that correct?

If so, I have a couple of questions
 I know transistors have legs classed as Base, Emitter & Collectors.

Q1: In your sketch that shows the Q1 BC547, which is the Base, Emitter & Collector?
Q2: “To GPIO Output” on your sketch I presume is pretty clear, it will goto the ESP32 (via the Resistor R1)?
Q3: Do you solder the remaining 2 NPN legs to either side of each of the LEDs?
Q4: Finally, what ESp32 board did you use? Seems like you needed a lot of GPIO!

Thanks
Jon

How to make Humidifier card - Home Assistant (home-assistant.io) card from esphome entities?

There is no dehumidifier component in ESPHome.