Git Product home page Git Product logo

esphome-miot's Introduction

ESPHome components for MIoT devices

These ESPHome components are designed for MIoT devices which adhere to the Xiaomi MIoT Serial Communication protocol.

Such devices contain two microcontrollers, one actually controls the hardware, and the other acts as a LAN/cloud gateway.

These components allow you to replace the firmware on the latter, hence liberating your devices from the vendor cloud.

Since this uses ESPHome, adding your liberated devices to Home Assistant becomes a breeze with the official integration:

controls sensors config diag

Supported devices

There are probably many more devices that could be supported, currently there are ESPHome configs for the following:

Device Model Version Wiki ESPHome Config MIoT Specification
Mi Air Purifier 3C zhimi.airp.mb4a
zhimi.airpurifier.mb4
link zhimi.airp.mb4a link
link
Xiaomi Smart Air Purifier 4 zhimi.airp.mb5 link zhimi.airp.mb5 link
Xiaomi Smart Air Purifier 4 Lite zhimi.airp.rmb1 link zhimi.airp.rmb1 link

Some of the devices has more than one model versions (like Mi Air Purifier 3C). If their MIoT specifications are identical, the ESPHome config will be compatible with all of them.

Building a firmware

Either download an ESPHome config or create your own (see below) and feed it to ESPHome to build the firmware.

There's no need to clone this repo, unless you plan to contribute - which would be very welcome!

Adding devices

First, look up the desired device on the Xiaomi MIoT Spec site.

Each device defines its service (SIID) and property (PIID) IDs. You just have to add all the desired properties with their according IDs to your ESPHome yaml config.

For examples, see the supported devices table above and compare a config against its specification.

Once your newly added device is working, please open a PR to add its config here!

Feedback

Please feel free to open issues and/or pull requests here.

Alternatively, there's a thread on the official ESPHome forums.

Inspired by

https://github.com/jaromeyer/mipurifier-esphome

esphome-miot's People

Contributors

cristianchelu avatar dhewg avatar gfduszynski avatar mguentner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

esphome-miot's Issues

Heartbeat SIID/PIID not really optional

I'm trying to create a config for Smart Pet Food Feeder (mmgg.feeder.fi1) which doesn't need a heartbeat SIID/PIID and discovered that even though miot_heartbeat_siid and miot_heartbeat_piid are defined as Optional in the config validator schema, they don't have a default set in __main__.py.

With the following yaml I get no editor warnings but the below error on compilation.

external_components:
  source: github://dhewg/esphome-miot@main
# ...
miot:
  id: miot_main
# ...
INFO ESPHome 2023.12.9
INFO Reading configuration /config/pet-feeder.yaml...
INFO Generating C++ source...
Traceback (most recent call last):
  File "/usr/local/bin/esphome", line 33, in <module>
    sys.exit(load_entry_point('esphome', 'console_scripts', 'esphome')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 1041, in main
    return run_esphome(sys.argv)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 1028, in run_esphome
    rc = POST_CONFIG_ACTIONS[args.command](args, config)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 407, in command_compile
    exit_code = write_cpp(config)
                ^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 192, in write_cpp
    generate_cpp_contents(config)
  File "/esphome/esphome/__main__.py", line 204, in generate_cpp_contents
    CORE.flush_tasks()
  File "/esphome/esphome/core/__init__.py", line 679, in flush_tasks
    self.event_loop.flush_tasks()
  File "/esphome/esphome/coroutine.py", line 246, in flush_tasks
    next(task.iterator)
  File "/esphome/esphome/__main__.py", line 184, in wrapped
    await coro(conf)
  File "/config/.esphome/external_components/b0e0b644/components/miot/__init__.py", line 34, in to_code
    cg.add(var.set_heartbeat_config(config[CONF_MIOT_HEARTBEAT_SIID], config[CONF_MIOT_HEARTBEAT_PIID]))
                                    ~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
KeyError: 'miot_heartbeat_siid'

This yaml snippet works as intended though and no heartbeat message is being sent to the MCU.

# ...
miot:
  id: miot_main
  miot_heartbeat_siid: 0
  miot_heartbeat_piid: 0
# ...

ESPHome 2023.12.9
esphome-miot@d64d16b

P.S. Thanks for this repo! I already have some parts of the config working beatifully for my device.

Support switch and binary_sensor as int

The specs for Smart Pet Food Feeder (mmgg.feeder.fi1) use a uint8 0 ~ 1 value instead of a boolean true ~ false to read or control the status of some properties, for example SIID 6 PIID 1 (Child Lock), SIID 3 PIID 1 (Indicator Lights), SIID 4 PIID 8 (Food outlet door) and SIID 4 PIID 9 (Food storage cover).

I'm not really sure if this should be handled as a configuration option in this component or if it's better to leave it as a combination of filters in the esphome config (or I missed some obvious solution, in which case I'm sorry for the time waste!).

I have the following configuration:

binary_sensor:
  - platform: "miot"
    miot_siid: 4
    miot_piid: 9
    name: "Top Lid"
    device_class: opening
  - platform: "miot"
    miot_siid: 4
    miot_piid: 8
    name: "Food door"
    device_class: opening
    
switch:
  - platform: "miot"
    miot_siid: 3
    miot_piid: 1
    name: "Indicator lights"
    icon: mdi:lightbulb
    entity_category: config
  - platform: "miot"
    miot_siid: 6
    miot_piid: 1
    name: "Child Lock"
    icon: mdi:lock
    inverted: yes
    entity_category: config

For the Child lock switch, here's a verbose log for triggering it via the mcu_command service with command: "set_properties 6 1 0"

[19:14:19][D][miot:125]: Queuing MCU command 'set_properties 6 1 0'
[19:14:19][V][miot:091]: Received MCU message 'get_down'
[19:14:19][V][miot:174]: Sending reply 'down set_properties 6 1 0' to MCU
[19:14:19][V][miot:091]: Received MCU message 'result 6 1 0'
[19:14:19][V][miot:174]: Sending reply 'ok' to MCU
[19:14:19][V][miot:091]: Received MCU message 'properties_changed 6 1 0'
[19:14:19][V][miot.switch:011]: MCU reported switch 6:1 is: OFF
[19:14:19][V][miot:174]: Sending reply 'ok' to MCU

The inverted switch is now on in the UI, and toggling it back off results in the following verbose log

[19:16:18][D][switch:016]: 'Child Lock' Turning OFF.
[19:16:18][V][miot.switch:017]: Setting switch 6:1 ON
[19:16:18][D][miot:125]: Queuing MCU command 'set_properties 6 1 true'
[19:16:18][D][switch:055]: 'Child Lock': Sending state OFF
[19:16:18][V][miot:091]: Received MCU message 'get_down'
[19:16:18][V][miot:174]: Sending reply 'down set_properties 6 1 true' to MCU
[19:16:19][V][miot:091]: Received MCU message 'result 6 1 0'
[19:16:19][V][miot:174]: Sending reply 'ok' to MCU
[19:16:19][V][miot:091]: Received MCU message 'properties_changed 6 1 0'
[19:16:19][V][miot.switch:011]: MCU reported switch 6:1 is: OFF
[19:16:19][D][switch:055]: 'Child Lock': Sending state ON
[19:16:19][V][miot:174]: Sending reply 'ok' to MCU

For the read-only top lid state, here's the verbose log when I physically open it:

[19:18:33][V][miot:091]: Received MCU message 'properties_changed 4 8 1'
[19:18:33][V][miot.binary_sensor:011]: MCU reported sensor 4:8 is: OFF
[19:18:33][V][miot:174]: Sending reply 'ok' to MCU

and when I physically close it back:

[19:19:35][V][miot:091]: Received MCU message 'properties_changed 4 8 0'
[19:19:35][V][miot.binary_sensor:011]: MCU reported sensor 4:8 is: OFF
[19:19:35][V][miot:174]: Sending reply 'ok' to MCU

ESPHome 2023.12.9
esphome-miot@5bff0dc

Support for dmaker.fan.p18 and dmaker.fan.p33

Hi,

I have here a dmaker.fan.p18 and a dmaker.fan.p33 (Mi Smart Standing Fan 2 and Mi Smart Standing Fan 2 Pro). Difference between the two is that one has a battery, otherwise they should be the same. The specs differ slightly though:

https://home.miot-spec.com/s/dmaker.fan.p18
https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:fan:0000A005:dmaker-p18:1

https://home.miot-spec.com/s/dmaker.fan.p33
https://home.miot-spec.com/spec?type=urn:miot-spec-v2:device:fan:0000A005:dmaker-p33:1

Screenshots of the app show that there are differences regarding accessible controls through the app. The control name for speed adjustment differs:

(dmaker.fan.p18 / Mi Smart Standing Fan 2)
Screenshot_2024-04-13-02-48-56-74

(dmaker.fan.p33 / Mi Smart Standing Fan 2 Pro)
Screenshot_2024-04-13-02-50-21-79

These are pictures of the dmaker.fan.p33 / Mi Smart Standing Fan 2 Pro version (for the other one I haven't done the sull teardown yet but I could see inside that it's an ESP-WROOM-02D for both):

image

image

Unlike the Air Purifier devices that are already supported in this project these fans don't seem to have an easily accessible UART port so one probably has to flash directly on the pins of the ESP-WROOM-02D.

I checked plenty of contacts combinations for continuity but for the ESP-WROOM-02D I could only find test points for IO13 and IO15 on the backside of the PCB (marked in the pictures above) + 3.3V and GND. My hope is that IO13 and IO15 would work if I use them in the ESPHome config:

uart:
tx_pin: GPIO15
rx_pin: GPIO13
baud_rate: 115200

For Air Purifier 4 Lite the config looks like this:

uart:
tx_pin: GPIO17
rx_pin: GPIO16
baud_rate: 115200

and the docucmentation (ESP32-­WROOM­-32D - https://www.espressif.com/sites/default/files/documentation/esp32-wroom-32d_esp32-wroom-32u_datasheet_en.pdf) states this :

image

This is from the ESP-WROOM-02D documentation ( https://www.espressif.com/sites/default/files/documentation/esp-wroom-02u_esp-wroom-02d_datasheet_en.pdf ):

image

image

image

As a next step I will try backing up the original firmware and flashing the chip with ESPHome, starting with only a basic config and as a next step I would try if e.g. a switch added to the config would work. I'd be happy though if - in the meantime - maybe one of the pros here could share their opinion if these things I've summarized here make sense. Thank you!

MCU time request: no time source available

I have flashed successfully Xiaomi Air Purifier 3H (zhimi.airpurifier.mb3) and everything works without any issues.

While I was monitoring the logs, I saw that the below error occurs very often:

[17:37:38][W][miot:295]: MCU time request: no time source available

It doesn't cause any negative effect, but I wanted to make sure that there are no issues before I prepare a PR with the config file and the wiki page for that particular model.

Does anyone know what can cause those errors?

Guru Meditation Error in miot.cpp

Hi, I have flashed the firmware on Mi Purifier 3C (single core ESP32), and it's experiencing a bootloop.
The flash chip was erased completely before proceeding.

[C][api:140]:   Address: purifier.local:6053
[C][api:142]:   Using noise encryption: YES
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x40001277  PS      : 0x00060f30  A0      : 0x800db40b  A1      : 0x3ffbccb0
A2      : 0x00000000  A3      : 0x3f405006  A4      : 0x3ffbccf8  A5      : 0x00000004
A6      : 0x00ff0000  A7      : 0xff000000  A8      : 0x8000c71a  A9      : 0x3ffbcc80
A10     : 0x00000000  A11     : 0x3f41f66b  A12     : 0x3ffbccf8  A13     : 0x00000001
A14     : 0x00ff0000  A15     : 0xff000000  SAR     : 0x0000000a  EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000  LBEG    : 0x400014fd  LEND    : 0x4000150d  LCOUNT  : 0xffffffff


Backtrace: 0x40001274:0x3ffbccb0 0x400db408:0x3ffbccc0 0x400db5b1:0x3ffbcd20 0x4015f91d:0x3ffbcd50 0x4015f9a5:0x3ffbcd70 0x400e2020:0x3ffbcd90 0x400e4862:0x3ffbcdc0 0x400d9242:0x3ffbcde0

Decoded stack trace below:

0x400db408: esphome::miot::Miot::process_message_(char*) at /config/.esphome/build/purifier/src/esphome/components/miot/miot.cpp:324
0x400db5b1: esphome::miot::Miot::loop() at /config/.esphome/build/purifier/src/esphome/components/miot/miot.cpp:96
0x4015f91d: esphome::Component::call_loop() at /config/.esphome/build/purifier/src/esphome/core/component.cpp:76
0x4015f9a5: esphome::Component::call() at /config/.esphome/build/purifier/src/esphome/core/component.cpp:98
0x400e2020: esphome::Application::loop() at /config/.esphome/build/purifier/src/esphome/core/application.cpp:74
0x400e4862: loop() at /config/.esphome/build/purifier/zhimi.airp.mb4a.yaml:44
0x400d9242: esphome::loop_task(void*) at /config/.esphome/build/purifier/src/esphome/components/esp32/core.cpp:69

Xiaomi Smart Air Purifier 4 Lite - Wiki update

Any chance to get a bit more details about the Xiaomi Smart Air Purifier 4 Lite steps?

I am trying to get my heads around with the "power on the board" step.

I tried either power on the whole unit (3 beeps from the purifier and not connecting to my UART) - since nowhere mentioned HOW should we power on the board.
And also tried directly connecting the 3V from my UART to the ESP32 chip leg (still not connecting somehow for me)

The board layout is slightly different then the previous version, so those guides doesn't really help me with the 4 Lite.

(PS: strange to me that whenever I plug the TX/RX to my UART, the power led lights up on it)

Thank you

Support `event_occurred` MCU message

For the Smart Pet Food Feeder (mmgg.feeder.fi1), there's a physical/manual feed button that when pressed generates a number of messages from the MCU in the form event_occured 4 3 5 255.

This seems to conform to the message format that I read in https://blakadder.github.io/miot/#event_occured , even though the device spec page doesn't list any events.

For this device, I haven't found a cumulative "portions dispensed today/total" property so counting the portions as they're dispensed is useful for deriving state.

I'm not sure if this is already considered in the TODO comment,

 * add "access" to components? read/write/notify
 * automations?

But leaving this here just in case it's useful.


I would deduce the below event stream to be

  1. feed started + id 255 (manual instead of scheduled?)
  2. feed ended + dispensed portion count + id 255 (manual instead of scheduled?)
  3. ??

Example short press.

[20:25:21][V][miot:091]: Received MCU message 'event_occured 4 3 5 255'
[20:25:21][W][miot:297]: Unknown command 'event_occured'
[20:25:21][V][miot:174]: Sending reply 'ok' to MCU
[20:25:21][V][miot:091]: Received MCU message 'net'
[20:25:21][V][miot:174]: Sending reply 'cloud' to MCU
[20:25:21][V][miot:091]: Received MCU message 'get_down'
...
[20:25:24][V][miot:174]: Sending reply 'down none' to MCU
[20:25:24][V][miot:091]: Received MCU message 'event_occured 4 2 4 1 5 255'
[20:25:24][W][miot:297]: Unknown command 'event_occured'
[20:25:24][V][miot:174]: Sending reply 'ok' to MCU
[20:25:24][V][miot:091]: Received MCU message 'get_down'
[20:25:24][V][miot:174]: Sending reply 'down none' to MCU
[20:25:24][V][miot:091]: Received MCU message 'event_occured 4 1 4 1 5 255'
[20:25:24][W][miot:297]: Unknown command 'event_occured'
[20:25:24][V][miot:174]: Sending reply 'ok' to MCU
[20:25:24][V][miot:091]: Received MCU message 'properties_changed 4 9 0'
[20:25:24][V][miot.binary_sensor:011]: MCU reported sensor 4:9 is: OFF

Pressing and holding down the feed button:

[19:56:38][V][miot:174]: Sending reply 'down none' to MCU
[19:56:38][V][miot:091]: Received MCU message 'event_occured 4 3 5 255'
[19:56:38][W][miot:297]: Unknown command 'event_occured'
[19:56:38][V][miot:174]: Sending reply 'ok' to MCU
[19:56:38][V][miot:091]: Received MCU message 'get_down'
...
[19:56:45][V][miot:174]: Sending reply 'down none' to MCU
[19:56:45][V][miot:091]: Received MCU message 'event_occured 4 2 4 3 5 255'
[19:56:45][W][miot:297]: Unknown command 'event_occured'
[19:56:45][V][miot:174]: Sending reply 'ok' to MCU
[19:56:45][V][miot:091]: Received MCU message 'get_down'
[19:56:45][V][miot:174]: Sending reply 'down none' to MCU
[19:56:45][V][miot:091]: Received MCU message 'event_occured 4 1 4 3 5 255'
[19:56:45][W][miot:297]: Unknown command 'event_occured'
[19:56:45][V][miot:174]: Sending reply 'ok' to MCU
[19:56:45][V][miot:091]: Received MCU message 'properties_changed 4 9 0'
[19:56:45][V][miot.binary_sensor:011]: MCU reported sensor 4:9 is: OFF
[19:56:45][V][miot:174]: Sending reply 'ok' to MCU

Pressing for even longer:

[20:10:07][V][miot:091]: Received MCU message 'event_occured 4 3 5 255'
[20:10:07][W][miot:297]: Unknown command 'event_occured'
[20:10:07][V][miot:174]: Sending reply 'ok' to MCU
[20:10:07][V][miot:091]: Received MCU message 'get_down'
...
[20:10:16][V][miot:174]: Sending reply 'down none' to MCU
[20:10:16][V][miot:091]: Received MCU message 'event_occured 4 2 4 5 5 255'
[20:10:16][W][miot:297]: Unknown command 'event_occured'
[20:10:16][V][miot:174]: Sending reply 'ok' to MCU
[20:10:16][V][miot:091]: Received MCU message 'get_down'
[20:10:16][V][miot:174]: Sending reply 'down none' to MCU
[20:10:16][V][miot:091]: Received MCU message 'event_occured 4 1 4 5 5 255'
[20:10:16][W][miot:297]: Unknown command 'event_occured'
[20:10:16][V][miot:174]: Sending reply 'ok' to MCU
[20:10:16][V][miot:091]: Received MCU message 'properties_changed 4 9 0'
[20:10:16][V][miot.binary_sensor:011]: MCU reported sensor 4:9 is: OFF

I'll be available for testing this on the real device if/when this is implemented.

Incorrect parsing of `result` from `action` command

When we recieve a result message after dispatching an action, it's in a different form than get_properties/set_properties/properties_changed.
More specifically, there is only one SIID, one AIID and one code, but then multiple piid+value pairs belonging to the same service, and the update_properties function expects the pairs to always be siid+piid

I believe the same will happen for event_changed messages when those are implemented.

For convenience:
Get Properties Spec

Return value:result <siid> <piid> <code> [value] ... <siid> <piid> <code> [value]

Set Properties Spec

Return value: result <siid> <piid> <code> ... <siid> <piid> <code>

Properties Changed Spec

format:properties_changed <siid> <piid> <value> ... <siid> <piid> <value>

Action Spec

Return value:result <siid> <aiid> <code> <piid> <value> ... <piid> <value>

and Event Occurred Spec (With the same format as action)

format:event_occured <siid> <eiid> <piid> <value> ... <piid> <value>

I pushed a fix in my repo here, but I'm a noob at C++ and figured you might have a better approach to this. I also didn't add the event_occurred case as I just realized the similarity while writing this issue.

main branch:

[20:20:48][D][miot:125]: Queuing MCU command 'action 5 6'
[20:20:49][V][miot:091]: Received MCU message 'get_down'
[20:20:49][V][miot:171]: Sending reply 'down action 5 6' to MCU
[20:20:49][V][miot:091]: Received MCU message 'result 5 6 0 12 "0,255,255,255,255,1,255,255,255,255,2,8,0,5,0,3,255,255,255,255,4,255,255,255,255"'
[20:20:49][W][miot:183]: Received property value without component: 5 6 12
[20:20:49][V][miot:171]: Sending reply 'ok' to MCU

My branch:

[20:13:21][D][miot:125]: Queuing MCU command 'action 5 6'
[20:13:22][V][miot:091]: Received MCU message 'get_down'
[20:13:22][V][miot:171]: Sending reply 'down action 5 6' to MCU
[20:13:22][V][miot:091]: Received MCU message 'result 5 6 0 12 "0,255,255,255,255,1,255,255,255,255,2,8,0,5,0,3,255,255,255,255,4,255,255,255,255"'
[20:13:22][V][miot.text_sensor:011]: MCU reported text sensor 5:12 is: 0,255,255,255,255,1,255,255,255,255,2,8,0,5,0,3,255,255,255,255,4,255,255,255,255
[20:13:22][V][text_sensor:013]: 'Feed Plan': Received new state 0,255,255,255,255,1,255,255,255,255,2,8,0,5,0,3,255,255,255,255,4,255,255,255,255
[20:13:22][D][text_sensor:064]: 'Feed Plan': Sending state '0,255,255,255,255,1,255,255,255,255,2,8,0,5,0,3,255,255,255,255,4,255,255,255,255'
[20:13:22][V][miot:171]: Sending reply 'ok' to MCU

YAML (both):

  - platform: "miot"
    miot_siid: 5
    miot_piid: 12
    miot_poll: false
    name: "Feed Plan"
    icon: mdi:calendar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.