Merge branch 'dev' into platform

This commit is contained in:
tomaszduda23 2024-11-07 20:02:16 +01:00 committed by GitHub
commit b3af6d8b71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 125 additions and 33 deletions

View file

@ -70,8 +70,6 @@ def _validate_time_present(config):
_DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( _DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
web_server.WEBSERVER_SORTING_SCHEMA,
cv.MQTT_COMMAND_COMPONENT_SCHEMA,
cv.Schema( cv.Schema(
{ {
cv.Optional(CONF_ON_VALUE): automation.validate_automation( cv.Optional(CONF_ON_VALUE): automation.validate_automation(
@ -81,7 +79,9 @@ _DATETIME_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
), ),
cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock), cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock),
} }
), )
.extend(web_server.WEBSERVER_SORTING_SCHEMA)
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
).add_extra(_validate_time_present) ).add_extra(_validate_time_present)

View file

@ -391,7 +391,9 @@ def container_validator(schema, widget_type: WidgetType):
add_lv_use(ltype) add_lv_use(ltype)
if value == SCHEMA_EXTRACT: if value == SCHEMA_EXTRACT:
return result return result
result = result.extend(LAYOUT_SCHEMAS[ltype.lower()]) result = result.extend(
LAYOUT_SCHEMAS.get(ltype.lower(), LAYOUT_SCHEMAS[df.TYPE_NONE])
)
return result(value) return result(value)
return validator return validator

View file

@ -60,9 +60,10 @@ class AnimimgType(WidgetType):
lvgl_components_required.add(CONF_IMAGE) lvgl_components_required.add(CONF_IMAGE)
lvgl_components_required.add(CONF_ANIMIMG) lvgl_components_required.add(CONF_ANIMIMG)
if CONF_SRC in config: if CONF_SRC in config:
for x in config[CONF_SRC]: srcs = [
await cg.get_variable(x) await lv_image.process(await cg.get_variable(x))
srcs = [await lv_image.process(x) for x in config[CONF_SRC]] for x in config[CONF_SRC]
]
src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs) src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs)
count = len(config[CONF_SRC]) count = len(config[CONF_SRC])
lv.animimg_set_src(w.obj, src_id, count) lv.animimg_set_src(w.obj, src_id, count)

View file

@ -1,3 +1,4 @@
import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ANGLE, CONF_MODE from esphome.const import CONF_ANGLE, CONF_MODE
@ -64,6 +65,7 @@ class ImgType(WidgetType):
async def to_code(self, w: Widget, config): async def to_code(self, w: Widget, config):
if src := config.get(CONF_SRC): if src := config.get(CONF_SRC):
src = await cg.get_variable(src)
lv.img_set_src(w.obj, await lv_image.process(src)) lv.img_set_src(w.obj, await lv_image.process(src))
if (cf_angle := config.get(CONF_ANGLE)) is not None: if (cf_angle := config.get(CONF_ANGLE)) is not None:
pivot_x = config[CONF_PIVOT_X] pivot_x = config[CONF_PIVOT_X]

View file

