1
0
Fork 0

First Files

This commit is contained in:
Joerg Elfring 2020-04-01 21:15:04 +02:00
parent 6c17a5b291
commit ee9a73ff70
4 changed files with 179 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
## Configurations should be local
*.conf

55
README.md Normal file
View file

@ -0,0 +1,55 @@
# POC: Xiaomi Airpurifier 3H MQTT Bridge
This is a proof-of-concept, lacking a lot of errorhandling.
The Xiaomi Airpurifier 3H uses the (new) miot api.
This script bridges the air pufifier to the following state and control topics in mqtt.
These topics are reported from the device:
| STATE Topic | Values to expect | Meaning |
|-------------------------------------|------------------------------|----------------------------------------------------------------------------|
| $device/STATE/TIMESTAMP | 2020-03-29T15:44 | Timestamp of the last state update |
| $device/STATE/airQualityIndex | 0-999 | AQI current value (ppm2.5?) |
| $device/STATE/airQualityIndexAvg | 0-999 | AQI as displayed on the frontpanel (?) |
| $device/STATEairTemperatureC | FLOAT | Current temperature in °C |
| $device/STATE/airRelHumidityPercent | 0-100 | Relative humidity in % |
| $device/STATE/fanMotorSpeed | INT | Current motorspeed in rpm |
| $device/STATE/fanLevel | 1-3 | Fanlevel preset as selected by the button (1,2,3 waves) |
| $device/STATE/fanFavoriteSetLevel | 1-14 | Fanlevel preset for heart-mode (fanLevels 1-3 are positions in this range) |
| $device/STATE/filterUsedHours | INT | Filter-usage-time in hours |
| $device/STATE/filterRemainingPercent| 0-100 | Remaining filter-live in % |
| $device/STATE/filterRfidProductId | 0:0:31:31 | Filter product-id |
| $device/STATE/filterType | Regular, ... | Common name for the filtertype |
| $device/STATE/filterRfidTag | 80:66:58:da:7f:55:4 | The filters unique ID |
| $device/STATE/deviceBuzzerEnabled | True/False | Can the buzzer buzz? |
| $device/STATE/deviceLedBrightnes | Bright, Dim, Off | Brightness... |
| $device/STATE/deviceChildLockActive | True/False | Is the childlock active? |
| $device/STATE/devicePowerOn | True/False | Is the device powered on? |
| $device/STATE/devicePower | on/off | Power... |
| $device/STATE/deviceMode | Auto, Silent, Favorite, Fan | Mode as selcted by the front-button. (3 fanmodes indicated by fanLevel) |
| $device/STATE/statPurifiedVolumeM3 | INT | Purified volume of air |
| $device/STATE/statTimeActive | INT | Seconds active |
These topics can control the device:
| CMD Topic | Values expected | Meaning |
|----------------------|------------------|-------------------------------|
| $device/CMD/power | on/off | Turn the device on or off |
## Prerequisits
- Python 3
- PAHO MQTT-Client module
- python-miio > 5.0.1 (available from PIP)
- The devices security token
## Usage
- Copy airpurifier.conf.sample to airpurifier.conf
- Adjust the values in airpurifier.conf
- Run miotAirpurifierBridge.py
Set the environment `airpurifierConfigFile` to use a different configfile.

9
airpurifier.conf.sample Normal file
View file

@ -0,0 +1,9 @@
mqtt_ip = "1.2.3.5" # MQTT Broker IP
mqtt_topic = "testing/airPurifierBridge" # MQTT Topic to use
miot_ip ="1.2.3.4" # Xiaomi Arpurfier 3H IP-Address
miot_token ="1234567890ABCDEFGHIJKLMNopqrstuv" # device Token
update_interval = (10 * 60) # Update between regular updates of the state (10 minutes)
loglevel = 1 # 0=Exceptions 1=Application 2=Actions 3=Debug

113
miotAirpurifierBridge.py Normal file
View file

