Guide - Medify MA-40 with ESPHome

Just wanted to contribute something simple. I had been getting frustrated by my Medify Air Purifiers having absolutely zero smarts, so I decided to rip my MA-40s and my MA-112 open to get them integrated into home assistant while making no permanent changes to the devices. This guide is very basic, but gets the job done. These changes will disable the front panel on the device, making it 100% managed via Home Assistant/ESPHome. This adds a filter life field as well. I plan to do a guide for the MA-112 as well since it uses an analogue output for controlling fan speed, and also includes a tachometer for fan speed feedback.

This guide has more images to it, but I am limited to one image for this post :frowning:

Start by opening the top of the MA-40 unit, exposing the IO Panel and the Control Board Box. There should be a couple screws near the top holding this one, and the full panel snaps on/off.

Open the Control Board Box to expose the Control Board.

Unplug the cable connecting the Interface Panel and Control Board from the Control Board. We will be using the following pins on this header:

5V - ESP32 Dev Board Power
GND - ESP32 Dev Board GND
ION - DIO for ION control
H - DIO for Fan High
M - DIO for Fan Medium
L - DIO for Fan Low

Plug Jumper Cables into this header for the listed pins:

Lastly, close up the Control Board Box and plug these cables into the ESP32 Dev Board using the following pins:

gpio26 to H
gpio25 to M
gpio33 to L
gpio27 to ION
5V to 5V
GND to GND

Use the following code for ESPHome:

esphome:
  name: ma-40
  friendly_name: MA-40

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: 

ota:
  password: 

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

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

captive_portal:

globals:
  - id: filter_time
    type: int
    restore_value: yes
    initial_value: '0'

interval:
- interval: 1min
  then:
    if:
      condition:
        fan.is_on: ma40
      then:
      - lambda: |-
          id(filter_time) += 1;

sensor:
  - platform: template
    name: Filter On Time
    id: filter_time_disp
    unit_of_measurement: "minutes"
    device_class: "duration"
    state_class: "measurement"
    accuracy_decimals: 0
    lambda: |-
      return id(filter_time);

binary_sensor:
  - platform: template
    name: "Filter End of Life"
    lambda: |-
      if (id(filter_time) > 180000){
        return true;
      } else {
        return false;
      }

button:
  - platform: template
    name: "Reset Filter Life"
    on_press:
      lambda: |-
        id(filter_time) = 0;

switch:
  - platform: gpio
    pin: 26
    name: "High"
    id: high
    interlock: [medium, low]
    internal: true
  - platform: gpio
    pin: 25
    name: "Medium"
    id: medium
    interlock: [high, low]
    internal: true
  - platform: gpio
    pin: 33
    name: "Low"
    id: low
    interlock: [high, medium]
    internal: true
  - platform: gpio
    pin: 27
    name: "Ion"
    id: ion

output:
  - platform: template
    id: custom_fan
    type: float 
    write_action:
      - if:
          condition:
            lambda: return ((state == 0));
          then:
            # action for off
            - switch.turn_off: high
            - switch.turn_off: medium
            - switch.turn_off: low
            - switch.turn_off: ion
      - if:
          condition:
            lambda: return ((state > 0) && (state < 0.4));
          then:
            # action for speed 1
            - switch.turn_off: high
            - switch.turn_off: medium
            - switch.turn_on: low
            
      - if:
          condition:
            lambda: return ((state > 0.4) && (state < 0.7));
          then:
            # action for speed 2
            - switch.turn_off: high
            - switch.turn_off: low
            - switch.turn_on: medium
            
      - if:
          condition:
            lambda: return ((state > 0.7));
          then:
            # action for speed 3
            - switch.turn_off: low
            - switch.turn_off: medium
            - switch.turn_on: high

fan:
  - platform: speed
    id: ma40
    output: custom_fan
    name: "Fan"
    speed_count: 3
2 Likes

Your MA-40 should display in Home Assistant like so:

1 Like

Hey Steven. I have an ma-40uv. It looks like I have the same board as the picture in your post. Except mine has the U1 chip blown. Because it is blown I can’t read the numbers on it to cross reference it so I can order a replacement. You mentioned that you have more pics, any chance you have one showing this chip? Would really appreciate it. My email address is [email protected]
Thanks.

@stevo32792 i wanted to thank you for the excellent write up. I recently purchased a 112. Is there any possibility you might post how you did yours? I would love to follow your guide.

Thanks again.

Matt

Was looking at the board for the 112, based on multi meter it looks like VSP goes from .6v => .65v => .75v => .96v. based on the fan speed button. I haven’t actually tried controlling the fan with the pin though so more testing is needed.

I’m probably not going to look more into this further and just DIY a box air purifier since medify filters are expensive.

Yes! I can put something together tomorrow most likely! I will link the post when I have it up. Sorry for the slow response, I need to turn on email notifications. This gives me time to open up the box and actually measure the pin for the motor control on the MA-112. Just got an oscilloscope in last month for figuring out how to control a Blisslight so I can make sure I got everything right for the MA-112.