@ -22,6 +22,7 @@ from esphome.const import (
CONF_DISCOVERY_PREFIX, CONF_DISCOVERY_PREFIX,
CONF_DISCOVERY_RETAIN, CONF_DISCOVERY_RETAIN,
CONF_DISCOVERY_UNIQUE_ID_GENERATOR, CONF_DISCOVERY_UNIQUE_ID_GENERATOR,
CONF_ENABLE_ON_BOOT,
CONF_ID, CONF_ID,
CONF_KEEPALIVE, CONF_KEEPALIVE,
CONF_LEVEL, CONF_LEVEL,
@ -99,6 +100,8 @@ MQTTMessage = mqtt_ns.struct("MQTTMessage")
MQTTClientComponent = mqtt_ns.class_("MQTTClientComponent", cg.Component) MQTTClientComponent = mqtt_ns.class_("MQTTClientComponent", cg.Component)
MQTTPublishAction = mqtt_ns.class_("MQTTPublishAction", automation.Action) MQTTPublishAction = mqtt_ns.class_("MQTTPublishAction", automation.Action)
MQTTPublishJsonAction = mqtt_ns.class_("MQTTPublishJsonAction", automation.Action) MQTTPublishJsonAction = mqtt_ns.class_("MQTTPublishJsonAction", automation.Action)
MQTTEnableAction = mqtt_ns.class_("MQTTEnableAction", automation.Action)
MQTTDisableAction = mqtt_ns.class_("MQTTDisableAction", automation.Action)
MQTTMessageTrigger = mqtt_ns.class_( MQTTMessageTrigger = mqtt_ns.class_(
"MQTTMessageTrigger", automation.Trigger.template(cg.std_string), cg.Component "MQTTMessageTrigger", automation.Trigger.template(cg.std_string), cg.Component
) )
@ -208,6 +211,7 @@ CONFIG_SCHEMA = cv.All(
{ {
cv.GenerateID(): cv.declare_id(MQTTClientComponent), cv.GenerateID(): cv.declare_id(MQTTClientComponent),
cv.Required(CONF_BROKER): cv.string_strict, cv.Required(CONF_BROKER): cv.string_strict,
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
cv.Optional(CONF_PORT, default=1883): cv.port, cv.Optional(CONF_PORT, default=1883): cv.port,
cv.Optional(CONF_USERNAME, default=""): cv.string, cv.Optional(CONF_USERNAME, default=""): cv.string,
cv.Optional(CONF_PASSWORD, default=""): cv.string, cv.Optional(CONF_PASSWORD, default=""): cv.string,
@ -325,6 +329,7 @@ async def to_code(config):
cg.add_global(mqtt_ns.using) cg.add_global(mqtt_ns.using)
cg.add(var.set_broker_address(config[CONF_BROKER])) cg.add(var.set_broker_address(config[CONF_BROKER]))
cg.add(var.set_enable_on_boot(config[CONF_ENABLE_ON_BOOT]))
cg.add(var.set_broker_port(config[CONF_PORT])) cg.add(var.set_broker_port(config[CONF_PORT]))
cg.add(var.set_username(config[CONF_USERNAME])) cg.add(var.set_username(config[CONF_USERNAME]))
cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_password(config[CONF_PASSWORD]))
@ -555,3 +560,31 @@ async def register_mqtt_component(var, config):
async def mqtt_connected_to_code(config, condition_id, template_arg, args): async def mqtt_connected_to_code(config, condition_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID]) paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren) return cg.new_Pvariable(condition_id, template_arg, paren)
@automation.register_action(
"mqtt.enable",
MQTTEnableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(MQTTClientComponent),
}
),
)
async def mqtt_enable_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@automation.register_action(
"mqtt.disable",
MQTTDisableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(MQTTClientComponent),
}
),
)
async def mqtt_disable_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)

View file

