[update] Implement `update.perform action and update.is_available` condition (#7165)

* [update] Fix unimplemented yaml action/condition

* Add/update tests

---------

Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
Jesse Hills 2024-07-31 16:08:11 +12:00 committed by GitHub
parent dd3dd7a136
commit 8849443bf6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 98 additions and 19 deletions

View file

@ -138,8 +138,8 @@ void HttpRequestUpdate::update() {
this->publish_state(); this->publish_state();
} }
void HttpRequestUpdate::perform() { void HttpRequestUpdate::perform(bool force) {
if (this->state_ != update::UPDATE_STATE_AVAILABLE) { if (this->state_ != update::UPDATE_STATE_AVAILABLE && !force) {
return; return;
} }

View file

@ -15,7 +15,7 @@ class HttpRequestUpdate : public update::UpdateEntity, public PollingComponent {
void setup() override; void setup() override;
void update() override; void update() override;
void perform() override; void perform(bool force) override;
void set_source_url(const std::string &source_url) { this->source_url_ = source_url; } void set_source_url(const std::string &source_url) { this->source_url_ = source_url; }

View file

@ -1,10 +1,11 @@
from esphome import automation from esphome import automation
import esphome.codegen as cg
from esphome.components import mqtt, web_server from esphome.components import mqtt, web_server
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import ( from esphome.const import (
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
CONF_ENTITY_CATEGORY, CONF_ENTITY_CATEGORY,
CONF_FORCE_UPDATE,
CONF_ID, CONF_ID,
CONF_MQTT_ID, CONF_MQTT_ID,
CONF_WEB_SERVER_ID, CONF_WEB_SERVER_ID,
@ -23,8 +24,12 @@ UpdateEntity = update_ns.class_("UpdateEntity", cg.EntityBase)
UpdateInfo = update_ns.struct("UpdateInfo") UpdateInfo = update_ns.struct("UpdateInfo")
PerformAction = update_ns.class_("PerformAction", automation.Action) PerformAction = update_ns.class_(
IsAvailableCondition = update_ns.class_("IsAvailableCondition", automation.Condition) "PerformAction", automation.Action, cg.Parented.template(UpdateEntity)
)
IsAvailableCondition = update_ns.class_(
"IsAvailableCondition", automation.Condition, cg.Parented.template(UpdateEntity)
)
DEVICE_CLASSES = [ DEVICE_CLASSES = [
DEVICE_CLASS_EMPTY, DEVICE_CLASS_EMPTY,
@ -92,24 +97,37 @@ async def to_code(config):
cg.add_global(update_ns.using) cg.add_global(update_ns.using)
UPDATE_AUTOMATION_SCHEMA = cv.Schema( @automation.register_action(
"update.perform",
PerformAction,
automation.maybe_simple_id(
{ {
cv.GenerateID(): cv.use_id(UpdateEntity), cv.GenerateID(): cv.use_id(UpdateEntity),
cv.Optional(CONF_FORCE_UPDATE, default=False): cv.templatable(cv.boolean),
} }
),
) )
@automation.register_action("update.perform", PerformAction, UPDATE_AUTOMATION_SCHEMA)
async def update_perform_action_to_code(config, action_id, template_arg, args): async def update_perform_action_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(action_id, template_arg)
return cg.new_Pvariable(action_id, paren, paren) await cg.register_parented(var, config[CONF_ID])
force = await cg.templatable(config[CONF_FORCE_UPDATE], args, cg.bool_)
cg.add(var.set_force(force))
return var
@automation.register_condition( @automation.register_condition(
"update.is_available", IsAvailableCondition, UPDATE_AUTOMATION_SCHEMA "update.is_available",
IsAvailableCondition,
automation.maybe_simple_id(
{
cv.GenerateID(): cv.use_id(UpdateEntity),
}
),
) )
async def update_is_available_condition_to_code( async def update_is_available_condition_to_code(
config, condition_id, template_arg, args config, condition_id, template_arg, args
): ):
paren = await cg.get_variable(config[CONF_ID]) var = cg.new_Pvariable(condition_id, template_arg)
return cg.new_Pvariable(condition_id, paren, paren) await cg.register_parented(var, config[CONF_ID])
return var

View file

@ -0,0 +1,23 @@
#pragma once
#include "update_entity.h"
#include "esphome/core/automation.h"
namespace esphome {
namespace update {
template<typename... Ts> class PerformAction : public Action<Ts...>, public Parented<UpdateEntity> {
TEMPLATABLE_VALUE(bool, force)
public:
void play(Ts... x) override { this->parent_->perform(this->force_.value(x...)); }
};
template<typename... Ts> class IsAvailableCondition : public Condition<Ts...>, public Parented<UpdateEntity> {
public:
bool check(Ts... x) override { return this->parent_->state == UPDATE_STATE_AVAILABLE; }
};
} // namespace update
} // namespace esphome

View file

@ -32,7 +32,9 @@ class UpdateEntity : public EntityBase, public EntityBase_DeviceClass {
void publish_state(); void publish_state();
virtual void perform() = 0; void perform() { this->perform(false); }
virtual void perform(bool force) = 0;
const UpdateInfo &update_info = update_info_; const UpdateInfo &update_info = update_info_;
const UpdateState &state = state_; const UpdateState &state = state_;

View file

@ -1 +1,28 @@
substitutions:
verify_ssl: "true"
esphome:
on_boot:
then:
- if:
condition:
update.is_available:
then:
- logger.log: "Update available"
- update.perform:
force_update: true
wifi:
ssid: MySSID
password: password1
http_request:
verify_ssl: ${verify_ssl}
ota:
- platform: http_request
update: update:
- platform: http_request
name: Firmware Update
source: http://example.com/manifest.json

View file

@ -1 +1,4 @@
substitutions:
verify_ssl: "false"
<<: !include common.yaml <<: !include common.yaml

View file

@ -1 +1,4 @@
substitutions:
verify_ssl: "false"
<<: !include common.yaml <<: !include common.yaml

View file

@ -1 +1,4 @@
substitutions:
verify_ssl: "false"
<<: !include common.yaml <<: !include common.yaml