mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 06:33:51 +00:00 
			
		
		
		
	Merge branch 'dev' of https://github.com/esphome/esphome into dev
This commit is contained in:
		| @@ -12,6 +12,75 @@ namespace xiaomi_ble { | |||||||
|  |  | ||||||
| static const char *TAG = "xiaomi_ble"; | static const char *TAG = "xiaomi_ble"; | ||||||
|  |  | ||||||
|  | bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result) { | ||||||
|  |   // motion detection, 1 byte, 8-bit unsigned integer | ||||||
|  |   if ((value_type == 0x03) && (value_length == 1)) { | ||||||
|  |     result.has_motion = (data[0]) ? true : false; | ||||||
|  |   } | ||||||
|  |   // temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C | ||||||
|  |   else if ((value_type == 0x04) && (value_length == 2)) { | ||||||
|  |     const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8); | ||||||
|  |     result.temperature = temperature / 10.0f; | ||||||
|  |   } | ||||||
|  |   // humidity, 2 bytes, 16-bit signed integer (LE), 0.1 % | ||||||
|  |   else if ((value_type == 0x06) && (value_length == 2)) { | ||||||
|  |     const int16_t humidity = uint16_t(data[0]) | (uint16_t(data[1]) << 8); | ||||||
|  |     result.humidity = humidity / 10.0f; | ||||||
|  |   } | ||||||
|  |   // illuminance (+ motion), 3 bytes, 24-bit unsigned integer (LE), 1 lx | ||||||
|  |   else if (((value_type == 0x07) || (value_type == 0x0F)) && (value_length == 3)) { | ||||||
|  |     const uint32_t illuminance = uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16); | ||||||
|  |     result.illuminance = illuminance; | ||||||
|  |     result.is_light = (illuminance == 100) ? true : false; | ||||||
|  |     if (value_type == 0x0F) | ||||||
|  |       result.has_motion = true; | ||||||
|  |   } | ||||||
|  |   // soil moisture, 1 byte, 8-bit unsigned integer, 1 % | ||||||
|  |   else if ((value_type == 0x08) && (value_length == 1)) { | ||||||
|  |     result.moisture = data[0]; | ||||||
|  |   } | ||||||
|  |   // conductivity, 2 bytes, 16-bit unsigned integer (LE), 1 µS/cm | ||||||
|  |   else if ((value_type == 0x09) && (value_length == 2)) { | ||||||
|  |     const uint16_t conductivity = uint16_t(data[0]) | (uint16_t(data[1]) << 8); | ||||||
|  |     result.conductivity = conductivity; | ||||||
|  |   } | ||||||
|  |   // battery, 1 byte, 8-bit unsigned integer, 1 % | ||||||
|  |   else if ((value_type == 0x0A) && (value_length == 1)) { | ||||||
|  |     result.battery_level = data[0]; | ||||||
|  |   } | ||||||
|  |   // temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 % | ||||||
|  |   else if ((value_type == 0x0D) && (value_length == 4)) { | ||||||
|  |     const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8); | ||||||
|  |     const int16_t humidity = uint16_t(data[2]) | (uint16_t(data[3]) << 8); | ||||||
|  |     result.temperature = temperature / 10.0f; | ||||||
|  |     result.humidity = humidity / 10.0f; | ||||||
|  |   } | ||||||
|  |   // formaldehyde, 2 bytes, 16-bit unsigned integer (LE), 0.01 mg / m3 | ||||||
|  |   else if ((value_type == 0x10) && (value_length == 2)) { | ||||||
|  |     const uint16_t formaldehyde = uint16_t(data[0]) | (uint16_t(data[1]) << 8); | ||||||
|  |     result.formaldehyde = formaldehyde / 100.0f; | ||||||
|  |   } | ||||||
|  |   // on/off state, 1 byte, 8-bit unsigned integer | ||||||
|  |   else if ((value_type == 0x12) && (value_length == 1)) { | ||||||
|  |     result.is_active = (data[0]) ? true : false; | ||||||
|  |   } | ||||||
|  |   // mosquito tablet, 1 byte, 8-bit unsigned integer, 1 % | ||||||
|  |   else if ((value_type == 0x13) && (value_length == 1)) { | ||||||
|  |     result.tablet = data[0]; | ||||||
|  |   } | ||||||
|  |   // idle time since last motion, 4 byte, 32-bit unsigned integer, 1 min | ||||||
|  |   else if ((value_type == 0x17) && (value_length == 4)) { | ||||||
|  |     const uint32_t idle_time = | ||||||
|  |         uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[2]) << 24); | ||||||
|  |     result.idle_time = idle_time / 60.0f; | ||||||
|  |     result.has_motion = (idle_time) ? false : true; | ||||||
|  |   } else { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result) { | bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result) { | ||||||
|   result.has_encryption = (message[0] & 0x08) ? true : false;  // update encryption status |   result.has_encryption = (message[0] & 0x08) ? true : false;  // update encryption status | ||||||
|   if (result.has_encryption) { |   if (result.has_encryption) { | ||||||
| @@ -25,81 +94,39 @@ bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult | |||||||
|   // Byte 2: length |   // Byte 2: length | ||||||
|   // Byte 3..3+len-1: data point value |   // Byte 3..3+len-1: data point value | ||||||
|  |  | ||||||
|   const uint8_t *raw = message.data() + result.raw_offset; |   const uint8_t *payload = message.data() + result.raw_offset; | ||||||
|   const uint8_t *data = raw + 3; |   uint8_t payload_length = message.size() - result.raw_offset; | ||||||
|   const uint8_t data_length = raw[2]; |   uint8_t payload_offset = 0; | ||||||
|  |   bool success = false; | ||||||
|  |  | ||||||
|   if ((data_length < 1) || (data_length > 4)) { |   if (payload_length < 4) { | ||||||
|     ESP_LOGVV(TAG, "parse_xiaomi_message(): payload has wrong size (%d)!", data_length); |     ESP_LOGVV(TAG, "parse_xiaomi_message(): payload has wrong size (%d)!", payload_length); | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // motion detection, 1 byte, 8-bit unsigned integer |   while (payload_length > 0) { | ||||||
|   if ((raw[0] == 0x03) && (data_length == 1)) { |     if (payload[payload_offset + 1] != 0x10) { | ||||||
|     result.has_motion = (data[0]) ? true : false; |       ESP_LOGVV(TAG, "parse_xiaomi_message(): fixed byte not found, stop parsing residual data."); | ||||||
|   } |       break; | ||||||
|   // temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C |     } | ||||||
|   else if ((raw[0] == 0x04) && (data_length == 2)) { |  | ||||||
|     const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8); |     const uint8_t value_length = payload[payload_offset + 2]; | ||||||
|     result.temperature = temperature / 10.0f; |     if ((value_length < 1) || (value_length > 4) || (payload_length < (3 + value_length))) { | ||||||
|   } |       ESP_LOGVV(TAG, "parse_xiaomi_message(): value has wrong size (%d)!", value_length); | ||||||
|   // humidity, 2 bytes, 16-bit signed integer (LE), 0.1 % |       break; | ||||||
|   else if ((raw[0] == 0x06) && (data_length == 2)) { |     } | ||||||
|     const int16_t humidity = uint16_t(data[0]) | (uint16_t(data[1]) << 8); |  | ||||||
|     result.humidity = humidity / 10.0f; |     const uint8_t value_type = payload[payload_offset + 0]; | ||||||
|   } |     const uint8_t *data = &payload[payload_offset + 3]; | ||||||
|   // illuminance (+ motion), 3 bytes, 24-bit unsigned integer (LE), 1 lx |  | ||||||
|   else if (((raw[0] == 0x07) || (raw[0] == 0x0F)) && (data_length == 3)) { |     if (parse_xiaomi_value(value_type, data, value_length, result)) | ||||||
|     const uint32_t illuminance = uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16); |       success = true; | ||||||
|     result.illuminance = illuminance; |  | ||||||
|     result.is_light = (illuminance == 100) ? true : false; |     payload_length -= 3 + value_length; | ||||||
|     if (raw[0] == 0x0F) |     payload_offset += 3 + value_length; | ||||||
|       result.has_motion = true; |  | ||||||
|   } |  | ||||||
|   // soil moisture, 1 byte, 8-bit unsigned integer, 1 % |  | ||||||
|   else if ((raw[0] == 0x08) && (data_length == 1)) { |  | ||||||
|     result.moisture = data[0]; |  | ||||||
|   } |  | ||||||
|   // conductivity, 2 bytes, 16-bit unsigned integer (LE), 1 µS/cm |  | ||||||
|   else if ((raw[0] == 0x09) && (data_length == 2)) { |  | ||||||
|     const uint16_t conductivity = uint16_t(data[0]) | (uint16_t(data[1]) << 8); |  | ||||||
|     result.conductivity = conductivity; |  | ||||||
|   } |  | ||||||
|   // battery, 1 byte, 8-bit unsigned integer, 1 % |  | ||||||
|   else if ((raw[0] == 0x0A) && (data_length == 1)) { |  | ||||||
|     result.battery_level = data[0]; |  | ||||||
|   } |  | ||||||
|   // temperature + humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 % |  | ||||||
|   else if ((raw[0] == 0x0D) && (data_length == 4)) { |  | ||||||
|     const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8); |  | ||||||
|     const int16_t humidity = uint16_t(data[2]) | (uint16_t(data[3]) << 8); |  | ||||||
|     result.temperature = temperature / 10.0f; |  | ||||||
|     result.humidity = humidity / 10.0f; |  | ||||||
|   } |  | ||||||
|   // formaldehyde, 2 bytes, 16-bit unsigned integer (LE), 0.01 mg / m3 |  | ||||||
|   else if ((raw[0] == 0x10) && (data_length == 2)) { |  | ||||||
|     const uint16_t formaldehyde = uint16_t(data[0]) | (uint16_t(data[1]) << 8); |  | ||||||
|     result.formaldehyde = formaldehyde / 100.0f; |  | ||||||
|   } |  | ||||||
|   // on/off state, 1 byte, 8-bit unsigned integer |  | ||||||
|   else if ((raw[0] == 0x12) && (data_length == 1)) { |  | ||||||
|     result.is_active = (data[0]) ? true : false; |  | ||||||
|   } |  | ||||||
|   // mosquito tablet, 1 byte, 8-bit unsigned integer, 1 % |  | ||||||
|   else if ((raw[0] == 0x13) && (data_length == 1)) { |  | ||||||
|     result.tablet = data[0]; |  | ||||||
|   } |  | ||||||
|   // idle time since last motion, 4 byte, 32-bit unsigned integer, 1 min |  | ||||||
|   else if ((raw[0] == 0x17) && (data_length == 4)) { |  | ||||||
|     const uint32_t idle_time = |  | ||||||
|         uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) | (uint32_t(data[2]) << 24); |  | ||||||
|     result.idle_time = idle_time / 60.0f; |  | ||||||
|     result.has_motion = (idle_time) ? false : true; |  | ||||||
|   } else { |  | ||||||
|     return false; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   return true; |   return success; | ||||||
| } | } | ||||||
|  |  | ||||||
| optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data) { | optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data) { | ||||||
|   | |||||||
| @@ -57,6 +57,7 @@ struct XiaomiAESVector { | |||||||
|   size_t ivsize; |   size_t ivsize; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | bool parse_xiaomi_value(uint8_t value_type, const uint8_t *data, uint8_t value_length, XiaomiParseResult &result); | ||||||
| bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result); | bool parse_xiaomi_message(const std::vector<uint8_t> &message, XiaomiParseResult &result); | ||||||
| optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data); | optional<XiaomiParseResult> parse_xiaomi_header(const esp32_ble_tracker::ServiceData &service_data); | ||||||
| bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, const uint64_t &address); | bool decrypt_xiaomi_payload(std::vector<uint8_t> &raw, const uint8_t *bindkey, const uint64_t &address); | ||||||
|   | |||||||
| @@ -205,7 +205,7 @@ def process_stacktrace(config, line, backtrace_state): | |||||||
|     # ESP8266 Exception type |     # ESP8266 Exception type | ||||||
|     match = re.match(STACKTRACE_ESP8266_EXCEPTION_TYPE_RE, line) |     match = re.match(STACKTRACE_ESP8266_EXCEPTION_TYPE_RE, line) | ||||||
|     if match is not None: |     if match is not None: | ||||||
|         code = match.group(1) |         code = int(match.group(1)) | ||||||
|         _LOGGER.warning("Exception type: %s", ESP8266_EXCEPTION_CODES.get(code, 'unknown')) |         _LOGGER.warning("Exception type: %s", ESP8266_EXCEPTION_CODES.get(code, 'unknown')) | ||||||
|  |  | ||||||
|     # ESP8266 PC/EXCVADDR |     # ESP8266 PC/EXCVADDR | ||||||
| @@ -273,4 +273,9 @@ class IDEData: | |||||||
|         if cc_path is None: |         if cc_path is None: | ||||||
|             return None |             return None | ||||||
|         # replace gcc at end with addr2line |         # replace gcc at end with addr2line | ||||||
|  |  | ||||||
|  |         # Windows | ||||||
|  |         if cc_path.endswith('.exe'): | ||||||
|  |             return cc_path[:-7] + 'addr2line.exe' | ||||||
|  |  | ||||||
|         return cc_path[:-3] + 'addr2line' |         return cc_path[:-3] + 'addr2line' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user