17 if ((value_type == 0x1001) && (value_length == 3)) {
22 else if ((value_type == 0x0003) && (value_length == 1)) {
26 else if ((value_type == 0x1004) && (value_length == 2)) {
31 else if ((value_type == 0x1006) && (value_length == 2)) {
36 else if (((value_type == 0x1007) || (value_type == 0x000F)) && (value_length == 3)) {
37 const uint32_t illuminance =
encode_uint24(data[2], data[1], data[0]);
39 result.
is_light = illuminance >= 100;
40 if (value_type == 0x0F)
44 else if ((value_type == 0x1008) && (value_length == 1)) {
48 else if ((value_type == 0x1009) && (value_length == 2)) {
49 const uint16_t conductivity =
encode_uint16(data[1], data[0]);
53 else if ((value_type == 0x100A || value_type == 0x4803) && (value_length == 1)) {
57 else if ((value_type == 0x100D) && (value_length == 4)) {
64 else if ((value_type == 0x1010) && (value_length == 2)) {
65 const uint16_t formaldehyde =
encode_uint16(data[1], data[0]);
69 else if ((value_type == 0x1012) && (value_length == 1)) {
73 else if ((value_type == 0x1013) && (value_length == 1)) {
77 else if ((value_type == 0x1017) && (value_length == 4)) {
78 const uint32_t idle_time =
encode_uint32(data[3], data[2], data[1], data[0]);
81 }
else if ((value_type == 0x1018) && (value_length == 1)) {
85 else if ((value_type == 0x4C01) && (value_length == 4)) {
86 const uint32_t int_number =
encode_uint32(data[3], data[2], data[1], data[0]);
92 else if ((value_type == 0x4C02) && (value_length == 1)) {
96 else if ((value_type == 0x4C08) && (value_length == 4)) {
97 const uint32_t int_number =
encode_uint32(data[3], data[2], data[1], data[0]);
99 std::memcpy(&humidity, &int_number,
sizeof(humidity));
111 ESP_LOGVV(TAG,
"parse_xiaomi_message(): payload is encrypted, stop reading message.");
121 const uint8_t *payload = message.data() + result.
raw_offset;
122 uint8_t payload_length = message.size() - result.
raw_offset;
123 uint8_t payload_offset = 0;
124 bool success =
false;
126 if (payload_length < 4) {
127 ESP_LOGVV(TAG,
"parse_xiaomi_message(): payload has wrong size (%d)!", payload_length);
131 while (payload_length > 3) {
132 if (payload[payload_offset + 1] != 0x10 && payload[payload_offset + 1] != 0x00 &&
133 payload[payload_offset + 1] != 0x4C && payload[payload_offset + 1] != 0x48) {
134 ESP_LOGVV(TAG,
"parse_xiaomi_message(): fixed byte not found, stop parsing residual data.");
138 const uint8_t value_length = payload[payload_offset + 2];
139 if ((value_length < 1) || (value_length > 4) || (payload_length < (3 + value_length))) {
140 ESP_LOGVV(TAG,
"parse_xiaomi_message(): value has wrong size (%d)!", value_length);
144 const uint16_t value_type =
encode_uint16(payload[payload_offset + 1], payload[payload_offset + 0]);
145 const uint8_t *data = &payload[payload_offset + 3];
150 payload_length -= 3 + value_length;
151 payload_offset += 3 + value_length;
160 ESP_LOGVV(TAG,
"parse_xiaomi_header(): no service data UUID magic bytes.");
170 ESP_LOGVV(TAG,
"parse_xiaomi_header(): service data has no DATA flag.");
174 static uint8_t last_frame_count = 0;
175 if (last_frame_count ==
raw[4]) {
176 ESP_LOGVV(TAG,
"parse_xiaomi_header(): duplicate data packet received (%d).",
static_cast<int>(last_frame_count));
180 last_frame_count =
raw[4];
186 if (device_uuid == 0x0098) {
188 result.
name =
"HHCCJCY01";
189 }
else if (device_uuid == 0x01aa) {
191 result.
name =
"LYWSDCGQ";
192 }
else if (device_uuid == 0x015d) {
194 result.
name =
"HHCCPOT002";
195 }
else if (device_uuid == 0x02df) {
197 result.
name =
"JQJCY01YM";
198 }
else if (device_uuid == 0x03dd) {
200 result.
name =
"MUE4094RT";
202 }
else if (device_uuid == 0x0347 ||
203 device_uuid == 0x0B48) {
205 result.
name =
"CGG1";
206 }
else if (device_uuid == 0x03bc) {
208 result.
name =
"GCLS002";
209 }
else if (device_uuid == 0x045b) {
211 result.
name =
"LYWSD02";
212 }
else if (device_uuid == 0x2542) {
214 result.
name =
"LYWSD02MMC";
215 if (
raw.size() == 19)
217 }
else if (device_uuid == 0x040a) {
219 result.
name =
"WX08ZM";
220 }
else if (device_uuid == 0x0576) {
222 result.
name =
"CGD1";
223 }
else if (device_uuid == 0x066F) {
225 result.
name =
"CGDK2";
226 }
else if (device_uuid == 0x055b) {
228 result.
name =
"LYWSD03MMC";
229 }
else if (device_uuid == 0x1203) {
231 result.
name =
"XMWSDJ04MMC";
232 if (
raw.size() == 19)
234 }
else if (device_uuid == 0x07f6) {
236 result.
name =
"MJYD02YLA";
237 if (
raw.size() == 19)
239 }
else if (device_uuid == 0x06d3) {
241 result.
name =
"MHOC303";
242 }
else if (device_uuid == 0x0387) {
244 result.
name =
"MHOC401";
245 }
else if (device_uuid == 0x0A83) {
247 result.
name =
"CGPR1";
248 if (
raw.size() == 19)
250 }
else if (device_uuid == 0x0A8D) {
252 result.
name =
"RTCGQ02LM";
253 if (
raw.size() == 19)
256 ESP_LOGVV(TAG,
"parse_xiaomi_header(): unknown device, no magic bytes.");
264 if ((
raw.size() != 19) && ((
raw.size() < 22) || (
raw.size() > 24))) {
265 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): data packet has wrong size (%d)!",
raw.size());
270 uint8_t mac_reverse[6] = {0};
271 mac_reverse[5] = (uint8_t) (
address >> 40);
272 mac_reverse[4] = (uint8_t) (
address >> 32);
273 mac_reverse[3] = (uint8_t) (
address >> 24);
274 mac_reverse[2] = (uint8_t) (
address >> 16);
275 mac_reverse[1] = (uint8_t) (
address >> 8);
276 mac_reverse[0] = (uint8_t) (
address >> 0);
291 int cipher_pos = (
raw.size() == 19) ? 5 : 11;
293 const uint8_t *v =
raw.data();
295 memcpy(vector.key, bindkey, vector.keysize);
296 memcpy(vector.ciphertext, v + cipher_pos, vector.datasize);
297 memcpy(vector.tag, v +
raw.size() - vector.tagsize, vector.tagsize);
298 memcpy(vector.iv, mac_reverse, 6);
299 memcpy(vector.iv + 6, v + 2, 3);
300 memcpy(vector.iv + 9, v +
raw.size() - 7, 3);
302 mbedtls_ccm_context ctx;
303 mbedtls_ccm_init(&ctx);
305 int ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, vector.key, vector.keysize * 8);
307 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): mbedtls_ccm_setkey() failed.");
308 mbedtls_ccm_free(&ctx);
312 ret = mbedtls_ccm_auth_decrypt(&ctx, vector.datasize, vector.iv, vector.ivsize, vector.authdata, vector.authsize,
313 vector.ciphertext, vector.plaintext, vector.tag, vector.tagsize);
315 uint8_t mac_address[6] = {0};
316 memcpy(mac_address, mac_reverse + 5, 1);
317 memcpy(mac_address + 1, mac_reverse + 4, 1);
318 memcpy(mac_address + 2, mac_reverse + 3, 1);
319 memcpy(mac_address + 3, mac_reverse + 2, 1);
320 memcpy(mac_address + 4, mac_reverse + 1, 1);
321 memcpy(mac_address + 5, mac_reverse, 1);
322 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): authenticated decryption failed.");
325 ESP_LOGVV(TAG,
" Key : %s",
format_hex_pretty(vector.key, vector.keysize).c_str());
327 ESP_LOGVV(TAG,
" Cipher : %s",
format_hex_pretty(vector.ciphertext, vector.datasize).c_str());
328 ESP_LOGVV(TAG,
" Tag : %s",
format_hex_pretty(vector.tag, vector.tagsize).c_str());
329 mbedtls_ccm_free(&ctx);
334 uint8_t *p = vector.plaintext;
335 for (std::vector<uint8_t>::iterator it =
raw.begin() + cipher_pos; it !=
raw.begin() + cipher_pos + vector.datasize;
343 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): authenticated decryption passed.");
344 ESP_LOGVV(TAG,
" Plaintext : %s, Packet : %d",
format_hex_pretty(
raw.data() + cipher_pos, vector.datasize).c_str(),
345 static_cast<int>(
raw[4]));
347 mbedtls_ccm_free(&ctx);