@ -50,6 +50,8 @@ void MQTTClientComponent::setup() {
} }
}); });
this->mqtt_backend_.set_on_disconnect([this](MQTTClientDisconnectReason reason) { this->mqtt_backend_.set_on_disconnect([this](MQTTClientDisconnectReason reason) {
if (this->state_ == MQTT_CLIENT_DISABLED)
return;
this->state_ = MQTT_CLIENT_DISCONNECTED; this->state_ = MQTT_CLIENT_DISCONNECTED;
this->disconnect_reason_ = reason; this->disconnect_reason_ = reason;
}); });
@ -77,8 +79,9 @@ void MQTTClientComponent::setup() {
topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2); topic, [this](const std::string &topic, const std::string &payload) { this->send_device_info_(); }, 2);
} }
this->last_connected_ = millis(); if (this->enable_on_boot_) {
this->start_dnslookup_(); this->enable();
}
} }
void MQTTClientComponent::send_device_info_() { void MQTTClientComponent::send_device_info_() {
@ -163,7 +166,9 @@ void MQTTClientComponent::dump_config() {
ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str()); ESP_LOGCONFIG(TAG, " Availability: '%s'", this->availability_.topic.c_str());
} }
} }
bool MQTTClientComponent::can_proceed() { return network::is_disabled() || this->is_connected(); } bool MQTTClientComponent::can_proceed() {
return network::is_disabled() || this->state_ == MQTT_CLIENT_DISABLED || this->is_connected();
}
void MQTTClientComponent::start_dnslookup_() { void MQTTClientComponent::start_dnslookup_() {
for (auto &subscription : this->subscriptions_) { for (auto &subscription : this->subscriptions_) {
@ -339,6 +344,8 @@ void MQTTClientComponent::loop() {
const uint32_t now = millis(); const uint32_t now = millis();
switch (this->state_) { switch (this->state_) {
case MQTT_CLIENT_DISABLED:
return; // Return to avoid a reboot when disabled
case MQTT_CLIENT_DISCONNECTED: case MQTT_CLIENT_DISCONNECTED:
if (now - this->connect_begin_ > 5000) { if (now - this->connect_begin_ > 5000) {
this->start_dnslookup_(); this->start_dnslookup_();
@ -501,6 +508,23 @@ bool MQTTClientComponent::publish_json(const std::string &topic, const json::jso
return this->publish(topic, message, qos, retain); return this->publish(topic, message, qos, retain);
} }
void MQTTClientComponent::enable() {
if (this->state_ != MQTT_CLIENT_DISABLED)
return;
ESP_LOGD(TAG, "Enabling MQTT...");
this->state_ = MQTT_CLIENT_DISCONNECTED;
this->last_connected_ = millis();
this->start_dnslookup_();
}
void MQTTClientComponent::disable() {
if (this->state_ == MQTT_CLIENT_DISABLED)
return;
ESP_LOGD(TAG, "Disabling MQTT...");
this->state_ = MQTT_CLIENT_DISABLED;
this->on_shutdown();
}
/** Check if the message topic matches the given subscription topic /** Check if the message topic matches the given subscription topic
* *
* INFO: MQTT spec mandates that topics must not be empty and must be valid NULL-terminated UTF-8 strings. * INFO: MQTT spec mandates that topics must not be empty and must be valid NULL-terminated UTF-8 strings.

View file

@ -87,7 +87,8 @@ struct MQTTDiscoveryInfo {
}; };
enum MQTTClientState { enum MQTTClientState {
MQTT_CLIENT_DISCONNECTED = 0, MQTT_CLIENT_DISABLED = 0,
MQTT_CLIENT_DISCONNECTED,
MQTT_CLIENT_RESOLVING_ADDRESS, MQTT_CLIENT_RESOLVING_ADDRESS,
MQTT_CLIENT_CONNECTING, MQTT_CLIENT_CONNECTING,
MQTT_CLIENT_CONNECTED, MQTT_CLIENT_CONNECTED,
@ -247,6 +248,9 @@ class MQTTClientComponent : public Component {
void register_mqtt_component(MQTTComponent *component); void register_mqtt_component(MQTTComponent *component);
bool is_connected(); bool is_connected();
void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
void enable();
void disable();
void on_shutdown() override; void on_shutdown() override;
@ -314,10 +318,11 @@ class MQTTClientComponent : public Component {
MQTTBackendLibreTiny mqtt_backend_; MQTTBackendLibreTiny mqtt_backend_;
#endif #endif
MQTTClientState state_{MQTT_CLIENT_DISCONNECTED}; MQTTClientState state_{MQTT_CLIENT_DISABLED};
network::IPAddress ip_; network::IPAddress ip_;
bool dns_resolved_{false}; bool dns_resolved_{false};
bool dns_resolve_error_{false}; bool dns_resolve_error_{false};
bool enable_on_boot_{true};
std::vector<MQTTComponent *> children_; std::vector<MQTTComponent *> children_;
uint32_t reboot_timeout_{300000}; uint32_t reboot_timeout_{300000};
uint32_t connect_begin_; uint32_t connect_begin_;
@ -414,6 +419,26 @@ template<typename... Ts> class MQTTConnectedCondition : public Condition<Ts...>
MQTTClientComponent *parent_; MQTTClientComponent *parent_;
}; };
template<typename... Ts> class MQTTEnableAction : public Action<Ts...> {
public:
MQTTEnableAction(MQTTClientComponent *parent) : parent_(parent) {}
void play(Ts... x) override { this->parent_->enable(); }
protected:
MQTTClientComponent *parent_;
};
template<typename... Ts> class MQTTDisableAction : public Action<Ts...> {
public:
MQTTDisableAction(MQTTClientComponent *parent) : parent_(parent) {}
void play(Ts... x) override { this->parent_->disable(); }
protected:
MQTTClientComponent *parent_;
};
} // namespace mqtt } // namespace mqtt
} // namespace esphome } // namespace esphome

View file

@ -66,6 +66,10 @@ SPI_MODE_OPTIONS = {
1: SPIMode.MODE1, 1: SPIMode.MODE1,
2: SPIMode.MODE2, 2: SPIMode.MODE2,
3: SPIMode.MODE3, 3: SPIMode.MODE3,
"0": SPIMode.MODE0,
"1": SPIMode.MODE1,
"2": SPIMode.MODE2,
"3": SPIMode.MODE3,
} }
CONF_SPI_MODE = "spi_mode" CONF_SPI_MODE = "spi_mode"

View file

@ -1,6 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import spi from esphome.components import spi
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_MODE from esphome.const import CONF_ID, CONF_MODE
DEPENDENCIES = ["spi"] DEPENDENCIES = ["spi"]
@ -11,18 +11,6 @@ spi_device_ns = cg.esphome_ns.namespace("spi_device")
spi_device = spi_device_ns.class_("SPIDeviceComponent", cg.Component, spi.SPIDevice) spi_device = spi_device_ns.class_("SPIDeviceComponent", cg.Component, spi.SPIDevice)
Mode = spi.spi_ns.enum("SPIMode")
MODES = {
"0": Mode.MODE0,
"1": Mode.MODE1,
"2": Mode.MODE2,
"3": Mode.MODE3,
"MODE0": Mode.MODE0,
"MODE1": Mode.MODE1,
"MODE2": Mode.MODE2,
"MODE3": Mode.MODE3,
}
BitOrder = spi.spi_ns.enum("SPIBitOrder") BitOrder = spi.spi_ns.enum("SPIBitOrder")
ORDERS = { ORDERS = {
"msb_first": BitOrder.BIT_ORDER_MSB_FIRST, "msb_first": BitOrder.BIT_ORDER_MSB_FIRST,
@ -34,7 +22,9 @@ CONFIG_SCHEMA = cv.Schema(
{ {
cv.GenerateID(CONF_ID): cv.declare_id(spi_device), cv.GenerateID(CONF_ID): cv.declare_id(spi_device),
cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True), cv.Optional(CONF_BIT_ORDER, default="msb_first"): cv.enum(ORDERS, lower=True),
cv.Optional(CONF_MODE, default="0"): cv.enum(MODES, upper=True), cv.Optional(CONF_MODE): cv.invalid(
"The 'mode' option has been renamed to 'spi_mode'."
),
} }
).extend(spi.spi_device_schema(False, "1MHz")) ).extend(spi.spi_device_schema(False, "1MHz"))
@ -42,6 +32,5 @@ CONFIG_SCHEMA = cv.Schema(
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
cg.add(var.set_mode(config[CONF_MODE]))
cg.add(var.set_bit_order(config[CONF_BIT_ORDER])) cg.add(var.set_bit_order(config[CONF_BIT_ORDER]))
await spi.register_spi_device(var, config) await spi.register_spi_device(var, config)

View file

@ -10,6 +10,7 @@ mqtt:
port: 1883 port: 1883
username: debug username: debug
password: debug password: debug
enable_on_boot: false
clean_session: True clean_session: True
client_id: someclient client_id: someclient
use_abbreviations: false use_abbreviations: false
@ -87,6 +88,8 @@ button:
state_topic: some/topic/button state_topic: some/topic/button
qos: 2 qos: 2
on_press: on_press:
- mqtt.disable
- mqtt.enable
- mqtt.publish: - mqtt.publish:
topic: some/topic/button topic: some/topic/button
payload: Hello payload: Hello
@ -230,6 +233,7 @@ datetime:
id: test_date id: test_date
type: date type: date
state_topic: some/topic/date state_topic: some/topic/date
command_topic: test_date/custom_command_topic
qos: 2 qos: 2
subscribe_qos: 2 subscribe_qos: 2
set_action: set_action:

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -7,5 +7,5 @@ spi:
spi_device: spi_device:
id: spi_device_test id: spi_device_test
data_rate: 2MHz data_rate: 2MHz
mode: 3 spi_mode: 3
bit_order: lsb_first bit_order: lsb_first

View file

@ -35,3 +35,11 @@ switch:
web_server: web_server:
sorting_group_id: sorting_group_2 sorting_group_id: sorting_group_2
sorting_weight: -10 sorting_weight: -10
datetime:
- platform: template
name: Pick a Date
type: datetime
optimistic: yes
web_server:
sorting_group_id: sorting_group_3
sorting_weight: -5