mirror of
https://github.com/esphome/esphome.git
synced 2026-09-15 17:18:40 +00:00
Merge remote-tracking branch 'upstream/dev' into ci/lazy-import-offenders
# Conflicts: # esphome/loader.py
This commit is contained in:
@@ -39,7 +39,7 @@ jobs:
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Generate cache-key
|
||||
id: cache-key
|
||||
run: echo key="${{ hashFiles('requirements.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
||||
run: echo key="${{ hashFiles('requirements.txt', 'requirements_dev.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
|
||||
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
|
||||
id: python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
python -m venv venv
|
||||
. venv/bin/activate
|
||||
python --version
|
||||
pip install -r requirements.txt -r requirements_test.txt pre-commit
|
||||
pip install -r requirements.txt -r requirements_dev.txt -r requirements_test.txt pre-commit
|
||||
pip install -e .
|
||||
|
||||
pylint:
|
||||
@@ -369,7 +369,7 @@ jobs:
|
||||
echo "binary=$BINARY" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Run CodSpeed benchmarks
|
||||
uses: CodSpeedHQ/action@658a901452bb54c799643e060733b7afe9121b8d # v4.14.0
|
||||
uses: CodSpeedHQ/action@c381be0bfd20e844fb45594f6aa182ffcd94545c # v4.15.0
|
||||
with:
|
||||
run: ${{ steps.build.outputs.binary }}
|
||||
mode: simulation
|
||||
|
||||
@@ -146,5 +146,6 @@ sdkconfig.*
|
||||
|
||||
/components
|
||||
/managed_components
|
||||
/dependencies.lock
|
||||
|
||||
api-docs/
|
||||
|
||||
@@ -78,43 +78,43 @@ void BME680Component::setup() {
|
||||
}
|
||||
|
||||
// Read calibration
|
||||
uint8_t cal1[25];
|
||||
if (!this->read_bytes(BME680_REGISTER_COEFF1, cal1, 25)) {
|
||||
uint8_t coeff1[25];
|
||||
if (!this->read_bytes(BME680_REGISTER_COEFF1, coeff1, 25)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
uint8_t cal2[16];
|
||||
if (!this->read_bytes(BME680_REGISTER_COEFF2, cal2, 16)) {
|
||||
uint8_t coeff2[16];
|
||||
if (!this->read_bytes(BME680_REGISTER_COEFF2, coeff2, 16)) {
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
|
||||
this->calibration_.t1 = cal2[9] << 8 | cal2[8];
|
||||
this->calibration_.t2 = cal1[2] << 8 | cal1[1];
|
||||
this->calibration_.t3 = cal1[3];
|
||||
this->calibration_.t1 = coeff2[9] << 8 | coeff2[8];
|
||||
this->calibration_.t2 = coeff1[2] << 8 | coeff1[1];
|
||||
this->calibration_.t3 = coeff1[3];
|
||||
|
||||
this->calibration_.h1 = cal2[2] << 4 | (cal2[1] & 0x0F);
|
||||
this->calibration_.h2 = cal2[0] << 4 | cal2[1] >> 4;
|
||||
this->calibration_.h3 = cal2[3];
|
||||
this->calibration_.h4 = cal2[4];
|
||||
this->calibration_.h5 = cal2[5];
|
||||
this->calibration_.h6 = cal2[6];
|
||||
this->calibration_.h7 = cal2[7];
|
||||
this->calibration_.h1 = coeff2[2] << 4 | (coeff2[1] & 0x0F);
|
||||
this->calibration_.h2 = coeff2[0] << 4 | coeff2[1] >> 4;
|
||||
this->calibration_.h3 = coeff2[3];
|
||||
this->calibration_.h4 = coeff2[4];
|
||||
this->calibration_.h5 = coeff2[5];
|
||||
this->calibration_.h6 = coeff2[6];
|
||||
this->calibration_.h7 = coeff2[7];
|
||||
|
||||
this->calibration_.p1 = cal1[6] << 8 | cal1[5];
|
||||
this->calibration_.p2 = cal1[8] << 8 | cal1[7];
|
||||
this->calibration_.p3 = cal1[9];
|
||||
this->calibration_.p4 = cal1[12] << 8 | cal1[11];
|
||||
this->calibration_.p5 = cal1[14] << 8 | cal1[13];
|
||||
this->calibration_.p6 = cal1[16];
|
||||
this->calibration_.p7 = cal1[15];
|
||||
this->calibration_.p8 = cal1[20] << 8 | cal1[19];
|
||||
this->calibration_.p9 = cal1[22] << 8 | cal1[21];
|
||||
this->calibration_.p10 = cal1[23];
|
||||
this->calibration_.p1 = coeff1[6] << 8 | coeff1[5];
|
||||
this->calibration_.p2 = coeff1[8] << 8 | coeff1[7];
|
||||
this->calibration_.p3 = coeff1[9];
|
||||
this->calibration_.p4 = coeff1[12] << 8 | coeff1[11];
|
||||
this->calibration_.p5 = coeff1[14] << 8 | coeff1[13];
|
||||
this->calibration_.p6 = coeff1[16];
|
||||
this->calibration_.p7 = coeff1[15];
|
||||
this->calibration_.p8 = coeff1[20] << 8 | coeff1[19];
|
||||
this->calibration_.p9 = coeff1[22] << 8 | coeff1[21];
|
||||
this->calibration_.p10 = coeff1[23];
|
||||
|
||||
this->calibration_.gh1 = cal2[14];
|
||||
this->calibration_.gh2 = cal2[12] << 8 | cal2[13];
|
||||
this->calibration_.gh3 = cal2[15];
|
||||
this->calibration_.gh1 = coeff2[14];
|
||||
this->calibration_.gh2 = coeff2[12] << 8 | coeff2[13];
|
||||
this->calibration_.gh3 = coeff2[15];
|
||||
|
||||
uint8_t temp_var = 0;
|
||||
if (!this->read_byte(0x02, &temp_var)) {
|
||||
|
||||
@@ -193,11 +193,14 @@ def _validate_ex1_wakeup_mode(value):
|
||||
|
||||
|
||||
def _validate_sleep_duration(value: core.TimePeriod) -> core.TimePeriod:
|
||||
if not CORE.is_bk72xx:
|
||||
return value
|
||||
max_duration = core.TimePeriod(hours=36)
|
||||
if value > max_duration:
|
||||
raise cv.Invalid("sleep duration cannot be more than 36 hours on BK72XX")
|
||||
if CORE.is_bk72xx:
|
||||
max_duration = core.TimePeriod(hours=36)
|
||||
if value > max_duration:
|
||||
raise cv.Invalid("sleep duration cannot be more than 36 hours on BK72XX")
|
||||
elif CORE.using_zephyr:
|
||||
max_duration = core.TimePeriod(days=49)
|
||||
if value > max_duration:
|
||||
raise cv.Invalid("sleep duration cannot be more than 49 days on Zephyr")
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -9,18 +9,11 @@ static const char *const TAG = "deep_sleep";
|
||||
// 5 seconds for deep sleep to ensure clean disconnect from Home Assistant
|
||||
static const uint32_t TEARDOWN_TIMEOUT_DEEP_SLEEP_MS = 5000;
|
||||
|
||||
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::atomic<DeepSleepComponent *> global_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
bool global_has_deep_sleep = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
void DeepSleepComponent::setup() {
|
||||
#ifdef USE_ZEPHYR
|
||||
k_sem_init(&this->wakeup_sem_, 0, 1);
|
||||
#endif
|
||||
global_has_deep_sleep = true;
|
||||
this->schedule_sleep_();
|
||||
// It can be used from another thread for waking up the device.
|
||||
// It should be called as last item in setup.
|
||||
global_deep_sleep.store(this);
|
||||
}
|
||||
|
||||
void DeepSleepComponent::schedule_sleep_() {
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include <atomic>
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#include <esp_sleep.h>
|
||||
#endif
|
||||
@@ -15,10 +13,6 @@
|
||||
#include "esphome/core/time.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
#include <zephyr/kernel.h>
|
||||
#endif
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome {
|
||||
@@ -125,9 +119,6 @@ class DeepSleepComponent : public Component {
|
||||
|
||||
void prevent_deep_sleep();
|
||||
void allow_deep_sleep();
|
||||
#ifdef USE_ZEPHYR
|
||||
void wakeup();
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Returns nullopt if no run duration is set. Otherwise, returns the run
|
||||
@@ -167,9 +158,6 @@ class DeepSleepComponent : public Component {
|
||||
optional<uint32_t> run_duration_;
|
||||
bool next_enter_deep_sleep_{false};
|
||||
bool prevent_{false};
|
||||
#ifdef USE_ZEPHYR
|
||||
k_sem wakeup_sem_;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bool global_has_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
@@ -256,8 +244,5 @@ template<typename... Ts> class AllowDeepSleepAction : public Action<Ts...>, publ
|
||||
void play(const Ts &...x) override { this->parent_->allow_deep_sleep(); }
|
||||
};
|
||||
|
||||
extern std::atomic<DeepSleepComponent *>
|
||||
global_deep_sleep; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
} // namespace deep_sleep
|
||||
} // namespace esphome
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#include "deep_sleep_component.h"
|
||||
#ifdef USE_ZEPHYR
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/wake.h"
|
||||
#include <zephyr/sys/poweroff.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/stats/stats.h>
|
||||
#include <zephyr/pm/pm.h>
|
||||
|
||||
namespace esphome::deep_sleep {
|
||||
|
||||
static const char *const TAG = "deep_sleep";
|
||||
|
||||
void DeepSleepComponent::wakeup() { k_sem_give(&this->wakeup_sem_); }
|
||||
|
||||
optional<uint32_t> DeepSleepComponent::get_run_duration_() const { return this->run_duration_; }
|
||||
|
||||
void DeepSleepComponent::dump_config_platform_() {}
|
||||
@@ -19,9 +15,8 @@ void DeepSleepComponent::dump_config_platform_() {}
|
||||
bool DeepSleepComponent::prepare_to_sleep_() { return true; }
|
||||
|
||||
void DeepSleepComponent::deep_sleep_() {
|
||||
k_timeout_t sleep_duration = K_FOREVER;
|
||||
if (this->sleep_duration_.has_value()) {
|
||||
sleep_duration = K_USEC(*this->sleep_duration_);
|
||||
esphome::internal::wakeable_delay(static_cast<uint32_t>(*this->sleep_duration_ / 1000));
|
||||
} else {
|
||||
#ifndef USE_ZIGBEE
|
||||
// the device can be woken up through one of the following signals:
|
||||
@@ -33,11 +28,12 @@ void DeepSleepComponent::deep_sleep_() {
|
||||
//
|
||||
// The system is reset when it wakes up from System OFF mode.
|
||||
sys_poweroff();
|
||||
#else
|
||||
esphome::internal::wakeable_delay(UINT32_MAX);
|
||||
#endif
|
||||
}
|
||||
// It might wake up immediately if k_sem_give was called again after wake up
|
||||
int ret = k_sem_take(&this->wakeup_sem_, sleep_duration);
|
||||
if (ret == 0) {
|
||||
const bool woke = esphome::wake_request_take();
|
||||
if (woke) {
|
||||
ESP_LOGD(TAG, "Woken up by another thread");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Timeout expired (normal sleep)");
|
||||
|
||||
@@ -29,7 +29,7 @@ class DemoAlarmControlPanel : public AlarmControlPanel, public Component {
|
||||
protected:
|
||||
void control(const AlarmControlPanelCall &call) override {
|
||||
auto state = call.get_state().value_or(ACP_STATE_DISARMED);
|
||||
auto code = call.get_code();
|
||||
const auto &code = call.get_code();
|
||||
switch (state) {
|
||||
case ACP_STATE_ARMED_AWAY:
|
||||
if (this->get_requires_code_to_arm()) {
|
||||
|
||||
@@ -462,7 +462,7 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
|
||||
this->request_headers_.push_back({key, value});
|
||||
}
|
||||
|
||||
void add_collect_header(const char *value) { this->lower_case_collect_headers_.push_back(value); }
|
||||
void add_collect_header(const char *value) { this->lower_case_collect_headers_.emplace_back(value); }
|
||||
|
||||
void init_json(size_t count) { this->json_.init(count); }
|
||||
void add_json(const char *key, TemplatableValue<std::string, Ts...> value) { this->json_.push_back({key, value}); }
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from operator import itemgetter
|
||||
|
||||
from esphome import config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import (
|
||||
@@ -11,6 +13,7 @@ from esphome.core import ID
|
||||
from esphome.cpp_generator import MockObj
|
||||
|
||||
from .defines import CONF_GRADIENTS, CONF_OPA, LV_DITHER, add_define, add_warning
|
||||
from .helpers import add_lv_use
|
||||
from .lv_validation import lv_color, lv_percentage, opacity
|
||||
from .lvcode import lv
|
||||
from .types import lv_color_t, lv_gradient_t, lv_opa_t
|
||||
@@ -50,6 +53,7 @@ GRADIENT_SCHEMA = cv.ensure_list(
|
||||
|
||||
|
||||
async def gradients_to_code(config):
|
||||
add_lv_use("gradient")
|
||||
max_stops = 2
|
||||
if any(CONF_DITHER in x for x in config.get(CONF_GRADIENTS, ())):
|
||||
add_warning(
|
||||
@@ -58,7 +62,7 @@ async def gradients_to_code(config):
|
||||
for gradient in config.get(CONF_GRADIENTS, ()):
|
||||
var = MockObj(cg.new_Pvariable(gradient[CONF_ID]), "->")
|
||||
idbase = gradient[CONF_ID].id
|
||||
stops = gradient[CONF_STOPS]
|
||||
stops = sorted(gradient[CONF_STOPS], key=itemgetter(CONF_POSITION))
|
||||
max_stops = max(max_stops, len(stops))
|
||||
if gradient[CONF_DIRECTION].startswith("VER"):
|
||||
lv.grad_vertical_init(var)
|
||||
|
||||
@@ -864,6 +864,32 @@ void lv_scale_draw_event_cb(lv_event_t *e, int16_t range_start, int16_t range_en
|
||||
}
|
||||
#endif // USE_LVGL_SCALE
|
||||
|
||||
#ifdef USE_LVGL_GRADIENT
|
||||
/**
|
||||
*
|
||||
* @param dsc The gradient descriptor containing the color stops
|
||||
* @param pos The current position to calculate the color for
|
||||
* @return The color for the given position
|
||||
*/
|
||||
|
||||
lv_color_t lv_grad_calculate_color(const lv_grad_dsc_t *dsc, int32_t pos) {
|
||||
if (dsc->stops_count == 0)
|
||||
return lv_color_black();
|
||||
if (dsc->stops_count == 1 || pos <= dsc->stops[0].frac)
|
||||
return dsc->stops[0].color;
|
||||
if (pos >= dsc->stops[dsc->stops_count - 1].frac)
|
||||
return dsc->stops[dsc->stops_count - 1].color;
|
||||
int i = 1;
|
||||
while (i < dsc->stops_count && dsc->stops[i].frac < pos)
|
||||
i++;
|
||||
auto *stop1 = &dsc->stops[i - 1];
|
||||
auto *stop2 = &dsc->stops[i];
|
||||
int32_t range = stop2->frac - stop1->frac;
|
||||
int32_t offset = pos - stop1->frac;
|
||||
return lv_color_mix(stop2->color, stop1->color, range == 0 ? 0 : (offset * 255) / range);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void lv_container_constructor(const lv_obj_class_t *class_p, lv_obj_t *obj) {
|
||||
LV_TRACE_OBJ_CREATE("begin");
|
||||
LV_UNUSED(class_p);
|
||||
|
||||
@@ -115,6 +115,16 @@ inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images
|
||||
int16_t lv_get_needle_angle_for_value(lv_obj_t *obj, int value);
|
||||
#endif
|
||||
|
||||
#ifdef USE_LVGL_GRADIENT
|
||||
/**
|
||||
*
|
||||
* @param dsc The gradient descriptor containing the color stops
|
||||
* @param pos The current position to calculate the color for
|
||||
* @return The color for the given position
|
||||
*/
|
||||
|
||||
lv_color_t lv_grad_calculate_color(const lv_grad_dsc_t *dsc, int32_t pos);
|
||||
#endif
|
||||
// Parent class for things that wrap an LVGL object
|
||||
class LvCompound {
|
||||
public:
|
||||
|
||||
@@ -1,18 +1,27 @@
|
||||
from collections.abc import Callable
|
||||
import difflib
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const import KEY_METADATA
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_FROM, CONF_ID, CONF_TO
|
||||
from esphome.core import CORE
|
||||
from esphome.cpp_generator import MockObj, VariableDeclarationExpression, add_global
|
||||
from esphome.core import CORE, ID
|
||||
from esphome.cpp_generator import (
|
||||
MockObj,
|
||||
MockObjClass,
|
||||
VariableDeclarationExpression,
|
||||
add_global,
|
||||
)
|
||||
from esphome.loader import get_component
|
||||
|
||||
CODEOWNERS = ["@clydebarrow"]
|
||||
MULTI_CONF = True
|
||||
DOMAIN = "mapping"
|
||||
|
||||
mapping_ns = cg.esphome_ns.namespace("mapping")
|
||||
mapping_class = mapping_ns.class_("Mapping")
|
||||
|
||||
CONF_DEFAULT_VALUE = "default_value"
|
||||
CONF_ENTRIES = "entries"
|
||||
CONF_CLASS = "class"
|
||||
|
||||
@@ -22,11 +31,18 @@ class IndexType:
|
||||
Represents a type of index in a map.
|
||||
"""
|
||||
|
||||
def __init__(self, validator, data_type, conversion):
|
||||
def __init__(
|
||||
self, validator: Callable, data_type: MockObj, conversion: Callable = None
|
||||
) -> None:
|
||||
self.validator = validator
|
||||
self.data_type = data_type
|
||||
self.conversion = conversion
|
||||
|
||||
async def convert_value(self, value):
|
||||
if self.conversion:
|
||||
return self.conversion(value)
|
||||
return await cg.get_variable(value)
|
||||
|
||||
|
||||
INDEX_TYPES = {
|
||||
"int": IndexType(cv.int_, cg.int_, int),
|
||||
@@ -38,6 +54,12 @@ INDEX_TYPES = {
|
||||
}
|
||||
|
||||
|
||||
class MappingMetaData:
|
||||
def __init__(self, from_: IndexType, to_: IndexType) -> None:
|
||||
self.from_ = from_
|
||||
self.to_ = to_
|
||||
|
||||
|
||||
def to_schema(value):
|
||||
"""
|
||||
Generate a schema for the 'to' field of a map. This can be either one of the index types or a class name.
|
||||
@@ -60,7 +82,7 @@ BASE_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
def get_object_type(to_):
|
||||
def get_object_type(to_) -> MockObjClass | None:
|
||||
"""
|
||||
Get the object type from a string. Possible formats:
|
||||
xxx The name of a component which defines INSTANCE_TYPE
|
||||
@@ -81,25 +103,60 @@ def get_object_type(to_):
|
||||
return None
|
||||
|
||||
|
||||
def get_all_mapping_metadata() -> dict[str, MappingMetaData]:
|
||||
"""Get all mapping metadata."""
|
||||
return CORE.data.setdefault(DOMAIN, {}).setdefault(KEY_METADATA, {})
|
||||
|
||||
|
||||
def get_mapping_metadata(mapping_id: str) -> MappingMetaData:
|
||||
"""Get mapping metadata by ID for use by other components."""
|
||||
return get_all_mapping_metadata()[mapping_id]
|
||||
|
||||
|
||||
def add_metadata(
|
||||
mapping_id: ID,
|
||||
from_: IndexType,
|
||||
to_: IndexType,
|
||||
) -> None:
|
||||
get_all_mapping_metadata()[mapping_id.id] = MappingMetaData(from_, to_)
|
||||
|
||||
|
||||
def map_schema(config):
|
||||
config = BASE_SCHEMA(config)
|
||||
if CONF_ENTRIES not in config or not isinstance(config[CONF_ENTRIES], dict):
|
||||
raise cv.Invalid("an entries list is required for a map")
|
||||
raise cv.Invalid("an entries dictionary is required for a mapping")
|
||||
entries = config[CONF_ENTRIES]
|
||||
if len(entries) == 0:
|
||||
raise cv.Invalid("Map must have at least one entry")
|
||||
raise cv.Invalid("A mapping must have at least one entry")
|
||||
to_ = config[CONF_TO]
|
||||
if to_ in INDEX_TYPES:
|
||||
value_type = INDEX_TYPES[to_].validator
|
||||
value_type = INDEX_TYPES[to_]
|
||||
else:
|
||||
value_type = get_object_type(to_)
|
||||
if value_type is None:
|
||||
object_type = get_object_type(to_)
|
||||
if object_type is None:
|
||||
matches = difflib.get_close_matches(to_, CORE.id_classes)
|
||||
raise cv.Invalid(
|
||||
f"No known mappable class name matches '{to_}'; did you mean one of {', '.join(matches)}?"
|
||||
)
|
||||
value_type = cv.use_id(value_type)
|
||||
config[CONF_ENTRIES] = {k: value_type(v) for k, v in entries.items()}
|
||||
validator = cv.use_id(object_type)
|
||||
value_type = IndexType(validator, object_type)
|
||||
config[CONF_ENTRIES] = {k: value_type.validator(v) for k, v in entries.items()}
|
||||
if (default_value := config.get(CONF_DEFAULT_VALUE)) is not None:
|
||||
config[CONF_DEFAULT_VALUE] = value_type.validator(default_value)
|
||||
unexpected_keys = config.keys() - {
|
||||
CONF_ENTRIES,
|
||||
CONF_TO,
|
||||
CONF_FROM,
|
||||
CONF_ID,
|
||||
CONF_DEFAULT_VALUE,
|
||||
}
|
||||
if unexpected_keys:
|
||||
errors = [
|
||||
cv.Invalid(f"Unexpected key '{k}'", path=[k]) for k in unexpected_keys
|
||||
]
|
||||
raise cv.MultipleInvalid(errors)
|
||||
|
||||
add_metadata(config[CONF_ID], INDEX_TYPES[config[CONF_FROM]], value_type)
|
||||
return config
|
||||
|
||||
|
||||
@@ -107,29 +164,19 @@ CONFIG_SCHEMA = map_schema
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
entries = config[CONF_ENTRIES]
|
||||
from_ = config[CONF_FROM]
|
||||
to_ = config[CONF_TO]
|
||||
index_conversion = INDEX_TYPES[from_].conversion
|
||||
index_type = INDEX_TYPES[from_].data_type
|
||||
if to_ in INDEX_TYPES:
|
||||
value_conversion = INDEX_TYPES[to_].conversion
|
||||
value_type = INDEX_TYPES[to_].data_type
|
||||
entries = {
|
||||
index_conversion(key): value_conversion(value)
|
||||
for key, value in entries.items()
|
||||
}
|
||||
else:
|
||||
entries = {
|
||||
index_conversion(key): await cg.get_variable(value)
|
||||
for key, value in entries.items()
|
||||
}
|
||||
value_type = get_object_type(to_)
|
||||
if list(entries.values())[0].op != ".":
|
||||
value_type = value_type.operator("ptr")
|
||||
varid = config[CONF_ID]
|
||||
metadata = get_mapping_metadata(varid.id)
|
||||
entries = {
|
||||
metadata.from_.conversion(key): await metadata.to_.convert_value(value)
|
||||
for key, value in config[CONF_ENTRIES].items()
|
||||
}
|
||||
value_type = metadata.to_.data_type
|
||||
# entries guaranteed to be non-empty here.
|
||||
value_0 = list(entries.values())[0]
|
||||
if isinstance(value_0, MockObj) and value_0.op != ".":
|
||||
value_type = value_type.operator("ptr")
|
||||
varid.type = mapping_class.template(
|
||||
index_type,
|
||||
metadata.from_.data_type,
|
||||
value_type,
|
||||
)
|
||||
var = MockObj(varid, ".")
|
||||
@@ -139,4 +186,6 @@ async def to_code(config):
|
||||
|
||||
for key, value in entries.items():
|
||||
cg.add(var.set(key, value))
|
||||
if (default_value := config.get(CONF_DEFAULT_VALUE)) is not None:
|
||||
cg.add(var.set_default_value(await metadata.to_.convert_value(default_value)))
|
||||
return var
|
||||
|
||||
@@ -40,6 +40,9 @@ template<typename K, typename V> class Mapping {
|
||||
if (it != this->map_.end()) {
|
||||
return V{it->second};
|
||||
}
|
||||
if (this->default_value_.has_value()) {
|
||||
return this->default_value_.value();
|
||||
}
|
||||
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>) {
|
||||
@@ -69,11 +72,17 @@ template<typename K, typename V> class Mapping {
|
||||
if (it != this->map_.end()) {
|
||||
return it->second.c_str(); // safe since value remains in map
|
||||
}
|
||||
if (this->default_value_.has_value()) {
|
||||
return this->default_value_.value();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void set_default_value(const V &default_value) { this->default_value_ = default_value; }
|
||||
|
||||
protected:
|
||||
std::map<key_t, value_t, std::less<key_t>, RAMAllocator<std::pair<key_t, value_t>>> map_;
|
||||
std::optional<V> default_value_{};
|
||||
};
|
||||
|
||||
} // namespace esphome::mapping
|
||||
|
||||
@@ -141,6 +141,22 @@ CONF_UICR_ERASE = "uicr_erase"
|
||||
VOLTAGE_LEVELS = [1.8, 2.1, 2.4, 2.7, 3.0, 3.3]
|
||||
|
||||
|
||||
_DFU_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DeviceFirmwareUpdate),
|
||||
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _dfu_schema(value: bool | ConfigType) -> ConfigType:
|
||||
if isinstance(value, bool):
|
||||
if not value:
|
||||
raise cv.Invalid("Use 'dfu: true' or specify a configuration dict")
|
||||
return _DFU_SCHEMA({})
|
||||
return _DFU_SCHEMA(value)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
_detect_bootloader,
|
||||
set_core_data,
|
||||
@@ -150,12 +166,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.string_strict, cv.ByteLength(max=BOARD_MAX_LENGTH)
|
||||
),
|
||||
cv.Optional(KEY_BOOTLOADER): cv.one_of(*BOOTLOADERS, lower=True),
|
||||
cv.Optional(CONF_DFU): cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(DeviceFirmwareUpdate),
|
||||
cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema,
|
||||
}
|
||||
),
|
||||
cv.Optional(CONF_DFU): _dfu_schema,
|
||||
cv.Optional(CONF_DCDC, default=True): cv.boolean,
|
||||
cv.Optional(CONF_REG0): cv.Schema(
|
||||
{
|
||||
@@ -321,8 +332,9 @@ async def to_code(config: ConfigType) -> None:
|
||||
async def _dfu_to_code(dfu_config):
|
||||
cg.add_define("USE_NRF52_DFU")
|
||||
var = cg.new_Pvariable(dfu_config[CONF_ID])
|
||||
pin = await cg.gpio_pin_expression(dfu_config[CONF_RESET_PIN])
|
||||
cg.add(var.set_reset_pin(pin))
|
||||
if CONF_RESET_PIN in dfu_config:
|
||||
pin = await cg.gpio_pin_expression(dfu_config[CONF_RESET_PIN])
|
||||
cg.add(var.set_reset_pin(pin))
|
||||
zephyr_add_prj_conf("CDC_ACM_DTE_RATE_CALLBACK_SUPPORT", True)
|
||||
await cg.register_component(var, dfu_config)
|
||||
|
||||
|
||||
@@ -2,24 +2,34 @@
|
||||
|
||||
#ifdef USE_NRF52_DFU
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/components/zephyr/cdc_acm.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace nrf52 {
|
||||
#include <hal/nrf_power.h>
|
||||
|
||||
namespace esphome::nrf52 {
|
||||
|
||||
static const char *const TAG = "dfu";
|
||||
|
||||
static const uint32_t DFU_DBL_RESET_MAGIC = 0x5A1AD5; // SALADS
|
||||
static const uint8_t DFU_MAGIC_UF2_RESET = 0x57; // Adafruit nRF52 bootloader UF2 magic
|
||||
|
||||
void DeviceFirmwareUpdate::setup() {
|
||||
this->reset_pin_->setup();
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->setup();
|
||||
}
|
||||
#if defined(CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT)
|
||||
zephyr::global_cdc_acm->add_on_rate_callback([this](const device *, uint32_t rate) {
|
||||
if (rate == 1200) {
|
||||
volatile uint32_t *dbl_reset_mem = (volatile uint32_t *) 0x20007F7C;
|
||||
(*dbl_reset_mem) = DFU_DBL_RESET_MAGIC;
|
||||
this->reset_pin_->digital_write(true);
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->digital_write(true);
|
||||
} else {
|
||||
NRF_POWER->GPREGRET = DFU_MAGIC_UF2_RESET;
|
||||
App.reboot();
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif
|
||||
@@ -27,10 +37,13 @@ void DeviceFirmwareUpdate::setup() {
|
||||
|
||||
void DeviceFirmwareUpdate::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "DFU:");
|
||||
LOG_PIN(" RESET Pin: ", this->reset_pin_);
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
LOG_PIN(" RESET Pin: ", this->reset_pin_);
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG, " Method: GPREGRET");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nrf52
|
||||
} // namespace esphome
|
||||
} // namespace esphome::nrf52
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/gpio.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace nrf52 {
|
||||
namespace esphome::nrf52 {
|
||||
class DeviceFirmwareUpdate : public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
@@ -14,10 +13,9 @@ class DeviceFirmwareUpdate : public Component {
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
GPIOPin *reset_pin_;
|
||||
GPIOPin *reset_pin_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace nrf52
|
||||
} // namespace esphome
|
||||
} // namespace esphome::nrf52
|
||||
|
||||
#endif
|
||||
|
||||
@@ -433,13 +433,17 @@ void Pipsolar::handle_qpigs_(const char *message) {
|
||||
}
|
||||
|
||||
void Pipsolar::handle_qmod_(const char *message) {
|
||||
std::string mode;
|
||||
char device_mode = char(message[1]);
|
||||
if (this->last_qmod_) {
|
||||
this->last_qmod_->publish_state(message);
|
||||
}
|
||||
// QMOD response is "(M" where M is the device-mode character. Bail out if the
|
||||
// message is shorter than 2 chars (e.g. empty error response from
|
||||
// handle_poll_error_) — reading message[1] would otherwise be out of bounds.
|
||||
if (message[0] == '\0' || message[1] == '\0')
|
||||
return;
|
||||
if (this->device_mode_) {
|
||||
mode = device_mode;
|
||||
std::string mode;
|
||||
mode = char(message[1]);
|
||||
this->device_mode_->publish_state(mode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +451,7 @@ class SPIDevice : public SPIClient {
|
||||
|
||||
uint8_t read_byte() { return this->delegate_->transfer(0); }
|
||||
|
||||
void read_array(uint8_t *data, size_t length) { return this->delegate_->read_array(data, length); }
|
||||
void read_array(uint8_t *data, size_t length) { this->delegate_->read_array(data, length); }
|
||||
|
||||
/**
|
||||
* Write a single data item, up to 32 bits.
|
||||
|
||||
@@ -68,13 +68,8 @@ void TLC5971::transfer_(uint8_t send) {
|
||||
uint8_t startbit = 0x80;
|
||||
|
||||
bool towrite, lastmosi = !(send & startbit);
|
||||
uint8_t bitdelay_us = (1000000 / 1000000) / 2;
|
||||
|
||||
for (uint8_t b = startbit; b != 0; b = b >> 1) {
|
||||
if (bitdelay_us) {
|
||||
delayMicroseconds(bitdelay_us);
|
||||
}
|
||||
|
||||
towrite = send & b;
|
||||
if ((lastmosi != towrite)) {
|
||||
this->data_pin_->digital_write(towrite);
|
||||
@@ -82,11 +77,6 @@ void TLC5971::transfer_(uint8_t send) {
|
||||
}
|
||||
|
||||
this->clock_pin_->digital_write(true);
|
||||
|
||||
if (bitdelay_us) {
|
||||
delayMicroseconds(bitdelay_us);
|
||||
}
|
||||
|
||||
this->clock_pin_->digital_write(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#ifdef USE_ESP32
|
||||
#include <soc/soc_caps.h>
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#endif
|
||||
@@ -40,7 +39,7 @@ void WatchdogManager::set_timeout_(uint32_t timeout_ms) {
|
||||
#ifdef USE_ESP32
|
||||
esp_task_wdt_config_t wdt_config = {
|
||||
.timeout_ms = timeout_ms,
|
||||
.idle_core_mask = (1 << SOC_CPU_CORES_NUM) - 1,
|
||||
.idle_core_mask = (1U << CONFIG_FREERTOS_NUMBER_OF_CORES) - 1U,
|
||||
.trigger_panic = true,
|
||||
};
|
||||
esp_task_wdt_reconfigure(&wdt_config);
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/storage/flash_map.h>
|
||||
#include "esphome/core/hal.h"
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
#include "esphome/components/deep_sleep/deep_sleep_component.h"
|
||||
#endif
|
||||
#include "esphome/core/wake.h"
|
||||
|
||||
extern "C" {
|
||||
#include <zboss_api.h>
|
||||
@@ -119,11 +117,7 @@ void ZigbeeComponent::zcl_device_cb(zb_bufid_t bufid) {
|
||||
/* Set default response value. */
|
||||
p_device_cb_param->status = RET_OK;
|
||||
|
||||
#ifdef USE_DEEP_SLEEP
|
||||
if (auto *ds = deep_sleep::global_deep_sleep.load()) {
|
||||
ds->wakeup();
|
||||
}
|
||||
#endif
|
||||
esphome::wake_loop_threadsafe();
|
||||
|
||||
// endpoints are enumerated from 1
|
||||
if (global_zigbee->callbacks_.size() >= endpoint) {
|
||||
|
||||
@@ -370,6 +370,9 @@ class Application {
|
||||
#elif defined(USE_ESP8266)
|
||||
/// Wake from ISR (ESP8266). No task_woken arg — no FreeRTOS. Caller must be IRAM_ATTR.
|
||||
static void IRAM_ATTR ESPHOME_ALWAYS_INLINE wake_loop_isrsafe() { esphome::wake_loop_isrsafe(); }
|
||||
#elif defined(USE_ZEPHYR)
|
||||
/// Wake from ISR (Zephyr). No task_woken arg — k_sem_give() handles ISR scheduling internally.
|
||||
static void wake_loop_isrsafe() { esphome::wake_loop_isrsafe(); }
|
||||
#endif
|
||||
|
||||
/// Wake from any context (ISR, thread, callback).
|
||||
|
||||
@@ -812,7 +812,7 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
||||
"wake/wake_host.cpp": {
|
||||
PlatformFramework.HOST_NATIVE,
|
||||
},
|
||||
"wake/wake_generic.cpp": {
|
||||
"wake/wake_zephyr.cpp": {
|
||||
PlatformFramework.NRF52_ZEPHYR,
|
||||
},
|
||||
# Note: lock_free_queue.h and event_pool.h are header files and don't need to be filtered
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#define USE_LVGL_CHECKBOX
|
||||
#define USE_LVGL_DROPDOWN
|
||||
#define USE_LVGL_FONT
|
||||
#define USE_LVGL_GRADIENT
|
||||
#define USE_LVGL_IMAGE
|
||||
#define USE_LVGL_IMAGEBUTTON
|
||||
#define USE_LVGL_KEY_LISTENER
|
||||
|
||||
+3
-1
@@ -69,6 +69,8 @@ __attribute__((always_inline)) inline bool wake_request_take() {
|
||||
#include "esphome/core/wake/wake_rp2040.h"
|
||||
#elif defined(USE_HOST)
|
||||
#include "esphome/core/wake/wake_host.h"
|
||||
#elif defined(USE_ZEPHYR)
|
||||
#include "esphome/core/wake/wake_zephyr.h"
|
||||
#else
|
||||
#include "esphome/core/wake/wake_generic.h"
|
||||
#error "wake.h: wake_loop_threadsafe() is not implemented for this platform"
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,10 @@ inline void ESPHOME_ALWAYS_INLINE wakeable_delay(uint32_t ms) {
|
||||
}
|
||||
if (g_main_loop_woke) {
|
||||
g_main_loop_woke = false;
|
||||
// Yield even on the already-woken fast path so callers in tight loops
|
||||
// (e.g. lwIP raw TCP wait_for_data_) make forward progress when ISRs
|
||||
// keep re-setting g_main_loop_woke between iterations.
|
||||
delay(0);
|
||||
return;
|
||||
}
|
||||
esp_delay(ms, []() { return !g_main_loop_woke; });
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#if !defined(USE_ESP32) && !defined(USE_LIBRETINY) && !defined(USE_ESP8266) && !defined(USE_RP2040) && \
|
||||
!defined(USE_HOST)
|
||||
|
||||
#include "esphome/core/wake.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// === Wake-requested flag storage ===
|
||||
// Fallback platforms (currently only Zephyr/NRF52) are ESPHOME_THREAD_SINGLE.
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
volatile uint8_t g_wake_requested = 0;
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // fallback guard
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#if !defined(USE_ESP32) && !defined(USE_LIBRETINY) && !defined(USE_ESP8266) && !defined(USE_RP2040) && \
|
||||
!defined(USE_HOST)
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
/// Zephyr is currently the only platform without a wake mechanism.
|
||||
/// wake_loop_threadsafe() is a no-op and wakeable_delay() falls back to delay().
|
||||
/// TODO: implement proper Zephyr wake using k_poll / k_sem or similar.
|
||||
inline void wake_loop_threadsafe() {}
|
||||
|
||||
inline void wake_loop_any_context() { wake_loop_threadsafe(); }
|
||||
|
||||
namespace internal {
|
||||
inline void ESPHOME_ALWAYS_INLINE wakeable_delay(uint32_t ms) {
|
||||
if (ms == 0) [[unlikely]] {
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
delay(ms);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // fallback guard
|
||||
@@ -36,6 +36,10 @@ void wakeable_delay(uint32_t ms) {
|
||||
}
|
||||
if (g_main_loop_woke) {
|
||||
g_main_loop_woke = false;
|
||||
// Yield even on the already-woken fast path so callers in tight loops
|
||||
// (e.g. lwIP raw TCP wait_for_data_) make forward progress when async
|
||||
// wakes keep re-setting g_main_loop_woke between iterations.
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
s_delay_expired = false;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/wake.h"
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
K_SEM_DEFINE(esphome_wake_sem, 0, 1);
|
||||
|
||||
// === Wake-requested flag storage ===
|
||||
// Zephyr has preemptive threads and ISRs, so wake_loop_threadsafe() is genuinely
|
||||
// called cross-context. volatile uint8_t is sufficient because: (1) Cortex-M
|
||||
// 8-bit aligned store/load is a single non-tearing instruction, and (2) every
|
||||
// producer pairs the store with k_sem_give() (release barrier) and the consumer
|
||||
// pairs the load with k_sem_take() (acquire barrier).
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
volatile uint8_t g_wake_requested = 0;
|
||||
|
||||
void wake_loop_threadsafe() {
|
||||
wake_request_set();
|
||||
k_sem_give(&esphome_wake_sem);
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
void wakeable_delay(uint32_t ms) {
|
||||
if (ms == 0) [[unlikely]] {
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
k_sem_take(&esphome_wake_sem, ms == UINT32_MAX ? K_FOREVER : K_MSEC(ms));
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ZEPHYR
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_ZEPHYR
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
/// Zephyr: wakes the main loop via k_sem_give(). Thread- and ISR-safe.
|
||||
/// Defined in wake_zephyr.cpp.
|
||||
void wake_loop_threadsafe();
|
||||
|
||||
inline void wake_loop_any_context() { wake_loop_threadsafe(); }
|
||||
|
||||
/// ISR-safe: no task_woken arg because Zephyr's k_sem_give() does its own ISR
|
||||
/// scheduling. Forwards to wake_loop_threadsafe().
|
||||
inline void wake_loop_isrsafe() { wake_loop_threadsafe(); }
|
||||
|
||||
namespace internal {
|
||||
/// Zephyr wakeable_delay uses k_sem_take() with a timeout — defined in wake_zephyr.cpp.
|
||||
void wakeable_delay(uint32_t ms);
|
||||
} // namespace internal
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ZEPHYR
|
||||
+8
-2
@@ -9,16 +9,22 @@ import logging
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from esphome.const import SOURCE_FILE_EXTENSIONS
|
||||
from esphome.core import CORE
|
||||
from esphome.types import ConfigType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
|
||||
# `esphome.core.config` is imported lazily in `_lookup_module` when the
|
||||
# "esphome" pseudo-component is first resolved. It pulls in
|
||||
# `esphome.automation` and `esphome.config_validation`, which together
|
||||
# dominate `esphome.__main__` startup cost when loaded eagerly.
|
||||
# `esphome.cpp_generator` is similarly avoided at module scope; it pulls
|
||||
# in `esphome.yaml_util` and is only needed for the `MockObjClass` type
|
||||
# annotation, which is resolved lazily via `TYPE_CHECKING`.
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -97,7 +103,7 @@ class ComponentManifest:
|
||||
return getattr(self.module, "CODEOWNERS", [])
|
||||
|
||||
@property
|
||||
def instance_type(self) -> list[str]:
|
||||
def instance_type(self) -> "MockObjClass | None":
|
||||
return getattr(self.module, "INSTANCE_TYPE", None)
|
||||
|
||||
@property
|
||||
|
||||
@@ -21,6 +21,7 @@ mapping:
|
||||
entries:
|
||||
clear-night: image_1
|
||||
sunny: image_2
|
||||
default_value: image_1
|
||||
- id: weather_map_2
|
||||
from: string
|
||||
to: image
|
||||
@@ -35,6 +36,7 @@ mapping:
|
||||
2: "two"
|
||||
3: "three"
|
||||
77: "seventy-seven"
|
||||
default_value: unknown
|
||||
- id: string_map
|
||||
from: string
|
||||
to: int
|
||||
|
||||
@@ -4,7 +4,7 @@ packages:
|
||||
|
||||
display:
|
||||
spi_id: spi_bus
|
||||
platform: ili9xxx
|
||||
platform: mipi_spi
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 12
|
||||
|
||||
@@ -4,7 +4,7 @@ packages:
|
||||
|
||||
display:
|
||||
spi_id: spi_bus
|
||||
platform: ili9xxx
|
||||
platform: mipi_spi
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
cs_pin: 5
|
||||
|
||||
@@ -4,7 +4,7 @@ packages:
|
||||
|
||||
display:
|
||||
spi_id: spi_bus
|
||||
platform: ili9xxx
|
||||
platform: mipi_spi
|
||||
id: main_lcd
|
||||
model: ili9342
|
||||
data_rate: 31.25MHz
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
nrf52:
|
||||
dfu:
|
||||
reset_pin:
|
||||
number: 14
|
||||
inverted: true
|
||||
mode:
|
||||
output: true
|
||||
reg0:
|
||||
voltage: 1.8V
|
||||
@@ -1,9 +1,4 @@
|
||||
nrf52:
|
||||
dfu:
|
||||
reset_pin:
|
||||
number: 14
|
||||
inverted: true
|
||||
mode:
|
||||
output: true
|
||||
dfu: true
|
||||
reg0:
|
||||
voltage: 1.8V
|
||||
|
||||
Reference in New Issue
Block a user