Xiaomi
This Nim package includes proc's for working with Xiaomi devices.
Requirements
Nim:
- Nim >= 0.18.1
- Multicast >= 0.1.1 (nimble install multicast)
- Nimcrypto >= 0.3.2 (nimble install nimcrypto)
Devices
Xiaomi IOT devices are supported. The following devices has been thoroughly tested:
Working with Xiaomi
You can interact with the Xiaomi devices in 3 ways:
- Read - Asking for a status, e.g. is the door open (door sensor)
- Report - Awaiting an action, e.g. when the door opens, it sends a notification (door sensor)
- Write - Send a message to the device (only some devices accepted this), e.g. play a sound (gateway)
All you Xiaomi devices are connected to a gateway. It is through this gateway, we are communicating with each of the devices. Each devices is identified with a SID.
Discover devices
But before we get started, you need to acquire your devices SID.
Get the gateways SID
import xiaomi
xiaomiConnect()
echo xiaomiGatewayGetSid()
Get the devices SID
import xiaomi
xiaomiConnect()
echo xiaomiDiscover()
Read
There are numerous ways to read. Some proc's just read the next message, some waits for a specific device, etc.
Read the next message sent
import xiaomi
xiaomiConnect()
echo xiaomiReadMessage()
Request a device status and read the reply
import xiaomi
xiaomiConnect()
echo xiaomiReadDevice("device-SID")
Read the next message from custom-x
This will await that the cmd = "heartbeat" and the model = "gateway".
import xiaomi
xiaomiConnect()
echo xiaomiReadCustom("heartbeat", "gateway")
Read messages forever
import xiaomi
xiaomiConnect()
xiaomiListenForever()
Report
For PIR sensors you will receive a report, when there's motion or there hasn't been motion for 300 seconds.
For magnet sensors you will receive a report when they are connected (close
) and disconnected (open
).
Read next report
import xiaomi
xiaomiConnect()
echo xiaomiReportAck()
Read next report for device
import xiaomi
xiaomiConnect()
echo xiaomiReadReport("device-SID")
Write to a device
To write to a device, we need to exchange an encrypted key with the gateway based on an ever-changing token. We are utilizing nimcrypto AES CBC 128 to do this.
Gateway password
But before we can generate the key, you need to gather you gateway password. Follow this guide Domotics or the bullets below. Remember to write the key down.
- Install the Xiaomi app
- Set the region to Mainland China under Settings->Locale
- You can set the language to English, even though the region is China
- Sign in/Make an account
- Select your Gateway in the app
- Tap the 3 dots in top right corner
- Click About
- Tap on the version repeatedly until a new menu appear
- Click on Wireless communication protocol
- Enable the this and write down you password and press Ok
Setting the password
If you need to write to a device, insert your password in the global variable at the top of your code:
xiaomiGatewayPassword = "secretPassword"
Getting the encrypted key
The gateways token is changing all the time. You therefore need to the generate the encrypted key before each writing.
This is done with:
xiaomiTokenRefresh()
xiaomiSecretUpdate()
OR
xiaomiTokenRefresh(true)
OR while writing
xiaomiWrite("device-SID", "message", true)
Gateway writing options
There are 2 main elements you can write to the gateway - the light and sound.
Light writing
import xiaomi
xiaomiGatewayPassword = "secretPassword"
xiaomiTokenRefresh()
xiaomiWrite(xiaomiGatewaySid, "\"rgb\": 4294914304")
Light options
To assign a RGB color, you have to use the Android() color format.
You can convert HEX to Android() at this website.
- Red =
4294914304
- Green =
4283359807
- Purple =
4283637131
- Yellow =
4292211292
- Blue =
4283327469
- Off =
0
Sound writing
import xiaomi
xiaomiGatewayPassword = "secretPassword"
xiaomiTokenRefresh()
xiaomiWrite(xiaomiGatewaySid, "\"mid\": 7, \"vol\": 4")
Sound options
The volume is in percentage, whereas 10 = 100%.
The following sounds are available:
Alarms:
- 0 - Police car 1
- 1 - Police car 2
- 2 - Accident
- 3 - Countdown
- 4 - Ghost
- 5 - Sniper rifle
- 6 - Battle
- 7 - Air raid
- 8 - Bark
Doorbells
- 10 - Doorbell
- 11 - Knock at a door
- 12 - Amuse
- 13 - Alarm clock
Alarm clock
- 20 - MiMix
- 21 - Enthusiastic
- 22 - GuitarClassic
- 23 - IceWorldPiano
- 24 - LeisureTime
- 25 - ChildHood
- 26 - MorningStream
- 27 - MusicBox
- 28 - Orange
- 29 - Thinker
Example
import json
import xiaomi
# To be able to write to the gateway,
# you need to find your gateway password.
# Follow this guide: https://github.com/ThomasTJdev/nim_homeassistant/wiki/Xiaomi#gateway-password
xiaomiGatewayPassword = "gbbwsi3apkgd1ls2"
proc connectToXiaomi() =
## You neeed to connect as the first thing
xiaomiConnect()
proc getGatewayInfo() =
## Get information on the gateway.
## This will return a heartbeat from
## the gateway.
echo xiaomiReadCustom("heartbeat", "gateway")
proc getGatewaySid(): string =
## Get the gateway SID
return xiaomiGatewayGetSid()
proc startSound() =
## Play sound number 7 with volume level 4
# Refresh token does also update the gateway sid
xiaomiTokenRefresh(true)
xiaomiWrite(xiaomiGatewaySid, "\"mid\": 7, \"vol\": 4")
proc stopSound() =
## Stop sound
# Refresh token does also update the gateway sid
xiaomiTokenRefresh(true)
xiaomiWrite(xiaomiGatewaySid, "\"mid\": 10000")
proc lightRed() =
## Set red light on gateway
# Refresh token does also update the gateway sid
xiaomiTokenRefresh(true)
xiaomiWrite(xiaomiGatewaySid, "\"rgb\": 4294914304")
proc lightOff() =
## Set red light on gateway
# Refresh token does also update the gateway sid
xiaomiTokenRefresh(true)
xiaomiWrite(xiaomiGatewaySid, "\"rgb\": 0")
proc discoverDevices() =
## Auto discover all connected devices
echo xiaomiDiscover()
proc readNextMessage() =
## Read the next message
echo xiaomiReadMessage()
proc askforDeviceStatus() =
## Tell the device to reply with it's status.
## This proc does not read the reply, only
## ask the device for sending a message with
## it's status and the cmd = read_ack
xiaomiSendRead("device-sid")
proc getDeviceStatus() =
## Tell the device to reply with status.
## and get the reply.
echo xiaomiReadDevice("device-sid")
proc sendCustomMessage() =
## Get information on the gateway
xiaomiSend("{\"cmd\": \"whois\"}")
proc listenForever() =
## Get all Xiaomi messages
xiaomiListenForever()
xiaomiDisconnect()
proc listenForeverAndUpdateToken() =
## Get all Xiaomi messages and update token
while true:
echo xiaomiUpdateToken(xiaomiReadMessage())
xiaomiDisconnect()
# Connect
connectToXiaomi()
# Discover devices
discoverDevices()
# Close the connection
xiaomiDisconnect()