From 63a277ba8038856448c7be96216e4028a9699163 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 12 Nov 2023 12:20:34 -0600 Subject: [PATCH 1/9] Bump zeroconf to 0.123.0 (#5736) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 51799bc685..1d53c2761c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20231107.0 aioesphomeapi==18.4.0 -zeroconf==0.122.3 +zeroconf==0.123.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 684cf102306d7e5b5ba6d80d92796796b2cd32a8 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Sun, 12 Nov 2023 19:28:02 +0100 Subject: [PATCH 2/9] Bump Arduino Pico Framework to 3.6.0 and Platform to 1.10.0 (#5731) --- esphome/components/rp2040/__init__.py | 4 ++-- platformio.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/rp2040/__init__.py b/esphome/components/rp2040/__init__.py index 62f199b040..d027f48244 100644 --- a/esphome/components/rp2040/__init__.py +++ b/esphome/components/rp2040/__init__.py @@ -74,12 +74,12 @@ def _format_framework_arduino_version(ver: cv.Version) -> str: # The default/recommended arduino framework version # - https://github.com/earlephilhower/arduino-pico/releases # - https://api.registry.platformio.org/v3/packages/earlephilhower/tool/framework-arduinopico -RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 4, 0) +RECOMMENDED_ARDUINO_FRAMEWORK_VERSION = cv.Version(3, 6, 0) # The platformio/raspberrypi version to use for arduino frameworks # - https://github.com/platformio/platform-raspberrypi/releases # - https://api.registry.platformio.org/v3/packages/platformio/platform/raspberrypi -ARDUINO_PLATFORM_VERSION = cv.Version(1, 9, 0) +ARDUINO_PLATFORM_VERSION = cv.Version(1, 10, 0) def _arduino_check_versions(value): diff --git a/platformio.ini b/platformio.ini index 73cd7c65c8..51c9f4d0c1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -159,7 +159,7 @@ board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.4.0/rp2040-3.4.0.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.4.0/rp2040-3.6.0.zip framework = arduino lib_deps = From 45276cc24452b7ea1a7a0c6f88ed11ca38a4a1e6 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 13 Nov 2023 11:48:26 +1300 Subject: [PATCH 3/9] Handle wake word not set up internally (#5738) --- esphome/components/voice_assistant/voice_assistant.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index d15d702d4b..fc5dd6e4e4 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -610,6 +610,11 @@ void VoiceAssistant::on_event(const api::VoiceAssistantEventResponse &msg) { if (code == "wake-word-timeout" || code == "wake_word_detection_aborted") { // Don't change state here since either the "tts-end" or "run-end" events will do it. return; + } else if (code == "wake-provider-missing" || code == "wake-engine-missing") { + // Wake word is not set up or not ready on Home Assistant so stop and do not retry until user starts again. + this->request_stop(); + this->error_trigger_->trigger(code, message); + return; } ESP_LOGE(TAG, "Error: %s - %s", code.c_str(), message.c_str()); if (this->state_ != State::IDLE) { From 0a4853ba7bd0b94cbfd63a877cac6a1018766560 Mon Sep 17 00:00:00 2001 From: Jimmy Hedman Date: Mon, 13 Nov 2023 18:38:08 +0100 Subject: [PATCH 4/9] Correct url for Arduino platform (#5744) --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 51c9f4d0c1..cbd87155be 100644 --- a/platformio.ini +++ b/platformio.ini @@ -159,7 +159,7 @@ board_build.filesystem_size = 0.5m platform = https://github.com/maxgerhardt/platform-raspberrypi.git platform_packages = ; earlephilhower/framework-arduinopico@~1.20602.0 ; Cannot use the platformio package until old releases stop getting deleted - earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.4.0/rp2040-3.6.0.zip + earlephilhower/framework-arduinopico@https://github.com/earlephilhower/arduino-pico/releases/download/3.6.0/rp2040-3.6.0.zip framework = arduino lib_deps = From 00eedeb8b3a3e26370bd67493b972948f56be542 Mon Sep 17 00:00:00 2001 From: Sergey Dudanov Date: Mon, 13 Nov 2023 21:55:36 +0400 Subject: [PATCH 5/9] remote_base: added helper class and schemas (#5169) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/climate_ir/__init__.py | 51 ++++++++-------- esphome/components/climate_ir/climate_ir.h | 9 ++- esphome/components/coolix/coolix.cpp | 6 +- .../components/heatpumpir/ir_sender_esphome.h | 6 +- esphome/components/remote_base/__init__.py | 30 ++++++++-- .../components/remote_base/midea_protocol.h | 15 +---- .../remote_base/rc_switch_protocol.h | 4 +- esphome/components/remote_base/remote_base.h | 58 ++++++++++++------- tests/test1.yaml | 3 + 9 files changed, 99 insertions(+), 83 deletions(-) diff --git a/esphome/components/climate_ir/__init__.py b/esphome/components/climate_ir/__init__.py index 0cf1339971..c7c286d679 100644 --- a/esphome/components/climate_ir/__init__.py +++ b/esphome/components/climate_ir/__init__.py @@ -1,38 +1,37 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import ( - climate, - remote_transmitter, - remote_receiver, - sensor, - remote_base, -) -from esphome.components.remote_base import CONF_RECEIVER_ID, CONF_TRANSMITTER_ID +from esphome.components import climate, sensor, remote_base from esphome.const import CONF_SUPPORTS_COOL, CONF_SUPPORTS_HEAT, CONF_SENSOR +DEPENDENCIES = ["remote_transmitter"] AUTO_LOAD = ["sensor", "remote_base"] CODEOWNERS = ["@glmnet"] climate_ir_ns = cg.esphome_ns.namespace("climate_ir") ClimateIR = climate_ir_ns.class_( - "ClimateIR", climate.Climate, cg.Component, remote_base.RemoteReceiverListener + "ClimateIR", + climate.Climate, + cg.Component, + remote_base.RemoteReceiverListener, + remote_base.RemoteTransmittable, ) -CLIMATE_IR_SCHEMA = climate.CLIMATE_SCHEMA.extend( - { - cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id( - remote_transmitter.RemoteTransmitterComponent - ), - cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean, - cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, - cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor), - } -).extend(cv.COMPONENT_SCHEMA) +CLIMATE_IR_SCHEMA = ( + climate.CLIMATE_SCHEMA.extend( + { + cv.Optional(CONF_SUPPORTS_COOL, default=True): cv.boolean, + cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, + cv.Optional(CONF_SENSOR): cv.use_id(sensor.Sensor), + } + ) + .extend(cv.COMPONENT_SCHEMA) + .extend(remote_base.REMOTE_TRANSMITTABLE_SCHEMA) +) CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend( { - cv.Optional(CONF_RECEIVER_ID): cv.use_id( - remote_receiver.RemoteReceiverComponent + cv.Optional(remote_base.CONF_RECEIVER_ID): cv.use_id( + remote_base.RemoteReceiverBase ), } ) @@ -41,15 +40,11 @@ CLIMATE_IR_WITH_RECEIVER_SCHEMA = CLIMATE_IR_SCHEMA.extend( async def register_climate_ir(var, config): await cg.register_component(var, config) await climate.register_climate(var, config) - + await remote_base.register_transmittable(var, config) cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) + if remote_base.CONF_RECEIVER_ID in config: + await remote_base.register_listener(var, config) if sensor_id := config.get(CONF_SENSOR): sens = await cg.get_variable(sensor_id) cg.add(var.set_sensor(sens)) - if receiver_id := config.get(CONF_RECEIVER_ID): - receiver = await cg.get_variable(receiver_id) - cg.add(receiver.register_listener(var)) - - transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) - cg.add(var.set_transmitter(transmitter)) diff --git a/esphome/components/climate_ir/climate_ir.h b/esphome/components/climate_ir/climate_ir.h index 5be4fc06f5..ea0656121f 100644 --- a/esphome/components/climate_ir/climate_ir.h +++ b/esphome/components/climate_ir/climate_ir.h @@ -18,7 +18,10 @@ namespace climate_ir { Likewise to decode a IR into the AC state, implement bool RemoteReceiverListener::on_receive(remote_base::RemoteReceiveData data) and return true */ -class ClimateIR : public climate::Climate, public Component, public remote_base::RemoteReceiverListener { +class ClimateIR : public Component, + public climate::Climate, + public remote_base::RemoteReceiverListener, + public remote_base::RemoteTransmittable { public: ClimateIR(float minimum_temperature, float maximum_temperature, float temperature_step = 1.0f, bool supports_dry = false, bool supports_fan_only = false, std::set fan_modes = {}, @@ -35,9 +38,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base: void setup() override; void dump_config() override; - void set_transmitter(remote_transmitter::RemoteTransmitterComponent *transmitter) { - this->transmitter_ = transmitter; - } void set_supports_cool(bool supports_cool) { this->supports_cool_ = supports_cool; } void set_supports_heat(bool supports_heat) { this->supports_heat_ = supports_heat; } void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; } @@ -64,7 +64,6 @@ class ClimateIR : public climate::Climate, public Component, public remote_base: std::set swing_modes_ = {}; std::set presets_ = {}; - remote_transmitter::RemoteTransmitterComponent *transmitter_; sensor::Sensor *sensor_{nullptr}; }; diff --git a/esphome/components/coolix/coolix.cpp b/esphome/components/coolix/coolix.cpp index f4309419a4..22b3431c3e 100644 --- a/esphome/components/coolix/coolix.cpp +++ b/esphome/components/coolix/coolix.cpp @@ -102,11 +102,7 @@ void CoolixClimate::transmit_state() { } } ESP_LOGV(TAG, "Sending coolix code: 0x%06" PRIX32, remote_state); - - auto transmit = this->transmitter_->transmit(); - auto *data = transmit.get_data(); - remote_base::CoolixProtocol().encode(data, remote_state); - transmit.perform(); + this->transmit_(remote_state); } bool CoolixClimate::on_coolix(climate::Climate *parent, remote_base::RemoteReceiveData data) { diff --git a/esphome/components/heatpumpir/ir_sender_esphome.h b/esphome/components/heatpumpir/ir_sender_esphome.h index 7546d990ea..944d0e859c 100644 --- a/esphome/components/heatpumpir/ir_sender_esphome.h +++ b/esphome/components/heatpumpir/ir_sender_esphome.h @@ -3,7 +3,6 @@ #ifdef USE_ARDUINO #include "esphome/components/remote_base/remote_base.h" -#include "esphome/components/remote_transmitter/remote_transmitter.h" #include // arduino-heatpump library namespace esphome { @@ -11,14 +10,13 @@ namespace heatpumpir { class IRSenderESPHome : public IRSender { public: - IRSenderESPHome(remote_transmitter::RemoteTransmitterComponent *transmitter) - : IRSender(0), transmit_(transmitter->transmit()){}; + IRSenderESPHome(remote_base::RemoteTransmitterBase *transmitter) : IRSender(0), transmit_(transmitter->transmit()){}; void setFrequency(int frequency) override; // NOLINT(readability-identifier-naming) void space(int space_length) override; void mark(int mark_length) override; protected: - remote_transmitter::RemoteTransmitterComponent::TransmitCall transmit_; + remote_base::RemoteTransmitterBase::TransmitCall transmit_; }; } // namespace heatpumpir diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 25dedd71d8..a2411b1b12 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -52,8 +52,9 @@ RemoteReceiverTrigger = ns.class_( "RemoteReceiverTrigger", automation.Trigger, RemoteReceiverListener ) RemoteTransmitterDumper = ns.class_("RemoteTransmitterDumper") +RemoteTransmittable = ns.class_("RemoteTransmittable") RemoteTransmitterActionBase = ns.class_( - "RemoteTransmitterActionBase", automation.Action + "RemoteTransmitterActionBase", RemoteTransmittable, automation.Action ) RemoteReceiverBase = ns.class_("RemoteReceiverBase") RemoteTransmitterBase = ns.class_("RemoteTransmitterBase") @@ -68,11 +69,30 @@ def templatize(value): return cv.Schema(ret) +REMOTE_LISTENER_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_RECEIVER_ID): cv.use_id(RemoteReceiverBase), + } +) + + +REMOTE_TRANSMITTABLE_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(RemoteTransmitterBase), + } +) + + async def register_listener(var, config): receiver = await cg.get_variable(config[CONF_RECEIVER_ID]) cg.add(receiver.register_listener(var)) +async def register_transmittable(var, config): + transmitter_ = await cg.get_variable(config[CONF_TRANSMITTER_ID]) + cg.add(var.set_transmitter(transmitter_)) + + def register_binary_sensor(name, type, schema): return BINARY_SENSOR_REGISTRY.register(name, type, schema) @@ -129,10 +149,9 @@ def validate_repeat(value): BASE_REMOTE_TRANSMITTER_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_TRANSMITTER_ID): cv.use_id(RemoteTransmitterBase), cv.Optional(CONF_REPEAT): validate_repeat, } -) +).extend(REMOTE_TRANSMITTABLE_SCHEMA) def register_action(name, type_, schema): @@ -143,9 +162,8 @@ def register_action(name, type_, schema): def decorator(func): async def new_func(config, action_id, template_arg, args): - transmitter = await cg.get_variable(config[CONF_TRANSMITTER_ID]) var = cg.new_Pvariable(action_id, template_arg) - cg.add(var.set_parent(transmitter)) + await register_transmittable(var, config) if CONF_REPEAT in config: conf = config[CONF_REPEAT] template_ = await cg.templatable(conf[CONF_TIMES], args, cg.uint32) @@ -1539,7 +1557,7 @@ MIDEA_SCHEMA = cv.Schema( @register_binary_sensor("midea", MideaBinarySensor, MIDEA_SCHEMA) def midea_binary_sensor(var, config): - cg.add(var.set_code(config[CONF_CODE])) + cg.add(var.set_data(config[CONF_CODE])) @register_trigger("midea", MideaTrigger, MideaData) diff --git a/esphome/components/remote_base/midea_protocol.h b/esphome/components/remote_base/midea_protocol.h index 6925686b34..94fb6f3d94 100644 --- a/esphome/components/remote_base/midea_protocol.h +++ b/esphome/components/remote_base/midea_protocol.h @@ -67,20 +67,7 @@ class MideaProtocol : public RemoteProtocol { void dump(const MideaData &data) override; }; -class MideaBinarySensor : public RemoteReceiverBinarySensorBase { - public: - bool matches(RemoteReceiveData src) override { - auto data = MideaProtocol().decode(src); - return data.has_value() && data.value() == this->data_; - } - void set_code(const std::vector &code) { this->data_ = code; } - - protected: - MideaData data_; -}; - -using MideaTrigger = RemoteReceiverTrigger; -using MideaDumper = RemoteReceiverDumper; +DECLARE_REMOTE_PROTOCOL(Midea) template class MideaAction : public RemoteTransmitterActionBase { TEMPLATABLE_VALUE(std::vector, code) diff --git a/esphome/components/remote_base/rc_switch_protocol.h b/esphome/components/remote_base/rc_switch_protocol.h index fc465dbd5d..96cbbd1467 100644 --- a/esphome/components/remote_base/rc_switch_protocol.h +++ b/esphome/components/remote_base/rc_switch_protocol.h @@ -15,6 +15,8 @@ struct RCSwitchData { class RCSwitchBase { public: + using ProtocolData = RCSwitchData; + RCSwitchBase() = default; RCSwitchBase(uint32_t sync_high, uint32_t sync_low, uint32_t zero_high, uint32_t zero_low, uint32_t one_high, uint32_t one_low, bool inverted); @@ -213,7 +215,7 @@ class RCSwitchDumper : public RemoteReceiverDumperBase { bool dump(RemoteReceiveData src) override; }; -using RCSwitchTrigger = RemoteReceiverTrigger; +using RCSwitchTrigger = RemoteReceiverTrigger; } // namespace remote_base } // namespace esphome diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index a456007655..ebbb528a23 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -127,6 +127,14 @@ class RemoteTransmitterBase : public RemoteComponentBase { this->temp_.reset(); return TransmitCall(this); } + template + void transmit(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) { + auto call = this->transmit(); + Protocol().encode(call.get_data(), data); + call.set_send_times(send_times); + call.set_send_wait(send_wait); + call.perform(); + } protected: void send_(uint32_t send_times, uint32_t send_wait); @@ -184,12 +192,13 @@ class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitial template class RemoteProtocol { public: - virtual void encode(RemoteTransmitData *dst, const T &data) = 0; - virtual optional decode(RemoteReceiveData src) = 0; - virtual void dump(const T &data) = 0; + using ProtocolData = T; + virtual void encode(RemoteTransmitData *dst, const ProtocolData &data) = 0; + virtual optional decode(RemoteReceiveData src) = 0; + virtual void dump(const ProtocolData &data) = 0; }; -template class RemoteReceiverBinarySensor : public RemoteReceiverBinarySensorBase { +template class RemoteReceiverBinarySensor : public RemoteReceiverBinarySensorBase { public: RemoteReceiverBinarySensor() : RemoteReceiverBinarySensorBase() {} @@ -201,13 +210,14 @@ template class RemoteReceiverBinarySensor : public Remot } public: - void set_data(D data) { data_ = data; } + void set_data(typename T::ProtocolData data) { data_ = data; } protected: - D data_; + typename T::ProtocolData data_; }; -template class RemoteReceiverTrigger : public Trigger, public RemoteReceiverListener { +template +class RemoteReceiverTrigger : public Trigger, public RemoteReceiverListener { protected: bool on_receive(RemoteReceiveData src) override { auto proto = T(); @@ -220,28 +230,36 @@ template class RemoteReceiverTrigger : public Trigger } }; -template class RemoteTransmitterActionBase : public Action { +class RemoteTransmittable { public: - void set_parent(RemoteTransmitterBase *parent) { this->parent_ = parent; } + RemoteTransmittable() {} + RemoteTransmittable(RemoteTransmitterBase *transmitter) : transmitter_(transmitter) {} + void set_transmitter(RemoteTransmitterBase *transmitter) { this->transmitter_ = transmitter; } - TEMPLATABLE_VALUE(uint32_t, send_times); - TEMPLATABLE_VALUE(uint32_t, send_wait); + protected: + template + void transmit_(const typename Protocol::ProtocolData &data, uint32_t send_times = 1, uint32_t send_wait = 0) { + this->transmitter_->transmit(data, send_times, send_wait); + } + RemoteTransmitterBase *transmitter_; +}; +template class RemoteTransmitterActionBase : public RemoteTransmittable, public Action { + TEMPLATABLE_VALUE(uint32_t, send_times) + TEMPLATABLE_VALUE(uint32_t, send_wait) + + protected: void play(Ts... x) override { - auto call = this->parent_->transmit(); + auto call = this->transmitter_->transmit(); this->encode(call.get_data(), x...); call.set_send_times(this->send_times_.value_or(x..., 1)); call.set_send_wait(this->send_wait_.value_or(x..., 0)); call.perform(); } - - protected: virtual void encode(RemoteTransmitData *dst, Ts... x) = 0; - - RemoteTransmitterBase *parent_{}; }; -template class RemoteReceiverDumper : public RemoteReceiverDumperBase { +template class RemoteReceiverDumper : public RemoteReceiverDumperBase { public: bool dump(RemoteReceiveData src) override { auto proto = T(); @@ -254,9 +272,9 @@ template class RemoteReceiverDumper : public RemoteRecei }; #define DECLARE_REMOTE_PROTOCOL_(prefix) \ - using prefix##BinarySensor = RemoteReceiverBinarySensor; \ - using prefix##Trigger = RemoteReceiverTrigger; \ - using prefix##Dumper = RemoteReceiverDumper; + using prefix##BinarySensor = RemoteReceiverBinarySensor; \ + using prefix##Trigger = RemoteReceiverTrigger; \ + using prefix##Dumper = RemoteReceiverDumper; #define DECLARE_REMOTE_PROTOCOL(prefix) DECLARE_REMOTE_PROTOCOL_(prefix) } // namespace remote_base diff --git a/tests/test1.yaml b/tests/test1.yaml index 32e92440c1..61d28faf73 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -3050,6 +3050,9 @@ remote_receiver: on_coolix: then: delay: !lambda "return x.first + x.second;" + on_rc_switch: + then: + delay: !lambda "return uint32_t(x.code) + x.protocol;" status_led: pin: GPIO2 From 8c28bea5b1df8627885615e17f496e3122b182f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 16:19:15 -0600 Subject: [PATCH 6/9] Bump zeroconf from 0.123.0 to 0.126.0 (#5748) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1d53c2761c..3140d0a8a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.6.2 click==8.1.7 esphome-dashboard==20231107.0 aioesphomeapi==18.4.0 -zeroconf==0.123.0 +zeroconf==0.126.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 08fc96b890051280cd87ae099a78572c8d5f50b4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 13 Nov 2023 18:44:49 -0600 Subject: [PATCH 7/9] dashboard: remove usage of codecs module (#5741) --- esphome/dashboard/dashboard.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 5967c95aba..3de40ff402 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -2,7 +2,6 @@ from __future__ import annotations import base64 import binascii -import codecs import collections import datetime import functools @@ -339,8 +338,8 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): def handle_stdin(self, json_message): if not self.is_process_active: return - data = json_message["data"] - data = codecs.encode(data, "utf8", "replace") + text: str = json_message["data"] + data = text.encode("utf-8", "replace") _LOGGER.debug("< stdin: %s", data) self._proc.stdin.write(data) @@ -351,18 +350,18 @@ class EsphomeCommandWebSocket(tornado.websocket.WebSocketHandler): while True: try: if self._use_popen: - data = yield self._queue.get() + data: bytes = yield self._queue.get() if data is None: self._proc_on_exit(self._proc.poll()) break else: - data = yield self._proc.stdout.read_until_regex(reg) + data: bytes = yield self._proc.stdout.read_until_regex(reg) except tornado.iostream.StreamClosedError: break - data = codecs.decode(data, "utf8", "replace") - _LOGGER.debug("> stdout: %s", data) - self.write_message({"event": "line", "data": data}) + text = data.decode("utf-8", "replace") + _LOGGER.debug("> stdout: %s", text) + self.write_message({"event": "line", "data": text}) def _stdout_thread(self): if not self._use_popen: From f198be39d708114f01013d436a32bff93c18ec28 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 13 Nov 2023 18:46:51 -0600 Subject: [PATCH 8/9] dashboard: Run get_serial_ports in the executor (#5740) --- esphome/dashboard/dashboard.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/esphome/dashboard/dashboard.py b/esphome/dashboard/dashboard.py index 3de40ff402..050564d21e 100644 --- a/esphome/dashboard/dashboard.py +++ b/esphome/dashboard/dashboard.py @@ -1,5 +1,6 @@ from __future__ import annotations +import asyncio import base64 import binascii import collections @@ -508,8 +509,8 @@ class EsphomeUpdateAllHandler(EsphomeCommandWebSocket): class SerialPortRequestHandler(BaseHandler): @authenticated - def get(self): - ports = get_serial_ports() + async def get(self): + ports = await asyncio.get_running_loop().run_in_executor(None, get_serial_ports) data = [] for port in ports: desc = port.description From ae0e481cffb6ead0bb57d4b17527f39dd1b88b87 Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Mon, 13 Nov 2023 18:47:29 -0600 Subject: [PATCH 9/9] Generate partitions.csv based on flash size (#5697) --- esphome/components/esp32/__init__.py | 66 ++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index cda02f80c2..9b83d144f8 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -386,10 +386,21 @@ FRAMEWORK_SCHEMA = cv.typed_schema( ) +FLASH_SIZES = [ + "4MB", + "8MB", + "16MB", + "32MB", +] + +CONF_FLASH_SIZE = "flash_size" CONFIG_SCHEMA = cv.All( cv.Schema( { cv.Required(CONF_BOARD): cv.string_strict, + cv.Optional(CONF_FLASH_SIZE, default="4MB"): cv.one_of( + *FLASH_SIZES, upper=True + ), cv.Optional(CONF_VARIANT): cv.one_of(*VARIANTS, upper=True), cv.Optional(CONF_FRAMEWORK, default={}): FRAMEWORK_SCHEMA, } @@ -401,6 +412,7 @@ CONFIG_SCHEMA = cv.All( async def to_code(config): cg.add_platformio_option("board", config[CONF_BOARD]) + cg.add_platformio_option("board_upload.flash_size", config[CONF_FLASH_SIZE]) cg.add_build_flag("-DUSE_ESP32") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}") @@ -505,24 +517,46 @@ async def to_code(config): ) -ARDUINO_PARTITIONS_CSV = """\ -nvs, data, nvs, 0x009000, 0x005000, -otadata, data, ota, 0x00e000, 0x002000, -app0, app, ota_0, 0x010000, 0x1C0000, -app1, app, ota_1, 0x1D0000, 0x1C0000, -eeprom, data, 0x99, 0x390000, 0x001000, -spiffs, data, spiffs, 0x391000, 0x00F000 +APP_PARTITION_SIZES = { + "4MB": 0x1C0000, # 1792 KB + "8MB": 0x3C0000, # 3840 KB + "16MB": 0x7C0000, # 7936 KB + "32MB": 0xFC0000, # 16128 KB +} + + +def get_arduino_partition_csv(flash_size): + app_partition_size = APP_PARTITION_SIZES[flash_size] + eeprom_partition_size = 0x1000 # 4 KB + spiffs_partition_size = 0xF000 # 60 KB + + app0_partition_start = 0x010000 # 64 KB + app1_partition_start = app0_partition_start + app_partition_size + eeprom_partition_start = app1_partition_start + app_partition_size + spiffs_partition_start = eeprom_partition_start + eeprom_partition_size + + partition_csv = f"""\ +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xE000, 0x2000, +app0, app, ota_0, 0x{app0_partition_start:X}, 0x{app_partition_size:X}, +app1, app, ota_1, 0x{app1_partition_start:X}, 0x{app_partition_size:X}, +eeprom, data, 0x99, 0x{eeprom_partition_start:X}, 0x{eeprom_partition_size:X}, +spiffs, data, spiffs, 0x{spiffs_partition_start:X}, 0x{spiffs_partition_size:X} """ + return partition_csv -IDF_PARTITIONS_CSV = """\ -# Name, Type, SubType, Offset, Size, Flags +def get_idf_partition_csv(flash_size): + app_partition_size = APP_PARTITION_SIZES[flash_size] + + partition_csv = f"""\ otadata, data, ota, , 0x2000, phy_init, data, phy, , 0x1000, -app0, app, ota_0, , 0x1C0000, -app1, app, ota_1, , 0x1C0000, -nvs, data, nvs, , 0x6d000, +app0, app, ota_0, , 0x{app_partition_size:X}, +app1, app, ota_1, , 0x{app_partition_size:X}, +nvs, data, nvs, , 0x6D000, """ + return partition_csv def _format_sdkconfig_val(value: SdkconfigValueType) -> str: @@ -565,13 +599,17 @@ def copy_files(): if CORE.using_arduino: write_file_if_changed( CORE.relative_build_path("partitions.csv"), - ARDUINO_PARTITIONS_CSV, + get_arduino_partition_csv( + CORE.platformio_options.get("board_upload.flash_size") + ), ) if CORE.using_esp_idf: _write_sdkconfig() write_file_if_changed( CORE.relative_build_path("partitions.csv"), - IDF_PARTITIONS_CSV, + get_idf_partition_csv( + CORE.platformio_options.get("board_upload.flash_size") + ), ) # IDF build scripts look for version string to put in the build. # However, if the build path does not have an initialized git repo,