Merge branch 'esp32-tracker-parser-cleanup' into esp32-tracker-retire-scanner-listener

This commit is contained in:
J. Nick Koston
2026-08-08 09:52:24 -05:00
116 changed files with 1282 additions and 350 deletions
@@ -0,0 +1,39 @@
"""Tests for modbus configuration validation."""
import pytest
from esphome import config_validation as cv
from esphome.components import modbus
from esphome.components.modbus import CONF_MODBUS_ID, _validate_server_address
from esphome.const import CONF_ADDRESS
def test_server_address_accepts_valid_unit_address() -> None:
# A normal unit address (1-247) is accepted and returned as an int.
assert _validate_server_address(1) == 1
assert _validate_server_address(247) == 247
def test_server_address_accepts_hex_string() -> None:
# hex_uint8_t parses hex strings, and the validator returns the parsed int.
assert _validate_server_address("0x10") == 0x10
def test_server_address_zero_rejected() -> None:
# Address 0 is the Modbus broadcast address and cannot identify a server device.
with pytest.raises(cv.Invalid, match="broadcast address"):
_validate_server_address(0)
def test_server_schema_rejects_address_zero() -> None:
# The server-role schema wires in _validate_server_address, so address 0 is rejected there too.
schema = modbus.modbus_device_schema(0x01, role="server")
with pytest.raises(cv.Invalid, match="broadcast address"):
schema({CONF_MODBUS_ID: "hub", CONF_ADDRESS: 0})
def test_client_schema_still_accepts_address_zero() -> None:
# Not rejected for clients today, but not supported either: a client broadcast gets no reply and
# stalls the hub for the full send-wait.
schema = modbus.modbus_device_schema(0x01)
assert schema({CONF_MODBUS_ID: "hub", CONF_ADDRESS: 0})[CONF_ADDRESS] == 0
@@ -0,0 +1,276 @@
#include <gtest/gtest.h>
#include <cstdint>
#include <optional>
#include <vector>
#include "common.h"
#include "esphome/components/modbus/modbus.h"
namespace esphome::modbus {
namespace {
// A server device that records the writes the hub routes to it.
class RecordingDevice : public ModbusServerDevice {
public:
explicit RecordingDevice(uint8_t address) { this->set_address(address); }
ResponseStatus on_write_registers(uint16_t start_address, const RegisterValues &registers) override {
this->write_count++;
this->last_start_address = start_address;
this->last_values.assign(registers.begin(), registers.end());
return std::nullopt; // return value is ignored for broadcasts, which are never answered
}
int write_count{0};
uint16_t last_start_address{0};
std::vector<uint16_t> last_values;
};
// A server device that rejects every write, to exercise the broadcast dispatch loop's rejection branch.
class RejectingDevice : public ModbusServerDevice {
public:
explicit RejectingDevice(uint8_t address) { this->set_address(address); }
ResponseStatus on_write_registers(uint16_t start_address, const RegisterValues &registers) override {
this->write_count++;
return ExceptionCode::ILLEGAL_DATA_ADDRESS;
}
int write_count{0};
};
// A UART that records every byte written so the test can assert the hub sends no reply.
class RecordingUART : public testing::NullUART {
public:
void write_array(const uint8_t *data, size_t len) override {
this->written.insert(this->written.end(), data, data + len);
}
std::vector<uint8_t> written;
};
// Drives full frames through the server hub's receive path in tests.
class TestServerHub : public ModbusServerHub {
public:
bool tx_blocked() override { return false; }
// Builds a complete client frame (address + FC + pdu + CRC) and runs the full receive-side parser
// (parse_modbus_frames), so the expecting-peer-response routing is exercised, not just the frame parser
// below it. Returns true once the buffer has fully drained.
bool run_receive_parser_for_test(uint8_t address, uint8_t function_code, const uint8_t *pdu_data,
size_t pdu_data_len) {
this->rx_buffer_.clear();
this->rx_buffer_.reserve(pdu_data_len + 4);
this->rx_buffer_.push_back(address);
this->rx_buffer_.push_back(function_code);
this->rx_buffer_.insert(this->rx_buffer_.end(), pdu_data, pdu_data + pdu_data_len);
uint16_t crc = crc16(this->rx_buffer_.data(), this->rx_buffer_.size());
this->rx_buffer_.push_back(crc & 0xFF);
this->rx_buffer_.push_back(crc >> 8);
this->parse_modbus_frames();
return this->rx_buffer_.empty();
}
};
} // namespace
// A broadcast (address 0) single-register write reaches every registered device and is not answered.
// Driven through the full receive parser (parse_modbus_frames) so the address-0 routing -- frame length,
// CRC, and client-vs-broadcast dispatch -- is exercised, not just the handler below it.
TEST(ModbusBroadcast, SingleRegisterWriteReachesAllDevicesWithoutReply) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device_a(0x02);
RecordingDevice device_b(0x03);
hub.register_device(&device_a);
hub.register_device(&device_b);
// FC 0x06 payload: start address 0x9D31, value 0x00A5 (big-endian, no address/CRC).
const uint8_t pdu_data[] = {0x9D, 0x31, 0x00, 0xA5};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data, sizeof(pdu_data)));
for (RecordingDevice *device : {&device_a, &device_b}) {
EXPECT_EQ(device->write_count, 1);
EXPECT_EQ(device->last_start_address, 0x9D31);
ASSERT_EQ(device->last_values.size(), 1u);
EXPECT_EQ(device->last_values[0], 0x00A5);
}
EXPECT_TRUE(uart.written.empty()); // broadcasts are never answered
}
// A single-register broadcast (FC 0x06) must still reach every device when the hub is mid-way through
// waiting for a peer's response. Its frame length matches a response frame, so without the address-0 guard
// in parse_modbus_frames() it would be swallowed by the response parser instead of being dispatched.
TEST(ModbusBroadcast, SingleRegisterBroadcastDispatchedWhileExpectingPeerResponse) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device_a(0x02);
RecordingDevice device_b(0x03);
hub.register_device(&device_a);
hub.register_device(&device_b);
// A unicast write addressed to an unregistered peer (0x09) leaves the hub expecting that peer's response.
const uint8_t peer_pdu[] = {0x00, 0x10, 0x00, 0x2A};
ASSERT_TRUE(hub.run_receive_parser_for_test(0x09, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), peer_pdu,
sizeof(peer_pdu)));
ASSERT_EQ(device_a.write_count, 0); // the peer request is not for our devices
ASSERT_EQ(device_b.write_count, 0);
// The broadcast that follows must still be delivered to every device, and still without a reply.
const uint8_t pdu_data[] = {0x9D, 0x31, 0x00, 0xA5};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data, sizeof(pdu_data)));
for (RecordingDevice *device : {&device_a, &device_b}) {
EXPECT_EQ(device->write_count, 1);
EXPECT_EQ(device->last_start_address, 0x9D31);
ASSERT_EQ(device->last_values.size(), 1u);
EXPECT_EQ(device->last_values[0], 0x00A5);
}
EXPECT_TRUE(uart.written.empty()); // broadcasts are never answered
}
// After dispatching a broadcast, the hub must not still expect a peer response: a following unicast FC 0x06
// to one of our own devices must be handled, not misparsed as that peer's response and dropped.
TEST(ModbusBroadcast, BroadcastClearsStalePeerExpectation) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device(0x02);
hub.register_device(&device);
// A unicast write to an unregistered peer (0x09) leaves the hub expecting that peer's response.
const uint8_t pdu_data[] = {0x00, 0x10, 0x00, 0x2A};
ASSERT_TRUE(hub.run_receive_parser_for_test(0x09, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data,
sizeof(pdu_data)));
// The broadcast that follows clears that expectation as it is dispatched.
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data, sizeof(pdu_data)));
ASSERT_EQ(device.write_count, 1);
// The next unicast FC 0x06 to our own device is handled, not swallowed by the stale expectation.
ASSERT_TRUE(hub.run_receive_parser_for_test(0x02, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data,
sizeof(pdu_data)));
EXPECT_EQ(device.write_count, 2);
}
// A broadcast multi-register write is decoded and delivered to every device, still without a reply.
TEST(ModbusBroadcast, MultipleRegisterWriteReachesAllDevicesWithoutReply) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device_a(0x02);
RecordingDevice device_b(0x03);
hub.register_device(&device_a);
hub.register_device(&device_b);
// FC 0x10 payload: start 0x9D31, quantity 2, byte count 4, values 0x0102 and 0x0304.
const uint8_t pdu_data[] = {0x9D, 0x31, 0x00, 0x02, 0x04, 0x01, 0x02, 0x03, 0x04};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_MULTIPLE_REGISTERS), pdu_data, sizeof(pdu_data)));
for (RecordingDevice *device : {&device_a, &device_b}) {
EXPECT_EQ(device->write_count, 1);
EXPECT_EQ(device->last_start_address, 0x9D31);
ASSERT_EQ(device->last_values.size(), 2u);
EXPECT_EQ(device->last_values[0], 0x0102);
EXPECT_EQ(device->last_values[1], 0x0304);
}
EXPECT_TRUE(uart.written.empty());
}
// A read broadcast is meaningless (it would need a reply), so nothing is dispatched and nothing is sent.
TEST(ModbusBroadcast, ReadFunctionCodeIsIgnoredAndProducesNoReply) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device(0x02);
hub.register_device(&device);
// FC 0x03 payload: start 0x0000, quantity 2. Reads cannot be broadcast.
const uint8_t pdu_data[] = {0x00, 0x00, 0x00, 0x02};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::READ_HOLDING_REGISTERS), pdu_data, sizeof(pdu_data)));
EXPECT_EQ(device.write_count, 0); // no device was written
EXPECT_TRUE(uart.written.empty()); // and the broadcast address is never answered
}
// An invalid broadcast write is silently dropped: no writes dispatched and no exception reply sent.
TEST(ModbusBroadcast, InvalidMultipleWriteBroadcastProducesNoWriteAndNoReply) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device_a(0x02);
RecordingDevice device_b(0x03);
hub.register_device(&device_a);
hub.register_device(&device_b);
// FC 0x10 payload: quantity 2 but byte count 2 (should be 4), so parsing fails.
const uint8_t pdu_data[] = {0x9D, 0x31, 0x00, 0x02, 0x02, 0x01, 0x02};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_MULTIPLE_REGISTERS), pdu_data, sizeof(pdu_data)));
EXPECT_EQ(device_a.write_count, 0);
EXPECT_EQ(device_b.write_count, 0);
EXPECT_TRUE(uart.written.empty());
}
// A device that rejects a broadcast write must not stop dispatch to devices registered after it, and the
// broadcast is still never answered.
TEST(ModbusBroadcast, RejectingDeviceDoesNotStopBroadcastDispatch) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RejectingDevice rejecter(0x02);
RecordingDevice device(0x03);
hub.register_device(&rejecter); // registered first, so a rejection happens before the normal device
hub.register_device(&device);
// FC 0x06 payload: start address 0x9D31, value 0x00A5 (big-endian, no address/CRC).
const uint8_t pdu_data[] = {0x9D, 0x31, 0x00, 0xA5};
ASSERT_TRUE(hub.run_receive_parser_for_test(
BROADCAST_ADDRESS, static_cast<uint8_t>(FunctionCode::WRITE_SINGLE_REGISTER), pdu_data, sizeof(pdu_data)));
EXPECT_EQ(rejecter.write_count, 1); // the rejecting device was still invoked
EXPECT_EQ(device.write_count, 1); // and dispatch continued to the device registered after it
EXPECT_EQ(device.last_start_address, 0x9D31);
ASSERT_EQ(device.last_values.size(), 1u);
EXPECT_EQ(device.last_values[0], 0x00A5);
EXPECT_TRUE(uart.written.empty()); // a broadcast is never answered, even when a device rejects
}
// A unicast out-of-range write sends exactly one exception frame on the wire.
TEST(ModbusBroadcast, UnicastOutOfRangeWriteSendsSingleExceptionFrame) {
TestServerHub hub;
RecordingUART uart;
hub.set_uart_parent(&uart);
RecordingDevice device(0x02);
hub.register_device(&device);
// FC 0x10 payload: start 0xFFFF, quantity 2, byte count 4, values valid but address range overflows.
const uint8_t pdu_data[] = {0xFF, 0xFF, 0x00, 0x02, 0x04, 0x01, 0x02, 0x03, 0x04};
ASSERT_TRUE(hub.run_receive_parser_for_test(0x02, static_cast<uint8_t>(FunctionCode::WRITE_MULTIPLE_REGISTERS),
pdu_data, sizeof(pdu_data)));
EXPECT_EQ(device.write_count, 0);
ASSERT_EQ(uart.written.size(), 5u);
EXPECT_EQ(uart.written[0], 0x02); // server address
EXPECT_EQ(uart.written[1], static_cast<uint8_t>(FunctionCode::WRITE_MULTIPLE_REGISTERS) | 0x80);
EXPECT_EQ(uart.written[2], static_cast<uint8_t>(ExceptionCode::ILLEGAL_DATA_ADDRESS));
}
} // namespace esphome::modbus
+1 -1
View File
@@ -4,7 +4,7 @@ binary_sensor:
mac_address: "12:34:56:12:34:56"
bindkey: 48403ebe2d385db8d0c187f81e62cb64
battery_level:
name: CGPR1 battery Level
name: CGPR1 Battery Level
idle_time:
name: CGPR1 Idle Time
illuminance:
+1 -1
View File
@@ -9,7 +9,7 @@ binary_sensor:
mac_address: "12:34:56:12:34:56"
bindkey: 48403ebe2d385db8d0c187f81e62cb64
battery_level:
name: CGPR1 battery Level
name: CGPR1 Battery Level
idle_time:
name: CGPR1 Idle Time
illuminance:
@@ -12,7 +12,7 @@ binary_sensor:
mac_address: "12:34:56:12:34:56"
bindkey: 48403ebe2d385db8d0c187f81e62cb64
battery_level:
name: CGPR1 battery Level
name: CGPR1 Battery Level
idle_time:
name: CGPR1 Idle Time
illuminance:
@@ -0,0 +1,13 @@
sensor:
- platform: xiaomi_hhccjcy10
mac_address: 94:2B:FF:5C:91:61
temperature:
name: Xiaomi HHCCJCY10 Temperature
moisture:
name: Xiaomi HHCCJCY10 Moisture
illuminance:
name: Xiaomi HHCCJCY10 Illuminance
conductivity:
name: Xiaomi HHCCJCY10 Conductivity
battery_level:
name: Xiaomi HHCCJCY10 Battery Level
@@ -0,0 +1,18 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_hhccjcy10
ble_hub_id: ble_tracker_hub
mac_address: 94:2B:FF:5C:91:61
temperature:
name: Xiaomi HHCCJCY10 Temperature
moisture:
name: Xiaomi HHCCJCY10 Moisture
illuminance:
name: Xiaomi HHCCJCY10 Illuminance
conductivity:
name: Xiaomi HHCCJCY10 Conductivity
battery_level:
name: Xiaomi HHCCJCY10 Battery Level
@@ -0,0 +1,3 @@
packages:
ble: !include ../../test_build_components/common/ble/esp32-idf.yaml
xiaomi_hhccjcy10: !include common.yaml
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_hhccjcy10: !include common-ln.yaml
@@ -0,0 +1,26 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_hhccjcy10
ble_hub_id: ble_tracker_hub
mac_address: 94:2B:FF:5C:91:61
temperature:
name: Xiaomi HHCCJCY10 Temperature
moisture:
name: Xiaomi HHCCJCY10 Moisture
illuminance:
name: Xiaomi HHCCJCY10 Illuminance
conductivity:
name: Xiaomi HHCCJCY10 Conductivity
battery_level:
name: Xiaomi HHCCJCY10 Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_hhccjcy10
mac_address: 94:2B:FF:5C:91:62
temperature:
name: BK Xiaomi HHCCJCY10 Implicit Temperature
@@ -0,0 +1,7 @@
sensor:
- platform: xiaomi_hhccpot002
mac_address: 94:2B:FF:5C:91:61
moisture:
name: HHCCPOT002 Moisture
conductivity:
name: HHCCPOT002 Soil Conductivity
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_hhccpot002
ble_hub_id: ble_tracker_hub
mac_address: 94:2B:FF:5C:91:61
moisture:
name: HHCCPOT002 Moisture
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_hhccpot002: !include common-ln.yaml
@@ -0,0 +1,20 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_hhccpot002
ble_hub_id: ble_tracker_hub
mac_address: 94:2B:FF:5C:91:61
moisture:
name: HHCCPOT002 Moisture
conductivity:
name: HHCCPOT002 Soil Conductivity
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_hhccpot002
mac_address: 94:2B:FF:5C:91:62
moisture:
name: BK HHCCPOT002 Implicit Moisture
@@ -0,0 +1,11 @@
sensor:
- platform: xiaomi_jqjcy01ym
mac_address: 7A:80:8E:19:36:BA
temperature:
name: JQJCY01YM Temperature
humidity:
name: JQJCY01YM Humidity
formaldehyde:
name: JQJCY01YM Formaldehyde
battery_level:
name: JQJCY01YM Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_jqjcy01ym
ble_hub_id: ble_tracker_hub
mac_address: 7A:80:8E:19:36:BA
temperature:
name: JQJCY01YM Temperature
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_jqjcy01ym: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_jqjcy01ym
ble_hub_id: ble_tracker_hub
mac_address: 7A:80:8E:19:36:BA
temperature:
name: JQJCY01YM Temperature
humidity:
name: JQJCY01YM Humidity
formaldehyde:
name: JQJCY01YM Formaldehyde
battery_level:
name: JQJCY01YM Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_jqjcy01ym
mac_address: 7A:80:8E:19:36:BB
temperature:
name: BK JQJCY01YM Implicit Temperature
@@ -0,0 +1,9 @@
sensor:
- platform: xiaomi_lywsd02
mac_address: 3F:5B:7D:82:58:4E
temperature:
name: Xiaomi LYWSD02 Temperature
humidity:
name: Xiaomi LYWSD02 Humidity
battery_level:
name: Xiaomi LYWSD02 Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd02
ble_hub_id: ble_tracker_hub
mac_address: 3F:5B:7D:82:58:4E
temperature:
name: Xiaomi LYWSD02 Temperature
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_lywsd02: !include common-ln.yaml
@@ -0,0 +1,22 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd02
ble_hub_id: ble_tracker_hub
mac_address: 3F:5B:7D:82:58:4E
temperature:
name: Xiaomi LYWSD02 Temperature
humidity:
name: Xiaomi LYWSD02 Humidity
battery_level:
name: Xiaomi LYWSD02 Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_lywsd02
mac_address: 3F:5B:7D:82:58:4F
temperature:
name: BK Xiaomi LYWSD02 Implicit Temperature
@@ -0,0 +1,10 @@
sensor:
- platform: xiaomi_lywsd02mmc
mac_address: A4:C1:38:54:5E:18
bindkey: 2529d8e0d23150a588675cc54ad48400
temperature:
name: Xiaomi LYWSD02MMC Temperature
humidity:
name: Xiaomi LYWSD02MMC Humidity
battery_level:
name: Xiaomi LYWSD02MMC Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd02mmc
ble_hub_id: ble_tracker_hub
mac_address: A4:C1:38:54:5E:18
bindkey: 2529d8e0d23150a588675cc54ad48400
temperature:
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_lywsd02mmc: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd02mmc
ble_hub_id: ble_tracker_hub
mac_address: A4:C1:38:54:5E:18
bindkey: 2529d8e0d23150a588675cc54ad48400
temperature:
name: Xiaomi LYWSD02MMC Temperature
humidity:
name: Xiaomi LYWSD02MMC Humidity
battery_level:
name: Xiaomi LYWSD02MMC Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_lywsd02mmc
mac_address: A4:C1:38:54:5E:19
bindkey: 2529d8e0d23150a588675cc54ad48400
temperature:
name: BK Xiaomi LYWSD02MMC Implicit Temperature
@@ -0,0 +1,10 @@
sensor:
- platform: xiaomi_lywsd03mmc
mac_address: A4:C1:38:4E:16:78
bindkey: e9efaa6873f9f9c87a5e75a5f814801c
temperature:
name: Xiaomi LYWSD03MMC Temperature
humidity:
name: Xiaomi LYWSD03MMC Humidity
battery_level:
name: Xiaomi LYWSD03MMC Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd03mmc
ble_hub_id: ble_tracker_hub
mac_address: A4:C1:38:4E:16:78
bindkey: e9efaa6873f9f9c87a5e75a5f814801c
temperature:
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_lywsd03mmc: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsd03mmc
ble_hub_id: ble_tracker_hub
mac_address: A4:C1:38:4E:16:78
bindkey: e9efaa6873f9f9c87a5e75a5f814801c
temperature:
name: Xiaomi LYWSD03MMC Temperature
humidity:
name: Xiaomi LYWSD03MMC Humidity
battery_level:
name: Xiaomi LYWSD03MMC Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_lywsd03mmc
mac_address: A4:C1:38:4E:16:79
bindkey: e9efaa6873f9f9c87a5e75a5f814801c
temperature:
name: BK Xiaomi LYWSD03MMC Implicit Temperature
@@ -0,0 +1,9 @@
sensor:
- platform: xiaomi_lywsdcgq
mac_address: 7A:80:8E:19:36:BA
temperature:
name: Xiaomi LYWSDCGQ Temperature
humidity:
name: Xiaomi LYWSDCGQ Humidity
battery_level:
name: Xiaomi LYWSDCGQ Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsdcgq
ble_hub_id: ble_tracker_hub
mac_address: 7A:80:8E:19:36:BA
temperature:
name: Xiaomi LYWSDCGQ Temperature
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_lywsdcgq: !include common-ln.yaml
@@ -0,0 +1,22 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_lywsdcgq
ble_hub_id: ble_tracker_hub
mac_address: 7A:80:8E:19:36:BA
temperature:
name: Xiaomi LYWSDCGQ Temperature
humidity:
name: Xiaomi LYWSDCGQ Humidity
battery_level:
name: Xiaomi LYWSDCGQ Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_lywsdcgq
mac_address: 7A:80:8E:19:36:BB
temperature:
name: BK Xiaomi LYWSDCGQ Implicit Temperature
@@ -0,0 +1,9 @@
sensor:
- platform: xiaomi_mhoc303
mac_address: E7:50:59:32:A0:1C
temperature:
name: MHO-C303 Temperature
humidity:
name: MHO-C303 Humidity
battery_level:
name: MHO-C303 Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mhoc303
ble_hub_id: ble_tracker_hub
mac_address: E7:50:59:32:A0:1C
temperature:
name: MHO-C303 Temperature
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_mhoc303: !include common-ln.yaml
@@ -0,0 +1,22 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mhoc303
ble_hub_id: ble_tracker_hub
mac_address: E7:50:59:32:A0:1C
temperature:
name: MHO-C303 Temperature
humidity:
name: MHO-C303 Humidity
battery_level:
name: MHO-C303 Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_mhoc303
mac_address: E7:50:59:32:A0:1D
temperature:
name: BK MHO-C303 Implicit Temperature
@@ -0,0 +1,10 @@
sensor:
- platform: xiaomi_mhoc401
mac_address: E7:50:59:32:A0:1C
bindkey: eef418daf699a0c188f3bfd17e4565d9
temperature:
name: MHO-C401 Temperature
humidity:
name: MHO-C401 Humidity
battery_level:
name: MHO-C401 Battery Level
+6 -3
View File
@@ -1,12 +1,15 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mhoc401
ble_hub_id: ble_tracker_hub
mac_address: E7:50:59:32:A0:1C
bindkey: "eef418daf699a0c188f3bfd17e4565d9"
temperature:
name: MHO-C303 Temperature
name: MHO-C401 Temperature
humidity:
name: MHO-C303 Humidity
name: MHO-C401 Humidity
battery_level:
name: MHO-C303 Battery Level
name: MHO-C401 Battery Level
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_mhoc401: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mhoc401
ble_hub_id: ble_tracker_hub
mac_address: E7:50:59:32:A0:1C
bindkey: "eef418daf699a0c188f3bfd17e4565d9"
temperature:
name: MHO-C401 Temperature
humidity:
name: MHO-C401 Humidity
battery_level:
name: MHO-C401 Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_mhoc401
mac_address: E7:50:59:32:A0:1D
bindkey: eef418daf699a0c188f3bfd17e4565d9
temperature:
name: BK MHO-C401 Implicit Temperature
@@ -0,0 +1,7 @@
sensor:
- platform: xiaomi_miscale
mac_address: '5C:CA:D3:70:D4:A2'
weight:
name: "Xiaomi Mi Scale Weight"
impedance:
name: "Xiaomi Mi Scale Impedance"
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_miscale
ble_hub_id: ble_tracker_hub
mac_address: '5C:CA:D3:70:D4:A2'
weight:
name: "Xiaomi Mi Scale Weight"
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_miscale: !include common-ln.yaml
@@ -0,0 +1,20 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_miscale
ble_hub_id: ble_tracker_hub
mac_address: '5C:CA:D3:70:D4:A2'
weight:
name: "Xiaomi Mi Scale Weight"
impedance:
name: "Xiaomi Mi Scale Impedance"
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_miscale
mac_address: '5C:CA:D3:70:D4:A3'
weight:
name: "BK Xiaomi Mi Scale Implicit Weight"
@@ -0,0 +1,11 @@
binary_sensor:
- platform: xiaomi_mjyd02yla
name: MJYD02YL-A Motion
mac_address: 50:EC:50:CD:32:02
bindkey: 48403ebe2d385db8d0c187f81e62cb64
idle_time:
name: MJYD02YL-A Idle Time
light:
name: MJYD02YL-A Light Status
battery_level:
name: MJYD02YL-A Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mjyd02yla
ble_hub_id: ble_tracker_hub
name: MJYD02YL-A Motion
mac_address: 50:EC:50:CD:32:02
bindkey: 48403ebe2d385db8d0c187f81e62cb64
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_mjyd02yla: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mjyd02yla
ble_hub_id: ble_tracker_hub
name: MJYD02YL-A Motion
mac_address: 50:EC:50:CD:32:02
bindkey: 48403ebe2d385db8d0c187f81e62cb64
idle_time:
name: MJYD02YL-A Idle Time
light:
name: MJYD02YL-A Light Status
battery_level:
name: MJYD02YL-A Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_mjyd02yla
name: BK MJYD02YL-A Implicit Motion
mac_address: 50:EC:50:CD:32:03
bindkey: 48403ebe2d385db8d0c187f81e62cb64
@@ -0,0 +1,5 @@
binary_sensor:
- platform: xiaomi_mue4094rt
name: MUE4094RT Motion
mac_address: 7A:80:8E:19:36:BA
timeout: 5s
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mue4094rt
ble_hub_id: ble_tracker_hub
name: MUE4094RT Motion
mac_address: 7A:80:8E:19:36:BA
timeout: 5s
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_mue4094rt: !include common-ln.yaml
@@ -0,0 +1,18 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_mue4094rt
ble_hub_id: ble_tracker_hub
name: MUE4094RT Motion
mac_address: 7A:80:8E:19:36:BA
timeout: 5s
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_mue4094rt
name: BK MUE4094RT Implicit Motion
mac_address: 7A:80:8E:19:36:BB
timeout: 5s
@@ -0,0 +1,20 @@
xiaomi_rtcgq02lm:
- id: motion_rtcgq02lm
mac_address: 01:02:03:04:05:06
bindkey: "48403ebe2d385db8d0c187f81e62cb64"
binary_sensor:
- platform: xiaomi_rtcgq02lm
id: motion_rtcgq02lm
motion:
name: Mi Motion Sensor 2
light:
name: Mi Motion Sensor 2 Light
button:
name: Mi Motion Sensor 2 Button
sensor:
- platform: xiaomi_rtcgq02lm
id: motion_rtcgq02lm
battery_level:
name: Mi Motion Sensor 2 Battery level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
# Explicit ble_hub_id: pins the neutral binding as a declared key.
xiaomi_rtcgq02lm:
- id: motion_rtcgq02lm
ble_hub_id: ble_tracker_hub
mac_address: 01:02:03:04:05:06
bindkey: "48403ebe2d385db8d0c187f81e62cb64"
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_rtcgq02lm: !include common-ln.yaml
@@ -0,0 +1,32 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
# Explicit ble_hub_id: pins the neutral binding as a declared key.
xiaomi_rtcgq02lm:
- id: motion_rtcgq02lm
ble_hub_id: ble_tracker_hub
mac_address: 01:02:03:04:05:06
bindkey: "48403ebe2d385db8d0c187f81e62cb64"
# No ble_hub_id: exercises the generated binding real configs use.
- id: motion_rtcgq02lm_implicit
mac_address: 01:02:03:04:05:07
bindkey: "48403ebe2d385db8d0c187f81e62cb64"
binary_sensor:
- platform: xiaomi_rtcgq02lm
id: motion_rtcgq02lm
motion:
name: Mi Motion Sensor 2
light:
name: Mi Motion Sensor 2 Light
button:
name: Mi Motion Sensor 2 Button
sensor:
- platform: xiaomi_rtcgq02lm
id: motion_rtcgq02lm
battery_level:
name: Mi Motion Sensor 2 Battery level
@@ -0,0 +1,8 @@
binary_sensor:
- platform: xiaomi_wx08zm
name: WX08ZM Activation State
mac_address: 74:a3:4a:b5:07:34
tablet:
name: WX08ZM Tablet Resource
battery_level:
name: WX08ZM Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_wx08zm
ble_hub_id: ble_tracker_hub
name: WX08ZM Activation State
mac_address: 74:a3:4a:b5:07:34
tablet:
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_wx08zm: !include common-ln.yaml
@@ -0,0 +1,20 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
binary_sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_wx08zm
ble_hub_id: ble_tracker_hub
name: WX08ZM Activation State
mac_address: 74:a3:4a:b5:07:34
tablet:
name: WX08ZM Tablet Resource
battery_level:
name: WX08ZM Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_wx08zm
name: BK WX08ZM Implicit Activation State
mac_address: 74:a3:4a:b5:07:35
@@ -0,0 +1,10 @@
sensor:
- platform: xiaomi_xmwsdj04mmc
mac_address: 84:B4:DB:5D:A3:8F
bindkey: d8ca2ed09bb5541dc8f045ca360b00ea
temperature:
name: Xiaomi XMWSDJ04MMC Temperature
humidity:
name: Xiaomi XMWSDJ04MMC Humidity
battery_level:
name: Xiaomi XMWSDJ04MMC Battery Level
@@ -1,7 +1,10 @@
esp32_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_xmwsdj04mmc
ble_hub_id: ble_tracker_hub
mac_address: 84:B4:DB:5D:A3:8F
bindkey: d8ca2ed09bb5541dc8f045ca360b00ea
temperature:
@@ -0,0 +1,3 @@
packages:
ln882h_ble_tracker: !include ../ln882h_ble_tracker/common.yaml
xiaomi_xmwsdj04mmc: !include common-ln.yaml
@@ -0,0 +1,24 @@
# Config-only: the CI base board (generic-bk7252, BLE 4.2) cannot compile the
# BLE 5.x tracker, so this fixture proves validation (schema + neutral binding)
# on a non-esp32 platform; codegen and compilation are not exercised here.
bk72xx_ble_tracker:
id: ble_tracker_hub
sensor:
# Explicit ble_hub_id: pins the neutral binding as a declared key.
- platform: xiaomi_xmwsdj04mmc
ble_hub_id: ble_tracker_hub
mac_address: 84:B4:DB:5D:A3:8F
bindkey: d8ca2ed09bb5541dc8f045ca360b00ea
temperature:
name: Xiaomi XMWSDJ04MMC Temperature
humidity:
name: Xiaomi XMWSDJ04MMC Humidity
battery_level:
name: Xiaomi XMWSDJ04MMC Battery Level
# No ble_hub_id: exercises the generated binding real configs use.
- platform: xiaomi_xmwsdj04mmc
mac_address: 84:B4:DB:5D:A3:90
bindkey: d8ca2ed09bb5541dc8f045ca360b00ea
temperature:
name: BK Xiaomi XMWSDJ04MMC Implicit Temperature