mirror of
https://github.com/esphome/esphome.git
synced 2025-09-01 19:02:18 +01:00
Merge remote-tracking branch 'upstream/proxy_configured_mode' into integration
This commit is contained in:
@@ -11,7 +11,7 @@ ci:
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.12.10
|
||||
rev: v0.12.11
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
|
@@ -61,11 +61,10 @@ void AbsoluteHumidityComponent::loop() {
|
||||
ESP_LOGW(TAG, "No valid state from temperature sensor!");
|
||||
}
|
||||
if (no_humidity) {
|
||||
ESP_LOGW(TAG, "No valid state from temperature sensor!");
|
||||
ESP_LOGW(TAG, "No valid state from humidity sensor!");
|
||||
}
|
||||
ESP_LOGW(TAG, "Unable to calculate absolute humidity.");
|
||||
this->publish_state(NAN);
|
||||
this->status_set_warning();
|
||||
this->status_set_warning("Unable to calculate absolute humidity.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,9 +86,8 @@ void AbsoluteHumidityComponent::loop() {
|
||||
es = es_wobus(temperature_c);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Invalid saturation vapor pressure equation selection!");
|
||||
this->publish_state(NAN);
|
||||
this->status_set_error();
|
||||
this->status_set_error("Invalid saturation vapor pressure equation selection!");
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
|
||||
|
@@ -1712,6 +1712,7 @@ message BluetoothScannerStateResponse {
|
||||
|
||||
BluetoothScannerState state = 1;
|
||||
BluetoothScannerMode mode = 2;
|
||||
BluetoothScannerMode configured_mode = 3;
|
||||
}
|
||||
|
||||
message BluetoothScannerSetModeRequest {
|
||||
|
@@ -2153,10 +2153,12 @@ void BluetoothDeviceClearCacheResponse::calculate_size(ProtoSize &size) const {
|
||||
void BluetoothScannerStateResponse::encode(ProtoWriteBuffer buffer) const {
|
||||
buffer.encode_uint32(1, static_cast<uint32_t>(this->state));
|
||||
buffer.encode_uint32(2, static_cast<uint32_t>(this->mode));
|
||||
buffer.encode_uint32(3, static_cast<uint32_t>(this->configured_mode));
|
||||
}
|
||||
void BluetoothScannerStateResponse::calculate_size(ProtoSize &size) const {
|
||||
size.add_uint32(1, static_cast<uint32_t>(this->state));
|
||||
size.add_uint32(1, static_cast<uint32_t>(this->mode));
|
||||
size.add_uint32(1, static_cast<uint32_t>(this->configured_mode));
|
||||
}
|
||||
bool BluetoothScannerSetModeRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
switch (field_id) {
|
||||
|
@@ -2214,12 +2214,13 @@ class BluetoothDeviceClearCacheResponse final : public ProtoMessage {
|
||||
class BluetoothScannerStateResponse final : public ProtoMessage {
|
||||
public:
|
||||
static constexpr uint8_t MESSAGE_TYPE = 126;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 4;
|
||||
static constexpr uint8_t ESTIMATED_SIZE = 6;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
const char *message_name() const override { return "bluetooth_scanner_state_response"; }
|
||||
#endif
|
||||
enums::BluetoothScannerState state{};
|
||||
enums::BluetoothScannerMode mode{};
|
||||
enums::BluetoothScannerMode configured_mode{};
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void calculate_size(ProtoSize &size) const override;
|
||||
#ifdef HAS_PROTO_MESSAGE_DUMP
|
||||
|
@@ -1704,6 +1704,7 @@ void BluetoothScannerStateResponse::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "BluetoothScannerStateResponse");
|
||||
dump_field(out, "state", static_cast<enums::BluetoothScannerState>(this->state));
|
||||
dump_field(out, "mode", static_cast<enums::BluetoothScannerMode>(this->mode));
|
||||
dump_field(out, "configured_mode", static_cast<enums::BluetoothScannerMode>(this->configured_mode));
|
||||
}
|
||||
void BluetoothScannerSetModeRequest::dump_to(std::string &out) const {
|
||||
MessageDumpHelper helper(out, "BluetoothScannerSetModeRequest");
|
||||
|
@@ -24,6 +24,9 @@ void BluetoothProxy::setup() {
|
||||
this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
|
||||
|
||||
// Capture the configured scan mode from YAML before any API changes
|
||||
this->configured_scan_active_ = this->parent_->get_scan_active();
|
||||
|
||||
this->parent_->add_scanner_state_callback([this](esp32_ble_tracker::ScannerState state) {
|
||||
if (this->api_connection_ != nullptr) {
|
||||
this->send_bluetooth_scanner_state_(state);
|
||||
@@ -36,6 +39,9 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta
|
||||
resp.state = static_cast<api::enums::BluetoothScannerState>(state);
|
||||
resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
||||
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
||||
resp.configured_mode = this->configured_scan_active_
|
||||
? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
||||
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
||||
this->api_connection_->send_message(resp, api::BluetoothScannerStateResponse::MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
|
@@ -161,7 +161,8 @@ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, publ
|
||||
// Group 4: 1-byte types grouped together
|
||||
bool active_;
|
||||
uint8_t connection_count_{0};
|
||||
// 2 bytes used, 2 bytes padding
|
||||
bool configured_scan_active_{false}; // Configured scan mode from YAML
|
||||
// 3 bytes used, 1 byte padding
|
||||
};
|
||||
|
||||
extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
@@ -451,6 +451,7 @@ CONF_GRID_ROWS = "grid_rows"
|
||||
CONF_HEADER_MODE = "header_mode"
|
||||
CONF_HOME = "home"
|
||||
CONF_INITIAL_FOCUS = "initial_focus"
|
||||
CONF_SELECTED_DIGIT = "selected_digit"
|
||||
CONF_KEY_CODE = "key_code"
|
||||
CONF_KEYPADS = "keypads"
|
||||
CONF_LAYOUT = "layout"
|
||||
|
@@ -4,49 +4,112 @@ from esphome.yaml_util import parse_yaml
|
||||
|
||||
CONFIG = """
|
||||
- obj:
|
||||
radius: 0
|
||||
id: hello_world_card_
|
||||
pad_all: 12
|
||||
bg_color: 0xFFFFFF
|
||||
bg_color: white
|
||||
height: 100%
|
||||
width: 100%
|
||||
scrollable: false
|
||||
widgets:
|
||||
- spinner:
|
||||
id: hello_world_spinner_
|
||||
align: center
|
||||
indicator:
|
||||
arc_color: tomato
|
||||
height: 100
|
||||
width: 100
|
||||
spin_time: 2s
|
||||
arc_length: 60deg
|
||||
- label:
|
||||
id: hello_world_label_
|
||||
text: "Hello World!"
|
||||
- obj:
|
||||
align: top_mid
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
pad_all: 4
|
||||
scrollable: false
|
||||
height: size_content
|
||||
width: 100%
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row
|
||||
flex_align_cross: center
|
||||
flex_align_track: start
|
||||
flex_align_main: space_between
|
||||
widgets:
|
||||
- button:
|
||||
checkable: true
|
||||
radius: 4
|
||||
text_font: montserrat_20
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Clicked!"
|
||||
widgets:
|
||||
- label:
|
||||
text: "Button"
|
||||
- label:
|
||||
id: hello_world_title_
|
||||
text: ESPHome
|
||||
text_font: montserrat_20
|
||||
width: 100%
|
||||
text_align: center
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_title_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 400;
|
||||
- checkbox:
|
||||
text: Checkbox
|
||||
id: hello_world_checkbox_
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_checkbox_
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 240;
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Checked!"
|
||||
- obj:
|
||||
id: hello_world_container_
|
||||
align: center
|
||||
y: 14
|
||||
pad_all: 0
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
width: 100%
|
||||
height: size_content
|
||||
scrollable: false
|
||||
on_click:
|
||||
lvgl.spinner.update:
|
||||
id: hello_world_spinner_
|
||||
arc_color: springgreen
|
||||
- checkbox:
|
||||
pad_all: 8
|
||||
text: Checkbox
|
||||
align: top_right
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Checked!"
|
||||
- button:
|
||||
pad_all: 8
|
||||
checkable: true
|
||||
align: top_left
|
||||
text_font: montserrat_20
|
||||
on_click:
|
||||
lvgl.label.update:
|
||||
id: hello_world_label_
|
||||
text: "Clicked!"
|
||||
layout:
|
||||
type: flex
|
||||
flex_flow: row_wrap
|
||||
flex_align_cross: center
|
||||
flex_align_track: center
|
||||
flex_align_main: space_evenly
|
||||
widgets:
|
||||
- label:
|
||||
text: "Button"
|
||||
- spinner:
|
||||
id: hello_world_spinner_
|
||||
indicator:
|
||||
arc_color: tomato
|
||||
height: 100
|
||||
width: 100
|
||||
spin_time: 2s
|
||||
arc_length: 60deg
|
||||
widgets:
|
||||
- label:
|
||||
id: hello_world_label_
|
||||
text: "Hello World!"
|
||||
align: center
|
||||
- obj:
|
||||
id: hello_world_qrcode_
|
||||
outline_width: 0
|
||||
border_width: 0
|
||||
hidden: !lambda |-
|
||||
return lv_obj_get_width(lv_scr_act()) < 300 && lv_obj_get_height(lv_scr_act()) < 400;
|
||||
widgets:
|
||||
- label:
|
||||
text_font: montserrat_14
|
||||
text: esphome.io
|
||||
align: top_mid
|
||||
- qrcode:
|
||||
text: "https://esphome.io"
|
||||
size: 80
|
||||
align: bottom_mid
|
||||
on_boot:
|
||||
lvgl.widget.refresh: hello_world_qrcode_
|
||||
|
||||
- slider:
|
||||
width: 80%
|
||||
align: bottom_mid
|
||||
|
@@ -67,7 +67,6 @@ class Widget:
|
||||
self.type = wtype
|
||||
self.config = config
|
||||
self.scale = 1.0
|
||||
self.step = 1.0
|
||||
self.range_from = -sys.maxsize
|
||||
self.range_to = sys.maxsize
|
||||
if wtype.is_compound():
|
||||
|
@@ -11,6 +11,7 @@ from ..defines import (
|
||||
CONF_ROLLOVER,
|
||||
CONF_SCROLLBAR,
|
||||
CONF_SELECTED,
|
||||
CONF_SELECTED_DIGIT,
|
||||
CONF_TEXTAREA_PLACEHOLDER,
|
||||
)
|
||||
from ..lv_validation import lv_bool, lv_float
|
||||
@@ -38,18 +39,24 @@ def validate_spinbox(config):
|
||||
min_val = -1 - max_val
|
||||
range_from = int(config[CONF_RANGE_FROM])
|
||||
range_to = int(config[CONF_RANGE_TO])
|
||||
step = int(config[CONF_STEP])
|
||||
step = config[CONF_SELECTED_DIGIT]
|
||||
digits = config[CONF_DIGITS]
|
||||
if (
|
||||
range_from > max_val
|
||||
or range_from < min_val
|
||||
or range_to > max_val
|
||||
or range_to < min_val
|
||||
):
|
||||
raise cv.Invalid("Range outside allowed limits")
|
||||
if step <= 0 or step >= (range_to - range_from) / 2:
|
||||
raise cv.Invalid("Invalid step value")
|
||||
if config[CONF_DIGITS] <= config[CONF_DECIMAL_PLACES]:
|
||||
raise cv.Invalid("Number of digits must exceed number of decimal places")
|
||||
raise cv.Invalid("Range outside allowed limits", path=[CONF_RANGE_FROM])
|
||||
if digits <= config[CONF_DECIMAL_PLACES]:
|
||||
raise cv.Invalid(
|
||||
"Number of digits must exceed number of decimal places", path=[CONF_DIGITS]
|
||||
)
|
||||
if step >= digits:
|
||||
raise cv.Invalid(
|
||||
"Initial selected digit must be less than number of digits",
|
||||
path=[CONF_SELECTED_DIGIT],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
@@ -59,7 +66,10 @@ SPINBOX_SCHEMA = cv.Schema(
|
||||
cv.Optional(CONF_RANGE_FROM, default=0): cv.float_,
|
||||
cv.Optional(CONF_RANGE_TO, default=100): cv.float_,
|
||||
cv.Optional(CONF_DIGITS, default=4): cv.int_range(1, 10),
|
||||
cv.Optional(CONF_STEP, default=1.0): cv.positive_float,
|
||||
cv.Optional(CONF_STEP): cv.invalid(
|
||||
f"{CONF_STEP} has been replaced by {CONF_SELECTED_DIGIT}"
|
||||
),
|
||||
cv.Optional(CONF_SELECTED_DIGIT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_DECIMAL_PLACES, default=0): cv.int_range(0, 6),
|
||||
cv.Optional(CONF_ROLLOVER, default=False): lv_bool,
|
||||
}
|
||||
@@ -93,13 +103,12 @@ class SpinboxType(WidgetType):
|
||||
scale = 10 ** config[CONF_DECIMAL_PLACES]
|
||||
range_from = int(config[CONF_RANGE_FROM]) * scale
|
||||
range_to = int(config[CONF_RANGE_TO]) * scale
|
||||
step = int(config[CONF_STEP]) * scale
|
||||
step = config[CONF_SELECTED_DIGIT]
|
||||
w.scale = scale
|
||||
w.step = step
|
||||
w.range_to = range_to
|
||||
w.range_from = range_from
|
||||
lv.spinbox_set_range(w.obj, range_from, range_to)
|
||||
await w.set_property(CONF_STEP, step)
|
||||
await w.set_property("step", 10**step)
|
||||
await w.set_property(CONF_ROLLOVER, config)
|
||||
lv.spinbox_set_digit_format(
|
||||
w.obj, digits, digits - config[CONF_DECIMAL_PLACES]
|
||||
@@ -120,7 +129,7 @@ class SpinboxType(WidgetType):
|
||||
return config[CONF_RANGE_FROM]
|
||||
|
||||
def get_step(self, config: dict):
|
||||
return config[CONF_STEP]
|
||||
return 10 ** config[CONF_SELECTED_DIGIT]
|
||||
|
||||
|
||||
spinbox_spec = SpinboxType()
|
||||
|
@@ -10,7 +10,8 @@ from esphome.loader import get_component
|
||||
CODEOWNERS = ["@clydebarrow"]
|
||||
MULTI_CONF = True
|
||||
|
||||
map_ = cg.std_ns.class_("map")
|
||||
mapping_ns = cg.esphome_ns.namespace("mapping")
|
||||
mapping_class = mapping_ns.class_("Mapping")
|
||||
|
||||
CONF_ENTRIES = "entries"
|
||||
CONF_CLASS = "class"
|
||||
@@ -29,7 +30,11 @@ class IndexType:
|
||||
|
||||
INDEX_TYPES = {
|
||||
"int": IndexType(cv.int_, cg.int_, int),
|
||||
"string": IndexType(cv.string, cg.std_string, str),
|
||||
"string": IndexType(
|
||||
cv.string,
|
||||
cg.std_string,
|
||||
str,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +52,7 @@ def to_schema(value):
|
||||
|
||||
BASE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_ID): cv.declare_id(map_),
|
||||
cv.Required(CONF_ID): cv.declare_id(mapping_class),
|
||||
cv.Required(CONF_FROM): cv.one_of(*INDEX_TYPES, lower=True),
|
||||
cv.Required(CONF_TO): cv.string,
|
||||
},
|
||||
@@ -123,12 +128,15 @@ async def to_code(config):
|
||||
if list(entries.values())[0].op != ".":
|
||||
value_type = value_type.operator("ptr")
|
||||
varid = config[CONF_ID]
|
||||
varid.type = map_.template(index_type, value_type)
|
||||
varid.type = mapping_class.template(
|
||||
index_type,
|
||||
value_type,
|
||||
)
|
||||
var = MockObj(varid, ".")
|
||||
decl = VariableDeclarationExpression(varid.type, "", varid)
|
||||
add_global(decl)
|
||||
CORE.register_variable(varid, var)
|
||||
|
||||
for key, value in entries.items():
|
||||
cg.add(var.insert((key, value)))
|
||||
cg.add(var.set(key, value))
|
||||
return var
|
||||
|
69
esphome/components/mapping/mapping.h
Normal file
69
esphome/components/mapping/mapping.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace esphome::mapping {
|
||||
|
||||
using alloc_string_t = std::basic_string<char, std::char_traits<char>, RAMAllocator<char>>;
|
||||
|
||||
/**
|
||||
*
|
||||
* Mapping class with custom allocator.
|
||||
* Additionally, when std::string is used as key or value, it will be replaced with a custom string type
|
||||
* that uses RAMAllocator.
|
||||
* @tparam K The type of the key in the mapping.
|
||||
* @tparam V The type of the value in the mapping. Should be a basic type or pointer.
|
||||
*/
|
||||
|
||||
static const char *const TAG = "mapping";
|
||||
|
||||
template<typename K, typename V> class Mapping {
|
||||
public:
|
||||
// Constructor
|
||||
Mapping() = default;
|
||||
|
||||
using key_t = const std::conditional_t<std::is_same_v<K, std::string>,
|
||||
alloc_string_t, // if K is std::string, custom string type
|
||||
K>;
|
||||
using value_t = std::conditional_t<std::is_same_v<V, std::string>,
|
||||
alloc_string_t, // if V is std::string, custom string type
|
||||
V>;
|
||||
|
||||
void set(const K &key, const V &value) { this->map_[key_t{key}] = value; }
|
||||
|
||||
V get(const K &key) const {
|
||||
auto it = this->map_.find(key_t{key});
|
||||
if (it != this->map_.end()) {
|
||||
return V{it->second};
|
||||
}
|
||||
if constexpr (std::is_pointer_v<K>) {
|
||||
esph_log_e(TAG, "Key '%p' not found in mapping", key);
|
||||
} else if constexpr (std::is_same_v<K, std::string>) {
|
||||
esph_log_e(TAG, "Key '%s' not found in mapping", key.c_str());
|
||||
} else {
|
||||
esph_log_e(TAG, "Key '%s' not found in mapping", to_string(key).c_str());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// index map overload
|
||||
V operator[](K key) { return this->get(key); }
|
||||
|
||||
// convenience function for strings to get a C-style string
|
||||
template<typename T = V, std::enable_if_t<std::is_same_v<T, std::string>, int> = 0>
|
||||
const char *operator[](K key) const {
|
||||
auto it = this->map_.find(key_t{key});
|
||||
if (it != this->map_.end()) {
|
||||
return it->second.c_str(); // safe since value remains in map
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
protected:
|
||||
std::map<key_t, value_t, std::less<key_t>, RAMAllocator<std::pair<key_t, value_t>>> map_;
|
||||
};
|
||||
|
||||
} // namespace esphome::mapping
|
@@ -198,7 +198,7 @@ uint16_t Mcp4461Component::get_wiper_level_(Mcp4461WiperIdx wiper) {
|
||||
|
||||
uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) {
|
||||
uint8_t addr = this->get_wiper_address_(wiper_idx);
|
||||
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
|
||||
uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
|
||||
if (wiper_idx > 3) {
|
||||
if (!this->is_eeprom_ready_for_writing_(true)) {
|
||||
return 0;
|
||||
|
@@ -65,26 +65,47 @@ ACCELERATION_MODES = {
|
||||
"high": RhtAccelerationMode.HIGH_ACCELERATION,
|
||||
}
|
||||
|
||||
GAS_SENSOR = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_ALGORITHM_TUNING): cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_INDEX_OFFSET, default=100): cv.int_range(1, 250),
|
||||
cv.Optional(CONF_LEARNING_TIME_OFFSET_HOURS, default=12): cv.int_range(
|
||||
1, 1000
|
||||
),
|
||||
cv.Optional(CONF_LEARNING_TIME_GAIN_HOURS, default=12): cv.int_range(
|
||||
1, 1000
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_GATING_MAX_DURATION_MINUTES, default=720
|
||||
): cv.int_range(0, 3000),
|
||||
cv.Optional(CONF_STD_INITIAL, default=50): cv.int_,
|
||||
cv.Optional(CONF_GAIN_FACTOR, default=230): cv.int_range(1, 1000),
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
def _gas_sensor(
|
||||
*,
|
||||
index_offset: int,
|
||||
learning_time_offset: int,
|
||||
learning_time_gain: int,
|
||||
gating_max_duration: int,
|
||||
std_initial: int,
|
||||
gain_factor: int,
|
||||
) -> cv.Schema:
|
||||
return sensor.sensor_schema(
|
||||
icon=ICON_RADIATOR,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_AQI,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
).extend(
|
||||
{
|
||||
cv.Optional(CONF_ALGORITHM_TUNING): cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_INDEX_OFFSET, default=index_offset): cv.int_range(
|
||||
1, 250
|
||||
),
|
||||
cv.Optional(
|
||||
CONF_LEARNING_TIME_OFFSET_HOURS, default=learning_time_offset
|
||||
): cv.int_range(1, 1000),
|
||||
cv.Optional(
|
||||
CONF_LEARNING_TIME_GAIN_HOURS, default=learning_time_gain
|
||||
): cv.int_range(1, 1000),
|
||||
cv.Optional(
|
||||
CONF_GATING_MAX_DURATION_MINUTES, default=gating_max_duration
|
||||
): cv.int_range(0, 3000),
|
||||
cv.Optional(CONF_STD_INITIAL, default=std_initial): cv.int_range(
|
||||
10, 5000
|
||||
),
|
||||
cv.Optional(CONF_GAIN_FACTOR, default=gain_factor): cv.int_range(
|
||||
1, 1000
|
||||
),
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def float_previously_pct(value):
|
||||
@@ -127,18 +148,22 @@ CONFIG_SCHEMA = (
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
),
|
||||
cv.Optional(CONF_AUTO_CLEANING_INTERVAL): cv.update_interval,
|
||||
cv.Optional(CONF_VOC): sensor.sensor_schema(
|
||||
icon=ICON_RADIATOR,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_AQI,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
).extend(GAS_SENSOR),
|
||||
cv.Optional(CONF_NOX): sensor.sensor_schema(
|
||||
icon=ICON_RADIATOR,
|
||||
accuracy_decimals=0,
|
||||
device_class=DEVICE_CLASS_AQI,
|
||||
state_class=STATE_CLASS_MEASUREMENT,
|
||||
).extend(GAS_SENSOR),
|
||||
cv.Optional(CONF_VOC): _gas_sensor(
|
||||
index_offset=100,
|
||||
learning_time_offset=12,
|
||||
learning_time_gain=12,
|
||||
gating_max_duration=180,
|
||||
std_initial=50,
|
||||
gain_factor=230,
|
||||
),
|
||||
cv.Optional(CONF_NOX): _gas_sensor(
|
||||
index_offset=1,
|
||||
learning_time_offset=12,
|
||||
learning_time_gain=12,
|
||||
gating_max_duration=720,
|
||||
std_initial=50,
|
||||
gain_factor=230,
|
||||
),
|
||||
cv.Optional(CONF_STORE_BASELINE, default=True): cv.boolean,
|
||||
cv.Optional(CONF_VOC_BASELINE): cv.hex_uint16_t,
|
||||
cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema(
|
||||
@@ -194,16 +219,15 @@ async def to_code(config):
|
||||
await i2c.register_i2c_device(var, config)
|
||||
|
||||
for key, funcName in SETTING_MAP.items():
|
||||
if key in config:
|
||||
cg.add(getattr(var, funcName)(config[key]))
|
||||
if cfg := config.get(key):
|
||||
cg.add(getattr(var, funcName)(cfg))
|
||||
|
||||
for key, funcName in SENSOR_MAP.items():
|
||||
if key in config:
|
||||
sens = await sensor.new_sensor(config[key])
|
||||
if cfg := config.get(key):
|
||||
sens = await sensor.new_sensor(cfg)
|
||||
cg.add(getattr(var, funcName)(sens))
|
||||
|
||||
if CONF_VOC in config and CONF_ALGORITHM_TUNING in config[CONF_VOC]:
|
||||
cfg = config[CONF_VOC][CONF_ALGORITHM_TUNING]
|
||||
if cfg := config.get(CONF_VOC, {}).get(CONF_ALGORITHM_TUNING):
|
||||
cg.add(
|
||||
var.set_voc_algorithm_tuning(
|
||||
cfg[CONF_INDEX_OFFSET],
|
||||
@@ -214,8 +238,7 @@ async def to_code(config):
|
||||
cfg[CONF_GAIN_FACTOR],
|
||||
)
|
||||
)
|
||||
if CONF_NOX in config and CONF_ALGORITHM_TUNING in config[CONF_NOX]:
|
||||
cfg = config[CONF_NOX][CONF_ALGORITHM_TUNING]
|
||||
if cfg := config.get(CONF_NOX, {}).get(CONF_ALGORITHM_TUNING):
|
||||
cg.add(
|
||||
var.set_nox_algorithm_tuning(
|
||||
cfg[CONF_INDEX_OFFSET],
|
||||
@@ -225,12 +248,12 @@ async def to_code(config):
|
||||
cfg[CONF_GAIN_FACTOR],
|
||||
)
|
||||
)
|
||||
if CONF_TEMPERATURE_COMPENSATION in config:
|
||||
if cfg := config.get(CONF_TEMPERATURE_COMPENSATION):
|
||||
cg.add(
|
||||
var.set_temperature_compensation(
|
||||
config[CONF_TEMPERATURE_COMPENSATION][CONF_OFFSET],
|
||||
config[CONF_TEMPERATURE_COMPENSATION][CONF_NORMALIZED_OFFSET_SLOPE],
|
||||
config[CONF_TEMPERATURE_COMPENSATION][CONF_TIME_CONSTANT],
|
||||
cfg[CONF_OFFSET],
|
||||
cfg[CONF_NORMALIZED_OFFSET_SLOPE],
|
||||
cfg[CONF_TIME_CONSTANT],
|
||||
)
|
||||
)
|
||||
|
||||
|
@@ -11,7 +11,7 @@ pyserial==3.5
|
||||
platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile
|
||||
esptool==5.0.2
|
||||
click==8.1.7
|
||||
esphome-dashboard==20250814.0
|
||||
esphome-dashboard==20250828.0
|
||||
aioesphomeapi==39.0.0
|
||||
zeroconf==0.147.0
|
||||
puremagic==1.30
|
||||
|
@@ -1,6 +1,6 @@
|
||||
pylint==3.3.8
|
||||
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
||||
ruff==0.12.10 # also change in .pre-commit-config.yaml when updating
|
||||
ruff==0.12.11 # also change in .pre-commit-config.yaml when updating
|
||||
pyupgrade==3.20.0 # also change in .pre-commit-config.yaml when updating
|
||||
pre-commit
|
||||
|
||||
|
@@ -684,7 +684,7 @@ lvgl:
|
||||
width: 120
|
||||
range_from: -10
|
||||
range_to: 1000
|
||||
step: 5.0
|
||||
selected_digit: 2
|
||||
rollover: false
|
||||
digits: 6
|
||||
decimal_places: 2
|
||||
|
1
tests/components/mapping/.gitattributes
vendored
Normal file
1
tests/components/mapping/.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.ttf -text
|
@@ -50,6 +50,14 @@ mapping:
|
||||
red: red_id
|
||||
blue: blue_id
|
||||
green: green_id
|
||||
- id: string_map_2
|
||||
from: string
|
||||
to: string
|
||||
entries:
|
||||
one: "one"
|
||||
two: "two"
|
||||
three: "three"
|
||||
seventy-seven: "seventy-seven"
|
||||
|
||||
color:
|
||||
- id: red_id
|
||||
@@ -65,7 +73,14 @@ color:
|
||||
green: 0.0
|
||||
blue: 1.0
|
||||
|
||||
font:
|
||||
- file: "$component_dir/helvetica.ttf"
|
||||
id: font_id
|
||||
size: 20
|
||||
|
||||
display:
|
||||
lambda: |-
|
||||
it.image(0, 0, id(weather_map)[0]);
|
||||
it.image(0, 100, id(weather_map)[1]);
|
||||
std::string value = id(int_map)[2];
|
||||
it.print(0, 0, id(font_id), TextAlign::TOP_LEFT, value.c_str());
|
||||
it.image(0, 0, id(weather_map)["clear-night"]);
|
||||
it.image(0, 100, id(weather_map)["sunny"]);
|
||||
|
BIN
tests/components/mapping/helvetica.ttf
Normal file
BIN
tests/components/mapping/helvetica.ttf
Normal file
Binary file not shown.
@@ -4,14 +4,14 @@ spi:
|
||||
mosi_pin: 17
|
||||
miso_pin: 15
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 12
|
||||
dc_pin: 13
|
||||
reset_pin: 21
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
||||
display:
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 12
|
||||
dc_pin: 13
|
||||
reset_pin: 21
|
||||
invert_colors: false
|
||||
|
@@ -5,13 +5,13 @@ spi:
|
||||
miso_pin: 5
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 8
|
||||
dc_pin: 9
|
||||
reset_pin: 10
|
||||
invert_colors: false
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 8
|
||||
dc_pin: 9
|
||||
reset_pin: 10
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
@@ -5,13 +5,13 @@ spi:
|
||||
miso_pin: 5
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 8
|
||||
dc_pin: 9
|
||||
reset_pin: 10
|
||||
invert_colors: false
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 8
|
||||
dc_pin: 9
|
||||
reset_pin: 10
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
@@ -5,13 +5,13 @@ spi:
|
||||
miso_pin: 15
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 12
|
||||
dc_pin: 13
|
||||
reset_pin: 21
|
||||
invert_colors: false
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 12
|
||||
dc_pin: 13
|
||||
reset_pin: 21
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
@@ -5,13 +5,13 @@ spi:
|
||||
miso_pin: 12
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 5
|
||||
dc_pin: 15
|
||||
reset_pin: 16
|
||||
invert_colors: false
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 5
|
||||
dc_pin: 15
|
||||
reset_pin: 16
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
@@ -1,12 +1,12 @@
|
||||
display:
|
||||
- platform: sdl
|
||||
id: sdl_display
|
||||
update_interval: 1s
|
||||
auto_clear_enabled: false
|
||||
show_test_card: true
|
||||
dimensions:
|
||||
width: 450
|
||||
height: 600
|
||||
platform: sdl
|
||||
id: sdl_display
|
||||
update_interval: 1s
|
||||
auto_clear_enabled: false
|
||||
show_test_card: true
|
||||
dimensions:
|
||||
width: 450
|
||||
height: 600
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
@@ -5,13 +5,13 @@ spi:
|
||||
miso_pin: 4
|
||||
|
||||
display:
|
||||
- platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 20
|
||||
dc_pin: 21
|
||||
reset_pin: 22
|
||||
invert_colors: false
|
||||
platform: ili9xxx
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 20
|
||||
dc_pin: 21
|
||||
reset_pin: 22
|
||||
invert_colors: false
|
||||
|
||||
packages:
|
||||
map: !include common.yaml
|
||||
|
Reference in New Issue
Block a user