Cloudless Xiaomi Smart Plug
I want to measure the energy consumption of my devices at >10A, but in a cloudless, local Linux setup. Unfortunately, I didn’t get these plugs to work without the app, so I gave up and moved to a new hardware version instead.
I have a Xiamo (Mi) Smart Plug which when connected advertises itself as chuangmi-plug-hmi206_miapffff
,
with the last 4 characters linking to the BSSID of the device, in my case 46:23:7c:ab:ff:ff
.
The corresponding MAC address is 44:23:7c:ab:ff:ff
.
Prepare static IP ¶
We know the MAC, so we can inform the router to give it a static IP, making it easier to find back.
/ip dhcp-server lease add address=172.16.20.23 server=IoT_DHCP mac-address=44:23:7c:ab:8f:88 comment="mi-plug-8f88"
/ip dns static add address=172.16.20.23 name="mi-plug-8f88" place-before=0 ttl="01:00:00" comment="infrastructure"
/ip dns static add address=172.16.20.23 name="mi-plug-8f88.lan" place-before=0 ttl="01:00:00" comment="infrastructure"
Getting a token ¶
With the app ¶
Unfortunately you need the app to retrieve the token (github.com), meaning phoning home at least once is not preventable (let me know if you did!).
Without the app (fails - token changes after setup) ¶
Getting token ¶
First you need to have a security token, unique to each device. See here (readthedocs.io) and here (github.com) for more details
echo -ne '\x21\x31\x00\x20\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' | nc -u 192.168.4.1 54321 > xiaomi_answer && cat xiaomi_answer | xxd -p
Gives: 21310020000000000e254488000003a3ffffffffffffffffffffffffffffffff
Check this works:
miiocli device --ip 192.168.4.1 --token ffffffffffffffffffffffffffffffff info
Model: chuangmi.plug.hmi206
Hardware version: ESP8266
Firmware version: 1.3.9_0005
Connecting to WiFi ¶
We can either use the app here, or we can use the python-miio (readthedocs.io) package to do this ourselves. I prefer the latter because I can prevent it phoning home, and can directly attach it to a non-internet controlled VLAN. Instead of using a VLAN, one could block access to Xiaomi’s servers, but I’m not sure which those are.
python-miio
’s module has a method to connect to wifi, but this is not exposed
to the CLI, so we use Python instead.
python3 -c "
import miio
device = miio.Device(ip='192.168.4.1', token='d3394594e386aefcb6042989d0aac160')
device.configure_wifi(ssid='Oberon-IoT', password='TJ3rNlLRjLVkPcVvvM29a')
"
This gives an error, but the command seems to have succeeded as it shows up on my router.
In [3]: device.configure_wifi(ssid='Oberon-IoT', password='TJ3rNlLRjLVkPcVvvM29a
...: ')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-fb4c60736e51> in <module>
----> 1 device.configure_wifi(ssid='Oberon-IoT', password='TJ3rNlLRjLVkPcVvvM29a')
~/Library/Python/3.7/lib/python/site-packages/miio/device.py in configure_wifi(self, ssid, password, uid, extra_params)
247 params = {"ssid": ssid, "passwd": password, "uid": uid, **extra_params}
248
--> 249 return self.send("miIO.config_router", params)[0]
250
251 def get_properties(
TypeError: 'int' object is not subscriptable
Once connected to WiFi, the token appears to be reset:
miiocli chuangmiplug --ip 172.16.20.100 --token d3394594e386aefcb6042989d0aac160 info
Error: Got checksum error which indicates use of an invalid token. Please check your token!
So I tried to got a new token, which failed and returned only 0
s
echo -ne '\x21\x31\x00\x20\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' | nc -u 172.16.20.100 54321 > xiaomi_answer && cat xiaomi_answer | xxd -p
Gives 21310020000000000e2544880000027000000000000000000000000000000000