@ -0,0 +1,113 @@
import os
import time
from datetime import datetime
import paho.mqtt.client as paho
import miio
## Logging to con
def log(level, msg):
if ( level <= loglevel ):
now = datetime.now()
print(now.strftime("%Y-%m-%dT%H:%M:%S") + " " + str(level) + " " + msg)
## Receive the airpurifiers status and write it to mqtt
def updateMqttStateTopic():
log(3, "Starting update of state-topic.")
apStatus = ap.status()
now = datetime.now()
mqttClient.publish(mqtt_stateTopic + "TIMESTAMP", now.strftime("%Y-%m-%dT%H:%M:%S"))
mqttClient.publish(mqtt_stateTopic + "airQualityIndex", apStatus.aqi)
mqttClient.publish(mqtt_stateTopic + "airQualityIndexAvg", apStatus.average_aqi)
mqttClient.publish(mqtt_stateTopic + "airTemperatureC", apStatus.temperature)
mqttClient.publish(mqtt_stateTopic + "airRelHumidityPercent", apStatus.humidity)
mqttClient.publish(mqtt_stateTopic + "fanMotorSpeed", apStatus.motor_speed)
mqttClient.publish(mqtt_stateTopic + "fanLevel", apStatus.fan_level)
mqttClient.publish(mqtt_stateTopic + "fanFavoriteSetLevel", apStatus.favorite_level)
mqttClient.publish(mqtt_stateTopic + "filterUsedHours", apStatus.filter_hours_used)
mqttClient.publish(mqtt_stateTopic + "filterRemainingPercent", apStatus.filter_life_remaining)
mqttClient.publish(mqtt_stateTopic + "filterRfidProductId", apStatus.filter_rfid_product_id)
mqttClient.publish(mqtt_stateTopic + "filterRfidTag", apStatus.filter_rfid_tag)
mqttClient.publish(mqtt_stateTopic + "filterType", apStatus.filter_type.name)
mqttClient.publish(mqtt_stateTopic + "deviceBuzzerEnabled", apStatus.buzzer)
mqttClient.publish(mqtt_stateTopic + "deviceLedBrightnes", apStatus.led_brightness.name)
mqttClient.publish(mqtt_stateTopic + "deviceChildLockActive", apStatus.child_lock)
mqttClient.publish(mqtt_stateTopic + "devicePowerOn", apStatus.is_on)
mqttClient.publish(mqtt_stateTopic + "devicePower", apStatus.power)
mqttClient.publish(mqtt_stateTopic + "deviceMode", apStatus.mode.name)
mqttClient.publish(mqtt_stateTopic + "statPurifiedVolumeM3", apStatus.purify_volume)
mqttClient.publish(mqtt_stateTopic + "statTimeActive", apStatus.use_time)
# mqttClient.publish(mqtt_stateTopic + "deviceBuzzerSetVolume", apStatus.buzzer_volume)
# mqttClient.publish(mqtt_stateTopic + "deviceLedEnabled", apStatus.led)
log(3, "Update of state-topic finished.")
## MQTT broker disconnected
def on_mqttDisconnect(client, userdata, rc):
log(1, "MQTT broker disconnected")
## MQTT broker connected
def on_mqttConnect(client, userdata, flags, rc):
log(1, "MQTT broker connected")
## MQTT Subscription Loop Callback Function
def on_mqttMessage(client, userdata, message):
mqttMsgData = message.payload.decode("utf-8")
mqttMsgTopic = message.topic
log(2, "RECEIVED: " + mqttMsgTopic + ":" + mqttMsgData)
if ( mqttMsgTopic == mqtt_cmdTopic+"power" ):
if (mqttMsgData == "on"):
ap.on()
log(2, "ACTION: Power On")
elif (mqttMsgData == "off"):
ap.off()
log(2, "ACTION: Power Off")
## Force update of STATE after switching things
time.sleep(5)
updateMqttStateTopic()
## --------------------------------------------------------------------------------------------------
## Get confiuration
configfile = os.getenv('airpurifierConfigFile', 'airpurifier.conf')
exec(open(configfile).read())
log(1, "---------------- Starting Air Purifier Bridge ----------------")
log(1, "Loaded confguration file: " + configfile)
## The airpurifier object
ap = miio.airpurifier_miot.AirPurifierMiot(ip=miot_ip, token=miot_token)
## The MQTT Client object
mqttClient = paho.Client("airPurifierBridge")
log(1, "Connecting to MQTT broker " + mqtt_ip)
mqttClient.connect(mqtt_ip)
time.sleep(5)
## Subscribe to mqtt command topics and start the loop
mqtt_cmdTopic = mqtt_topic + "/CMD/"
mqttClient.subscribe(mqtt_cmdTopic+"power")
mqttClient.on_message = on_mqttMessage
mqttClient.on_connect = on_mqttConnect
mqttClient.on_disconnect = on_mqttDisconnect
log(1, "Starting the subscription loop on " + mqtt_cmdTopic)
mqttClient.loop_start()
## State Update Loop
mqtt_stateTopic = mqtt_topic + "/STATE/"
log(1, "Starting the state update loop on " + mqtt_stateTopic)
while True:
updateMqttStateTopic()
time.sleep(update_interval)