Работаем с датчиком CO₂ Xiaomi ClearGrass Air Detector локально, без китайских серверов

в 21:10, , рубрики: cleargrass, co2, diy или сделай сам, Raspberry Pi, xiaomi, гаджеты, датчик, Интернет вещей, умный дом

Работаем с датчиком CO₂ Xiaomi ClearGrass Air Detector локально, без китайских серверов - 1

Давно планировал внедрить в домашнюю автоматизацию датчик углекислого газа CO₂. По соотношению цена/качество/функции/внешний вид лучшим для меня оказался Xiaomi ClearGrass Air Detector. Анализатор качества воздуха содержит датчики:

  1. CO₂
  2. tVOC (летучие органические соединения)
  3. PM2.5
  4. Температуры
  5. Влажности

У ClearGrass качественный экран с большими углами обзора и аккумулятор на 6 часов автономной работы. Цена в районе 130$ за такой девайс переводит его в сегмент маст хэв! Большой обзор можно почитать на mysku.ru.
Анализатор можно добавить в родное приложение qingping+ или MiHome, в обоих случаях данные ходят через китайские сервера, что меня категорически не устраивало. Я решил разобраться, как можно получить данные с датчика локально без использования сторонних удаленных серверов.

1. Изучение трафика

Первым делом нужно было посмотреть, как ClearGrass передает данные в приложение qingping+. ClearGrass подключается к интернет по Wi-Fi. Чтобы слушать трафик я поднял на Raspberry Pi Wi-Fi точку доступа и запустил tcpdump собирать информацию:

sudo tcpdump -i wlan0 -vv -s0 -X -n port 1883 -s 65535 -w cleargrass.pcap

Анализ трафика показал, что ClearGrass обращается примерно к 5 разным IP адресам, а на 154.8.191.174 передает в незашифрованном виде по протоколу MQTT данные о качестве воздуха.
Работаем с датчиком CO₂ Xiaomi ClearGrass Air Detector локально, без китайских серверов - 2

2. Заворачиваем трафик с ClearGrass на Raspberry Pi

Немного поэкспериментировав с iptables я пришел к такому правилу:

sudo iptables -i wlan0 -t nat -A PREROUTING -s 192.168.115.19 -j REDIRECT

Читается оно так: «Весь новый трафик на интерфейсе wlan0 от 192.168.115.19 (IP ClearGrass) перенаправлять локально». Я не большой знаток iptables, поэтому буду рад предложениям и улучшениям. В этом правиле есть минус, если анализатор уже подключен к Raspberry Pi, то трафик не будет перенаправляться. Сначала нужно запустить правило и только затем подключить ClearGrass к Raspberry Pi по Wi-Fi.
В итоге, подняв MQTT брокер mosquitto на Raspberry Pi я увидел, что анализатор передает данные о качестве воздуха раз в минуты.

3. MQTT нано-брокер на JS для домашней автоматизации Z-Way

В качестве сервера домашней автоматизации я использую Z-Way, который поддерживает множество Z-Wave устройств и возможность писать скрипты на JS.
Работаем с датчиком CO₂ Xiaomi ClearGrass Air Detector локально, без китайских серверов - 3

К сожалению для Z-Way нет MQTT брокера на JS (в отличие от систем на базе node.js), поэтому я решил написать минимальные брокер, который только принимает данные от этого анализатора и ничего больше не умеет. Не читая особо документацию я посмотрел на общение между анализатором и mosquitto и составил следующую последовательность:

MQTT PROTOCOL

Connect Command (sensor -> broker)
	0x10 - Connect Command

Connect Ack (broker -> sensor)
	0x20 - Connect Ack
	0x02 - Len 2
	0x00
	0x00 - Connection Accepted

Subscribe Request (sensor -> broker)
	0x82 - 0b1000 0010; 0b1000 - Subscribe Request

Subscribe Ack (broker -> sensor)
	0x90 - 0b1001 0000; 0b1001 - Subscribe Ack
	0x03 - Len 3
	0x00
	0x08 - Message identifier 8
	0x00 - Fire and Forget

Ping Request (sensor -> broker)
	0xC0 - Ping Request
	0x00 - Len 0

Ping Response (broker -> sensor)
	0xD0 - Ping Response
	0x00 - Len 0

Publish Message (sensor -> broker)
	0x30 - Publish Message
	0x96
	0x04 - Len 534

В итоге родился простой JS скрипт:

mqttSocket.reusable();
mqttSocket.bind(1883);
mqttSocket.onrecv = function(data, host, port) {
	var arr = new Uint8Array(data);

	switch(arr[0]) {
		// PING
		case 0xC0:
			console.log("---------- MQTT PING RESPONSE");
			this.send([0xD0, 0x00]);
			break;
		// CONNECT
		case 0x10:
			console.log("---------- MQTT CONNECT ACK");
			this.send([0x20, 0x02, 0x00, 0x00]);
			break;
		// SUBSCRIBE
		case 0x82:
			console.log("---------- MQTT SUBSCRIBE ACK");
			this.send([0x90, 0x03, arr[2], arr[3], 0x00]);
			break;
		// PUBLISH
		case 0x30:
			var sensorPayload = self.getPayload(arr);
			var sensorMessage = sensorPayload.substr(sensorPayload.indexOf('{'), sensorPayload.lastIndexOf('}'));
			var sensorObj = JSON.parse(sensorMessage);
			console.logJS("---------- MQTT MESSAGE:", sensorObj);
			console.logJS("---------- CO2: ", sensorObj.data.co2);
			self.vDevCO2.set("metrics:level", sensorObj.data.co2);
			break;
	}
};
mqttSocket.listen();

Конечно пока многое не учитывается, например в одной посылке, может прийти и PING, и MESSAGE, а я что-то из этого пропущу. Возможно в будущем я использую кодовую базу aedes для создания MQTT брокера для Z-Way. А на данный момент целью была принципиальная возможность получить локально данные о качестве воздуха с анализатора Xiaomi ClearGrass Air Detector и эта цель достигнута.
В перспективе хочу установить Z-Wave версию бризера TION S3 и управлять им основываясь на данных от ClearGrass.

Автор: Виталий

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js