SmartMi Electric Air Heater
Model reference: ZNNFJ07ZM
SmartMi Electric Air

Available from:


Flashed with:
Serial port

Template for ESP32 device
Works only with a tasmota32 binary. Flashing instructions.

by blakadder

Serial Flashing

Remove the back dust grill, unscrew 6 screws. Remove back plate which is clipped to the shell but it will snap out just by pulling using the handle on the top.

At the top of the heater is the ESP-WROOM-32D Wi-Fi module with everything neatly broken out and labelled on the side.


Connect the serial-to-USB adapter to TX, RX, GND and 3V3. Make sure to ground BOOT pin (GPIO0) to put the Wi-Fi module in flashing mode. Flash tasmota32solo1 binary. If the flash isn’t succeeding disable the MCU by connecting both J3 pins (RST and GND).


After applying the template run a set of commands to configure the serial port:

Backlog SerialSend1 00; SerialBuffer 512; Rule0 1, TelePeriod 30

Next you need a set of rules that will sent necessary replies to MCU queries:

rule1 on serialreceived#data$<result do serialsend3 down MIIO_net_change cloud\r endon on serialreceived#data$<model do serialsend3 ok\r endon on serialreceived#data$<mcu_version do serialsend3 ok\r endon on serialreceived#data$<net do serialsend3 cloud\r endon on serialreceived#data$<time do serialsend3 %time%\r endon on serialreceived#data$<ble_config do serialsend3 ok\r endon on tele-wifi#rssi do serialsend3 down MIIO_net_change local\r endon


This heater is a part of Xiaomi’s MiOT ecosystem which uses a standardised MiOT protocol for communication with the MCU and Xiaomi cloud. More about the protocol here. You can safely ignore the MCU query posted every 500ms tele/smartmi/RESULT = {"SerialReceived":"get_down \r"}

To control the device you send a down set_properties command using SerialSend3. siid and piid target the feature you want with value. Finally every command line needs to end with a carriage return or \r.

The list is formatted as: siid piid - possible values - description

  • 2 2 - true/false - Switch status
  • 2 3 - 1/2 - Heat level (1 = high, 2 = low)
  • 2 4 - 0/1 - Fan mode (0 - not swinging, 1 - swinging)
  • 3 1 - true/false - Beeper sound
  • 4 1 - 0/1/2/4/8 - Countdown timer in hours
  • 6 1 - 0/1/2 - LED brightness (0 - bright, 1 - low, 2 - off)
  • 7 1 - true/false - Child lock
  • 8 1 - 0/15/1 - Button click (notify only)
  • 8 3 - true/false - Return fan to middle position when turning off

For example, to turn the heater on send

serialsend3 down set_properties 2 2 true\r

or change LED brightness to low

serialsend3 down set_properties 6 1 1\r

If a property has changed from previous state it will report as:

{“SerialReceived”:”properties_changed 6 1 1\r”}

Rule1 has some actions to ensure status updates are polled periodically which are reported to

{“SerialReceived”:”properties_changed 2 2 true 2 1 0 2 3 2 2 4 0 8 1 0 3 1 false 4 1 0 6 1 0 7 1 false 8 3 true\r”}

To read the status of all functions and status changes we need to parse it manually. It is possible to program full support for this device with Berry but I opted to forward the status to MQTT and parse it outside (in my case: Home Assistant).

rule2 on serialreceived#data$<properties_changed do publish %topic%/changed_properties %value% endon

Full MiOT spec in formatted JSON grabbed from miot-spec.org.

Home Assistant

First create this automation which will reformat the MiOT output into a nice JSON MQTT message to %topic%/properties:

GitHub Link

Next create an autodiscovery automation to create the Heater climate entity and two switches for child lock and sound control.

GitHub Link