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)) {
104 ESP_LOGVV(TAG,
"parse_xiaomi_message(): payload is encrypted, stop reading message.");
114 const uint8_t *payload = message.data() + result.
raw_offset;
115 uint8_t payload_length = message.size() - result.
raw_offset;
116 uint8_t payload_offset = 0;
117 bool success =
false;
119 if (payload_length < 4) {
120 ESP_LOGVV(TAG,
"parse_xiaomi_message(): payload has wrong size (%d)!", payload_length);
124 while (payload_length > 3) {
125 if (payload[payload_offset + 1] != 0x10 && payload[payload_offset + 1] != 0x00 &&
126 payload[payload_offset + 1] != 0x4C && payload[payload_offset + 1] != 0x48) {
127 ESP_LOGVV(TAG,
"parse_xiaomi_message(): fixed byte not found, stop parsing residual data.");
131 const uint8_t value_length = payload[payload_offset + 2];
132 if ((value_length < 1) || (value_length > 4) || (payload_length < (3 + value_length))) {
133 ESP_LOGVV(TAG,
"parse_xiaomi_message(): value has wrong size (%d)!", value_length);
137 const uint16_t value_type =
encode_uint16(payload[payload_offset + 1], payload[payload_offset + 0]);
138 const uint8_t *data = &payload[payload_offset + 3];
143 payload_length -= 3 + value_length;
144 payload_offset += 3 + value_length;
153 ESP_LOGVV(TAG,
"parse_xiaomi_header(): no service data UUID magic bytes.");
163 ESP_LOGVV(TAG,
"parse_xiaomi_header(): service data has no DATA flag.");
167 static uint8_t last_frame_count = 0;
168 if (last_frame_count ==
raw[4]) {
169 ESP_LOGVV(TAG,
"parse_xiaomi_header(): duplicate data packet received (%d).",
static_cast<int>(last_frame_count));
173 last_frame_count =
raw[4];
179 if (device_uuid == 0x0098) {
181 result.
name =
"HHCCJCY01";
182 }
else if (device_uuid == 0x01aa) {
184 result.
name =
"LYWSDCGQ";
185 }
else if (device_uuid == 0x015d) {
187 result.
name =
"HHCCPOT002";
188 }
else if (device_uuid == 0x02df) {
190 result.
name =
"JQJCY01YM";
191 }
else if (device_uuid == 0x03dd) {
193 result.
name =
"MUE4094RT";
195 }
else if (device_uuid == 0x0347 ||
196 device_uuid == 0x0B48) {
198 result.
name =
"CGG1";
199 }
else if (device_uuid == 0x03bc) {
201 result.
name =
"GCLS002";
202 }
else if (device_uuid == 0x045b) {
204 result.
name =
"LYWSD02";
205 }
else if (device_uuid == 0x2542) {
207 result.
name =
"LYWSD02MMC";
208 if (
raw.size() == 19)
210 }
else if (device_uuid == 0x040a) {
212 result.
name =
"WX08ZM";
213 }
else if (device_uuid == 0x0576) {
215 result.
name =
"CGD1";
216 }
else if (device_uuid == 0x066F) {
218 result.
name =
"CGDK2";
219 }
else if (device_uuid == 0x055b) {
221 result.
name =
"LYWSD03MMC";
222 }
else if (device_uuid == 0x07f6) {
224 result.
name =
"MJYD02YLA";
225 if (
raw.size() == 19)
227 }
else if (device_uuid == 0x06d3) {
229 result.
name =
"MHOC303";
230 }
else if (device_uuid == 0x0387) {
232 result.
name =
"MHOC401";
233 }
else if (device_uuid == 0x0A83) {
235 result.
name =
"CGPR1";
236 if (
raw.size() == 19)
238 }
else if (device_uuid == 0x0A8D) {
240 result.
name =
"RTCGQ02LM";
241 if (
raw.size() == 19)
244 ESP_LOGVV(TAG,
"parse_xiaomi_header(): unknown device, no magic bytes.");
252 if ((
raw.size() != 19) && ((
raw.size() < 22) || (
raw.size() > 24))) {
253 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): data packet has wrong size (%d)!",
raw.size());
258 uint8_t mac_reverse[6] = {0};
259 mac_reverse[5] = (uint8_t) (
address >> 40);
260 mac_reverse[4] = (uint8_t) (
address >> 32);
261 mac_reverse[3] = (uint8_t) (
address >> 24);
262 mac_reverse[2] = (uint8_t) (
address >> 16);
263 mac_reverse[1] = (uint8_t) (
address >> 8);
264 mac_reverse[0] = (uint8_t) (
address >> 0);
279 int cipher_pos = (
raw.size() == 19) ? 5 : 11;
281 const uint8_t *v =
raw.data();
283 memcpy(vector.key, bindkey, vector.keysize);
284 memcpy(vector.ciphertext, v + cipher_pos, vector.datasize);
285 memcpy(vector.tag, v +
raw.size() - vector.tagsize, vector.tagsize);
286 memcpy(vector.iv, mac_reverse, 6);
287 memcpy(vector.iv + 6, v + 2, 3);
288 memcpy(vector.iv + 9, v +
raw.size() - 7, 3);
290 mbedtls_ccm_context ctx;
291 mbedtls_ccm_init(&ctx);
293 int ret = mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, vector.key, vector.keysize * 8);
295 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): mbedtls_ccm_setkey() failed.");
296 mbedtls_ccm_free(&ctx);
300 ret = mbedtls_ccm_auth_decrypt(&ctx, vector.datasize, vector.iv, vector.ivsize, vector.authdata, vector.authsize,
301 vector.ciphertext, vector.plaintext, vector.tag, vector.tagsize);
303 uint8_t mac_address[6] = {0};
304 memcpy(mac_address, mac_reverse + 5, 1);
305 memcpy(mac_address + 1, mac_reverse + 4, 1);
306 memcpy(mac_address + 2, mac_reverse + 3, 1);
307 memcpy(mac_address + 3, mac_reverse + 2, 1);
308 memcpy(mac_address + 4, mac_reverse + 1, 1);
309 memcpy(mac_address + 5, mac_reverse, 1);
310 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): authenticated decryption failed.");
313 ESP_LOGVV(TAG,
" Key : %s",
format_hex_pretty(vector.key, vector.keysize).c_str());
315 ESP_LOGVV(TAG,
" Cipher : %s",
format_hex_pretty(vector.ciphertext, vector.datasize).c_str());
316 ESP_LOGVV(TAG,
" Tag : %s",
format_hex_pretty(vector.tag, vector.tagsize).c_str());
317 mbedtls_ccm_free(&ctx);
322 uint8_t *p = vector.plaintext;
323 for (std::vector<uint8_t>::iterator it =
raw.begin() + cipher_pos; it !=
raw.begin() + cipher_pos + vector.datasize;
331 ESP_LOGVV(TAG,
"decrypt_xiaomi_payload(): authenticated decryption passed.");
332 ESP_LOGVV(TAG,
" Plaintext : %s, Packet : %d",
format_hex_pretty(
raw.data() + cipher_pos, vector.datasize).c_str(),
333 static_cast<int>(
raw[4]));
335 mbedtls_ccm_free(&ctx);