mirror of
https://github.com/esphome/esphome.git
synced 2025-10-31 23:21:54 +00:00
Merge remote-tracking branch 'upstream/dev' into integration
This commit is contained in:
@@ -96,8 +96,11 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
||||
BLEClientWriteAction(BLEClient *ble_client) {
|
||||
ble_client->register_ble_node(this);
|
||||
ble_client_ = ble_client;
|
||||
this->construct_simple_value_();
|
||||
}
|
||||
|
||||
~BLEClientWriteAction() { this->destroy_simple_value_(); }
|
||||
|
||||
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
@@ -106,14 +109,18 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
||||
void set_char_uuid32(uint32_t uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_char_uuid128(uint8_t *uuid) { this->char_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
|
||||
void set_value_template(std::function<std::vector<uint8_t>(Ts...)> func) {
|
||||
this->value_template_ = std::move(func);
|
||||
has_simple_value_ = false;
|
||||
void set_value_template(std::vector<uint8_t> (*func)(Ts...)) {
|
||||
this->destroy_simple_value_();
|
||||
this->value_.template_func = func;
|
||||
this->has_simple_value_ = false;
|
||||
}
|
||||
|
||||
void set_value_simple(const std::vector<uint8_t> &value) {
|
||||
this->value_simple_ = value;
|
||||
has_simple_value_ = true;
|
||||
if (!this->has_simple_value_) {
|
||||
this->construct_simple_value_();
|
||||
}
|
||||
this->value_.simple = value;
|
||||
this->has_simple_value_ = true;
|
||||
}
|
||||
|
||||
void play(Ts... x) override {}
|
||||
@@ -121,7 +128,7 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
||||
void play_complex(Ts... x) override {
|
||||
this->num_running_++;
|
||||
this->var_ = std::make_tuple(x...);
|
||||
auto value = this->has_simple_value_ ? this->value_simple_ : this->value_template_(x...);
|
||||
auto value = this->has_simple_value_ ? this->value_.simple : this->value_.template_func(x...);
|
||||
// on write failure, continue the automation chain rather than stopping so that e.g. disconnect can work.
|
||||
if (!write(value))
|
||||
this->play_next_(x...);
|
||||
@@ -194,10 +201,22 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
|
||||
}
|
||||
|
||||
private:
|
||||
void construct_simple_value_() { new (&this->value_.simple) std::vector<uint8_t>(); }
|
||||
|
||||
void destroy_simple_value_() {
|
||||
if (this->has_simple_value_) {
|
||||
this->value_.simple.~vector();
|
||||
}
|
||||
}
|
||||
|
||||
BLEClient *ble_client_;
|
||||
bool has_simple_value_ = true;
|
||||
std::vector<uint8_t> value_simple_;
|
||||
std::function<std::vector<uint8_t>(Ts...)> value_template_{};
|
||||
union Value {
|
||||
std::vector<uint8_t> simple;
|
||||
std::vector<uint8_t> (*template_func)(Ts...);
|
||||
Value() {} // trivial constructor
|
||||
~Value() {} // trivial destructor - we manage lifetime via discriminator
|
||||
} value_;
|
||||
espbt::ESPBTUUID service_uuid_;
|
||||
espbt::ESPBTUUID char_uuid_;
|
||||
std::tuple<Ts...> var_{};
|
||||
@@ -213,9 +232,9 @@ template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...
|
||||
void play(Ts... x) override {
|
||||
uint32_t passkey;
|
||||
if (has_simple_value_) {
|
||||
passkey = this->value_simple_;
|
||||
passkey = this->value_.simple;
|
||||
} else {
|
||||
passkey = this->value_template_(x...);
|
||||
passkey = this->value_.template_func(x...);
|
||||
}
|
||||
if (passkey > 999999)
|
||||
return;
|
||||
@@ -224,21 +243,23 @@ template<typename... Ts> class BLEClientPasskeyReplyAction : public Action<Ts...
|
||||
esp_ble_passkey_reply(remote_bda, true, passkey);
|
||||
}
|
||||
|
||||
void set_value_template(std::function<uint32_t(Ts...)> func) {
|
||||
this->value_template_ = std::move(func);
|
||||
has_simple_value_ = false;
|
||||
void set_value_template(uint32_t (*func)(Ts...)) {
|
||||
this->value_.template_func = func;
|
||||
this->has_simple_value_ = false;
|
||||
}
|
||||
|
||||
void set_value_simple(const uint32_t &value) {
|
||||
this->value_simple_ = value;
|
||||
has_simple_value_ = true;
|
||||
this->value_.simple = value;
|
||||
this->has_simple_value_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
BLEClient *parent_{nullptr};
|
||||
bool has_simple_value_ = true;
|
||||
uint32_t value_simple_{0};
|
||||
std::function<uint32_t(Ts...)> value_template_{};
|
||||
union {
|
||||
uint32_t simple;
|
||||
uint32_t (*template_func)(Ts...);
|
||||
} value_{.simple = 0};
|
||||
};
|
||||
|
||||
template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Action<Ts...> {
|
||||
@@ -249,27 +270,29 @@ template<typename... Ts> class BLEClientNumericComparisonReplyAction : public Ac
|
||||
esp_bd_addr_t remote_bda;
|
||||
memcpy(remote_bda, parent_->get_remote_bda(), sizeof(esp_bd_addr_t));
|
||||
if (has_simple_value_) {
|
||||
esp_ble_confirm_reply(remote_bda, this->value_simple_);
|
||||
esp_ble_confirm_reply(remote_bda, this->value_.simple);
|
||||
} else {
|
||||
esp_ble_confirm_reply(remote_bda, this->value_template_(x...));
|
||||
esp_ble_confirm_reply(remote_bda, this->value_.template_func(x...));
|
||||
}
|
||||
}
|
||||
|
||||
void set_value_template(std::function<bool(Ts...)> func) {
|
||||
this->value_template_ = std::move(func);
|
||||
has_simple_value_ = false;
|
||||
void set_value_template(bool (*func)(Ts...)) {
|
||||
this->value_.template_func = func;
|
||||
this->has_simple_value_ = false;
|
||||
}
|
||||
|
||||
void set_value_simple(const bool &value) {
|
||||
this->value_simple_ = value;
|
||||
has_simple_value_ = true;
|
||||
this->value_.simple = value;
|
||||
this->has_simple_value_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
BLEClient *parent_{nullptr};
|
||||
bool has_simple_value_ = true;
|
||||
bool value_simple_{false};
|
||||
std::function<bool(Ts...)> value_template_{};
|
||||
union {
|
||||
bool simple;
|
||||
bool (*template_func)(Ts...);
|
||||
} value_{.simple = false};
|
||||
};
|
||||
|
||||
template<typename... Ts> class BLEClientRemoveBondAction : public Action<Ts...> {
|
||||
|
||||
@@ -117,9 +117,9 @@ void BLESensor::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
}
|
||||
|
||||
float BLESensor::parse_data_(uint8_t *value, uint16_t value_len) {
|
||||
if (this->data_to_value_func_.has_value()) {
|
||||
if (this->has_data_to_value_) {
|
||||
std::vector<uint8_t> data(value, value + value_len);
|
||||
return (*this->data_to_value_func_)(data);
|
||||
return this->data_to_value_func_(data);
|
||||
} else {
|
||||
return value[0];
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace ble_client {
|
||||
|
||||
namespace espbt = esphome::esp32_ble_tracker;
|
||||
|
||||
using data_to_value_t = std::function<float(std::vector<uint8_t>)>;
|
||||
|
||||
class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClientNode {
|
||||
public:
|
||||
void loop() override;
|
||||
@@ -33,13 +31,17 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie
|
||||
void set_descr_uuid16(uint16_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
|
||||
void set_descr_uuid32(uint32_t uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
|
||||
void set_descr_uuid128(uint8_t *uuid) { this->descr_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }
|
||||
void set_data_to_value(data_to_value_t &&lambda) { this->data_to_value_func_ = lambda; }
|
||||
void set_data_to_value(float (*lambda)(const std::vector<uint8_t> &)) {
|
||||
this->data_to_value_func_ = lambda;
|
||||
this->has_data_to_value_ = true;
|
||||
}
|
||||
void set_enable_notify(bool notify) { this->notify_ = notify; }
|
||||
uint16_t handle;
|
||||
|
||||
protected:
|
||||
float parse_data_(uint8_t *value, uint16_t value_len);
|
||||
optional<data_to_value_t> data_to_value_func_{};
|
||||
bool has_data_to_value_{false};
|
||||
float (*data_to_value_func_)(const std::vector<uint8_t> &){};
|
||||
bool notify_;
|
||||
espbt::ESPBTUUID service_uuid_;
|
||||
espbt::ESPBTUUID char_uuid_;
|
||||
|
||||
@@ -124,7 +124,7 @@ class HttpRequestComponent : public Component {
|
||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
||||
|
||||
void set_useragent(const char *useragent) { this->useragent_ = useragent; }
|
||||
void set_timeout(uint16_t timeout) { this->timeout_ = timeout; }
|
||||
void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
|
||||
void set_watchdog_timeout(uint32_t watchdog_timeout) { this->watchdog_timeout_ = watchdog_timeout; }
|
||||
uint32_t get_watchdog_timeout() const { return this->watchdog_timeout_; }
|
||||
void set_follow_redirects(bool follow_redirects) { this->follow_redirects_ = follow_redirects; }
|
||||
@@ -173,7 +173,7 @@ class HttpRequestComponent : public Component {
|
||||
const char *useragent_{nullptr};
|
||||
bool follow_redirects_{};
|
||||
uint16_t redirect_limit_{};
|
||||
uint16_t timeout_{4500};
|
||||
uint32_t timeout_{4500};
|
||||
uint32_t watchdog_timeout_{0};
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from esphome.const import (
|
||||
CONF_FAMILY,
|
||||
CONF_GROUP,
|
||||
CONF_ID,
|
||||
CONF_INDEX,
|
||||
CONF_INVERTED,
|
||||
CONF_LEVEL,
|
||||
CONF_MAGNITUDE,
|
||||
@@ -616,6 +617,49 @@ async def dooya_action(var, config, args):
|
||||
cg.add(var.set_check(template_))
|
||||
|
||||
|
||||
# Dyson
|
||||
DysonData, DysonBinarySensor, DysonTrigger, DysonAction, DysonDumper = declare_protocol(
|
||||
"Dyson"
|
||||
)
|
||||
DYSON_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_CODE): cv.hex_uint16_t,
|
||||
cv.Optional(CONF_INDEX, default=0xFF): cv.hex_uint8_t,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register_binary_sensor("dyson", DysonBinarySensor, DYSON_SCHEMA)
|
||||
def dyson_binary_sensor(var, config):
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(
|
||||
DysonData,
|
||||
("code", config[CONF_CODE]),
|
||||
("index", config[CONF_INDEX]),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@register_trigger("dyson", DysonTrigger, DysonData)
|
||||
def dyson_trigger(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_dumper("dyson", DysonDumper)
|
||||
def dyson_dumper(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_action("dyson", DysonAction, DYSON_SCHEMA)
|
||||
async def dyson_action(var, config, args):
|
||||
template_ = await cg.templatable(config[CONF_CODE], args, cg.uint16)
|
||||
cg.add(var.set_code(template_))
|
||||
template_ = await cg.templatable(config[CONF_INDEX], args, cg.uint8)
|
||||
cg.add(var.set_index(template_))
|
||||
|
||||
|
||||
# JVC
|
||||
JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol("JVC")
|
||||
JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t})
|
||||
|
||||
71
esphome/components/remote_base/dyson_protocol.cpp
Normal file
71
esphome/components/remote_base/dyson_protocol.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "dyson_protocol.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
static const char *const TAG = "remote.dyson";
|
||||
|
||||
// pulsewidth [µs]
|
||||
constexpr uint32_t PW_MARK_US = 780;
|
||||
constexpr uint32_t PW_SHORT_US = 720;
|
||||
constexpr uint32_t PW_LONG_US = 1500;
|
||||
constexpr uint32_t PW_START_US = 2280;
|
||||
|
||||
// MSB of 15 bit dyson code
|
||||
constexpr uint16_t MSB_DYSON = (1 << 14);
|
||||
|
||||
// required symbols in transmit buffer = (start_symbol + 15 data_symbols)
|
||||
constexpr uint32_t N_SYMBOLS_REQ = 2u * (1 + 15);
|
||||
|
||||
void DysonProtocol::encode(RemoteTransmitData *dst, const DysonData &data) {
|
||||
uint32_t raw_code = (data.code << 2) + (data.index & 3);
|
||||
dst->set_carrier_frequency(36000);
|
||||
dst->reserve(N_SYMBOLS_REQ + 1);
|
||||
dst->item(PW_START_US, PW_SHORT_US);
|
||||
for (uint16_t mask = MSB_DYSON; mask != 0; mask >>= 1) {
|
||||
if (mask == (mask & raw_code)) {
|
||||
dst->item(PW_MARK_US, PW_LONG_US);
|
||||
} else {
|
||||
dst->item(PW_MARK_US, PW_SHORT_US);
|
||||
}
|
||||
}
|
||||
dst->mark(PW_MARK_US); // final carrier pulse
|
||||
}
|
||||
|
||||
optional<DysonData> DysonProtocol::decode(RemoteReceiveData src) {
|
||||
uint32_t n_received = static_cast<uint32_t>(src.size());
|
||||
uint16_t raw_code = 0;
|
||||
DysonData data{
|
||||
.code = 0,
|
||||
.index = 0,
|
||||
};
|
||||
if (n_received < N_SYMBOLS_REQ)
|
||||
return {}; // invalid frame length
|
||||
if (!src.expect_item(PW_START_US, PW_SHORT_US))
|
||||
return {}; // start not found
|
||||
for (uint16_t mask = MSB_DYSON; mask != 0; mask >>= 1) {
|
||||
if (src.expect_item(PW_MARK_US, PW_SHORT_US)) {
|
||||
raw_code &= ~mask; // zero detected
|
||||
} else if (src.expect_item(PW_MARK_US, PW_LONG_US)) {
|
||||
raw_code |= mask; // one detected
|
||||
} else {
|
||||
return {}; // invalid data item
|
||||
}
|
||||
}
|
||||
data.code = raw_code >> 2; // extract button code
|
||||
data.index = raw_code & 3; // extract rolling index
|
||||
if (src.expect_mark(PW_MARK_US)) { // check total length
|
||||
return data;
|
||||
}
|
||||
return {}; // frame not complete
|
||||
}
|
||||
|
||||
void DysonProtocol::dump(const DysonData &data) {
|
||||
ESP_LOGI(TAG, "Dyson: code=0x%x rolling index=%d", data.code, data.index);
|
||||
}
|
||||
|
||||
} // namespace remote_base
|
||||
} // namespace esphome
|
||||
46
esphome/components/remote_base/dyson_protocol.h
Normal file
46
esphome/components/remote_base/dyson_protocol.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include "remote_base.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
static constexpr uint8_t IGNORE_INDEX = 0xFF;
|
||||
|
||||
struct DysonData {
|
||||
uint16_t code; // the button, e.g. power, swing, fan++, ...
|
||||
uint8_t index; // the rolling index counter
|
||||
bool operator==(const DysonData &rhs) const {
|
||||
if (IGNORE_INDEX == index || IGNORE_INDEX == rhs.index) {
|
||||
return code == rhs.code;
|
||||
}
|
||||
return code == rhs.code && index == rhs.index;
|
||||
}
|
||||
};
|
||||
|
||||
class DysonProtocol : public RemoteProtocol<DysonData> {
|
||||
public:
|
||||
void encode(RemoteTransmitData *dst, const DysonData &data) override;
|
||||
optional<DysonData> decode(RemoteReceiveData src) override;
|
||||
void dump(const DysonData &data) override;
|
||||
};
|
||||
|
||||
DECLARE_REMOTE_PROTOCOL(Dyson)
|
||||
|
||||
template<typename... Ts> class DysonAction : public RemoteTransmitterActionBase<Ts...> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint16_t, code)
|
||||
TEMPLATABLE_VALUE(uint8_t, index)
|
||||
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
DysonData data{};
|
||||
data.code = this->code_.value(x...);
|
||||
data.index = this->index_.value(x...);
|
||||
DysonProtocol().encode(dst, data);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace remote_base
|
||||
} // namespace esphome
|
||||
@@ -48,7 +48,6 @@ import sys
|
||||
from typing import Any
|
||||
|
||||
from helpers import (
|
||||
BASE_BUS_COMPONENTS,
|
||||
CPP_FILE_EXTENSIONS,
|
||||
PYTHON_FILE_EXTENSIONS,
|
||||
changed_files,
|
||||
@@ -453,7 +452,7 @@ def detect_memory_impact_config(
|
||||
# Get actually changed files (not dependencies)
|
||||
files = changed_files(branch)
|
||||
|
||||
# Find all changed components (excluding core and base bus components)
|
||||
# Find all changed components (excluding core)
|
||||
# Also collect platform hints from platform-specific filenames
|
||||
changed_component_set: set[str] = set()
|
||||
has_core_cpp_changes = False
|
||||
@@ -462,12 +461,12 @@ def detect_memory_impact_config(
|
||||
for file in files:
|
||||
component = get_component_from_path(file)
|
||||
if component:
|
||||
# Skip base bus components as they're used across many builds
|
||||
if component not in BASE_BUS_COMPONENTS:
|
||||
# Add all changed components, including base bus components
|
||||
# Base bus components (uart, i2c, spi, etc.) should still be analyzed
|
||||
# when directly changed, even though they're also used as dependencies
|
||||
changed_component_set.add(component)
|
||||
# Check if this is a platform-specific file
|
||||
platform_hint = _detect_platform_hint_from_filename(file)
|
||||
if platform_hint:
|
||||
if platform_hint := _detect_platform_hint_from_filename(file):
|
||||
platform_hints.append(platform_hint)
|
||||
elif file.startswith("esphome/") and file.endswith(CPP_FILE_EXTENSIONS):
|
||||
# Core ESPHome C++ files changed (not component-specific)
|
||||
|
||||
@@ -3,3 +3,52 @@ esp32_ble_tracker:
|
||||
ble_client:
|
||||
- mac_address: 01:02:03:04:05:06
|
||||
id: test_blec
|
||||
on_connect:
|
||||
- ble_client.ble_write:
|
||||
id: test_blec
|
||||
service_uuid: "abcd1234-abcd-1234-abcd-abcd12345678"
|
||||
characteristic_uuid: "abcd1235-abcd-1234-abcd-abcd12345678"
|
||||
value: !lambda |-
|
||||
return std::vector<uint8_t>{0x01, 0x02, 0x03};
|
||||
- ble_client.ble_write:
|
||||
id: test_blec
|
||||
service_uuid: "abcd1234-abcd-1234-abcd-abcd12345678"
|
||||
characteristic_uuid: "abcd1235-abcd-1234-abcd-abcd12345678"
|
||||
value: [0x04, 0x05, 0x06]
|
||||
on_passkey_request:
|
||||
- ble_client.passkey_reply:
|
||||
id: test_blec
|
||||
passkey: !lambda |-
|
||||
return 123456;
|
||||
- ble_client.passkey_reply:
|
||||
id: test_blec
|
||||
passkey: 654321
|
||||
on_numeric_comparison_request:
|
||||
- ble_client.numeric_comparison_reply:
|
||||
id: test_blec
|
||||
accept: !lambda |-
|
||||
return true;
|
||||
- ble_client.numeric_comparison_reply:
|
||||
id: test_blec
|
||||
accept: false
|
||||
|
||||
sensor:
|
||||
- platform: ble_client
|
||||
ble_client_id: test_blec
|
||||
type: characteristic
|
||||
id: test_sensor_lambda
|
||||
name: "BLE Sensor with Lambda"
|
||||
service_uuid: "abcd1234-abcd-1234-abcd-abcd12345678"
|
||||
characteristic_uuid: "abcd1236-abcd-1234-abcd-abcd12345678"
|
||||
lambda: |-
|
||||
if (x.size() >= 2) {
|
||||
return (float)(x[0] | (x[1] << 8)) / 100.0;
|
||||
}
|
||||
return NAN;
|
||||
- platform: ble_client
|
||||
ble_client_id: test_blec
|
||||
type: characteristic
|
||||
id: test_sensor_no_lambda
|
||||
name: "BLE Sensor without Lambda"
|
||||
service_uuid: "abcd1234-abcd-1234-abcd-abcd12345678"
|
||||
characteristic_uuid: "abcd1237-abcd-1234-abcd-abcd12345678"
|
||||
|
||||
@@ -48,6 +48,11 @@ on_drayton:
|
||||
- logger.log:
|
||||
format: "on_drayton: %u %u %u"
|
||||
args: ["x.address", "x.channel", "x.command"]
|
||||
on_dyson:
|
||||
then:
|
||||
- logger.log:
|
||||
format: "on_dyson: %u %u"
|
||||
args: ["x.code", "x.index"]
|
||||
on_gobox:
|
||||
then:
|
||||
- logger.log:
|
||||
|
||||
@@ -6,6 +6,13 @@ button:
|
||||
remote_transmitter.transmit_beo4:
|
||||
source: 0x01
|
||||
command: 0x0C
|
||||
- platform: template
|
||||
name: Dyson fan up
|
||||
id: dyson_fan_up
|
||||
on_press:
|
||||
remote_transmitter.transmit_dyson:
|
||||
code: 0x1215
|
||||
index: 0x0
|
||||
- platform: template
|
||||
name: JVC Off
|
||||
id: living_room_lights_on
|
||||
|
||||
@@ -19,3 +19,41 @@ uart:
|
||||
|
||||
packet_transport:
|
||||
- platform: uart
|
||||
|
||||
switch:
|
||||
# Test uart switch with single state (array)
|
||||
- platform: uart
|
||||
name: "UART Switch Single Array"
|
||||
uart_id: uart_uart
|
||||
data: [0x01, 0x02, 0x03]
|
||||
# Test uart switch with single state (string)
|
||||
- platform: uart
|
||||
name: "UART Switch Single String"
|
||||
uart_id: uart_uart
|
||||
data: "ON"
|
||||
# Test uart switch with turn_on/turn_off (arrays)
|
||||
- platform: uart
|
||||
name: "UART Switch Dual Array"
|
||||
uart_id: uart_uart
|
||||
data:
|
||||
turn_on: [0xA0, 0xA1, 0xA2]
|
||||
turn_off: [0xB0, 0xB1, 0xB2]
|
||||
# Test uart switch with turn_on/turn_off (strings)
|
||||
- platform: uart
|
||||
name: "UART Switch Dual String"
|
||||
uart_id: uart_uart
|
||||
data:
|
||||
turn_on: "TURN_ON"
|
||||
turn_off: "TURN_OFF"
|
||||
|
||||
button:
|
||||
# Test uart button with array data
|
||||
- platform: uart
|
||||
name: "UART Button Array"
|
||||
uart_id: uart_uart
|
||||
data: [0xFF, 0xEE, 0xDD]
|
||||
# Test uart button with string data
|
||||
- platform: uart
|
||||
name: "UART Button String"
|
||||
uart_id: uart_uart
|
||||
data: "BUTTON_PRESS"
|
||||
|
||||
@@ -13,3 +13,21 @@ uart:
|
||||
rx_buffer_size: 512
|
||||
parity: EVEN
|
||||
stop_bits: 2
|
||||
|
||||
switch:
|
||||
- platform: uart
|
||||
name: "UART Switch Array"
|
||||
uart_id: uart_uart
|
||||
data: [0x01, 0x02, 0x03]
|
||||
- platform: uart
|
||||
name: "UART Switch Dual"
|
||||
uart_id: uart_uart
|
||||
data:
|
||||
turn_on: [0xA0, 0xA1]
|
||||
turn_off: [0xB0, 0xB1]
|
||||
|
||||
button:
|
||||
- platform: uart
|
||||
name: "UART Button"
|
||||
uart_id: uart_uart
|
||||
data: [0xFF, 0xEE]
|
||||
|
||||
@@ -849,39 +849,47 @@ def test_detect_memory_impact_config_no_components_with_tests(tmp_path: Path) ->
|
||||
assert result["should_run"] == "false"
|
||||
|
||||
|
||||
def test_detect_memory_impact_config_skips_base_bus_components(tmp_path: Path) -> None:
|
||||
"""Test that base bus components (i2c, spi, uart) are skipped."""
|
||||
def test_detect_memory_impact_config_includes_base_bus_components(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
"""Test that base bus components (i2c, spi, uart) are included when directly changed.
|
||||
|
||||
Base bus components should be analyzed for memory impact when they are directly
|
||||
changed, even though they are often used as dependencies. This ensures that
|
||||
optimizations to base components (like using move semantics or initializer_list)
|
||||
are properly measured.
|
||||
"""
|
||||
# Create test directory structure
|
||||
tests_dir = tmp_path / "tests" / "components"
|
||||
|
||||
# i2c component (should be skipped as it's a base bus component)
|
||||
i2c_dir = tests_dir / "i2c"
|
||||
i2c_dir.mkdir(parents=True)
|
||||
(i2c_dir / "test.esp32-idf.yaml").write_text("test: i2c")
|
||||
# uart component (base bus component that should be included)
|
||||
uart_dir = tests_dir / "uart"
|
||||
uart_dir.mkdir(parents=True)
|
||||
(uart_dir / "test.esp32-idf.yaml").write_text("test: uart")
|
||||
|
||||
# wifi component (should not be skipped)
|
||||
# wifi component (regular component)
|
||||
wifi_dir = tests_dir / "wifi"
|
||||
wifi_dir.mkdir(parents=True)
|
||||
(wifi_dir / "test.esp32-idf.yaml").write_text("test: wifi")
|
||||
|
||||
# Mock changed_files to return both i2c and wifi
|
||||
# Mock changed_files to return both uart and wifi
|
||||
with (
|
||||
patch.object(determine_jobs, "root_path", str(tmp_path)),
|
||||
patch.object(helpers, "root_path", str(tmp_path)),
|
||||
patch.object(determine_jobs, "changed_files") as mock_changed_files,
|
||||
):
|
||||
mock_changed_files.return_value = [
|
||||
"esphome/components/i2c/i2c.cpp",
|
||||
"esphome/components/uart/automation.h", # Header file with inline code
|
||||
"esphome/components/wifi/wifi.cpp",
|
||||
]
|
||||
determine_jobs._component_has_tests.cache_clear()
|
||||
|
||||
result = determine_jobs.detect_memory_impact_config()
|
||||
|
||||
# Should only include wifi, not i2c
|
||||
# Should include both uart and wifi
|
||||
assert result["should_run"] == "true"
|
||||
assert result["components"] == ["wifi"]
|
||||
assert "i2c" not in result["components"]
|
||||
assert set(result["components"]) == {"uart", "wifi"}
|
||||
assert result["platform"] == "esp32-idf" # Common platform
|
||||
|
||||
|
||||
def test_detect_memory_impact_config_with_variant_tests(tmp_path: Path) -> None:
|
||||
|
||||
Reference in New Issue
Block a user