mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 09:44:12 +01:00
Merge branch 'dev' of https://github.com/esphome/esphome into dev
This commit is contained in:
commit
4774061405
3 changed files with 103 additions and 70 deletions
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue