Browse Source

Added visual feedback during OTA upgrades.

pull/36/head
Maurice Makaay 3 years ago
parent
commit
00d3803f5a
4 changed files with 173 additions and 0 deletions
  1. +6
    -0
      CHANGELOG.md
  2. +70
    -0
      components/ota_triggers/__init__.py
  3. +56
    -0
      components/ota_triggers/automation.h
  4. +41
    -0
      example.yaml

+ 6
- 0
CHANGELOG.md View File

@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Made the codebase compatible with ESPHome v1.x.0
([PR #1657: Introduce new async-def coroutine syntax](https://github.com/esphome/esphome/pull/1657))
### Added
- Implemented support for visual feedback during the OTA flashing process in the
`example.yaml` file: the light becomes blue during the process, the brightness bar
represents the update progress, when updating fails the light flashes red and when it
completes successfuly, the light flashes green.
## [1.0.0]
**Note**: This release requires ESPHome v1.18.0 or newer.


+ 70
- 0
components/ota_triggers/__init__.py View File

@ -0,0 +1,70 @@
from esphome.cpp_generator import RawExpression
from esphome import automation
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components.ota import ota_ns, OTAComponent
from esphome.const import (
CONF_ID,
)
CODEOWNERS = ["@mmakaay"]
DEPENDENCIES = ["ota"]
CONF_ON_BEGIN = "on_begin"
CONF_ON_PROGRESS = "on_progress"
CONF_ON_END = "on_end"
CONF_ON_ERROR = "on_error"
CONF_ON_BEGIN_TRIGGER_ID = "on_begin_trigger_id"
CONF_ON_PROGRESS_TRIGGER_ID = "on_progress_trigger_id"
CONF_ON_END_TRIGGER_ID = "on_end_trigger_id"
CONF_ON_ERROR_TRIGGER_ID = "on_error_trigger_id"
OTAStartTrigger = ota_ns.class_("OTAStartTrigger", automation.Trigger.template())
OTAProgressTrigger = ota_ns.class_("OTAProgressTrigger", automation.Trigger.template())
OTAEndTrigger = ota_ns.class_("OTAEndTrigger", automation.Trigger.template())
OTAErrorTrigger = ota_ns.class_("OTAErrorTrigger", automation.Trigger.template())
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(OTAComponent),
cv.Optional(CONF_ON_BEGIN): automation.validate_automation(
{
cv.GenerateID(CONF_ON_BEGIN_TRIGGER_ID): cv.declare_id(OTAStartTrigger),
}
),
cv.Optional(CONF_ON_ERROR): automation.validate_automation(
{
cv.GenerateID(CONF_ON_ERROR_TRIGGER_ID): cv.declare_id(OTAErrorTrigger),
}
),
cv.Optional(CONF_ON_PROGRESS): automation.validate_automation(
{
cv.GenerateID(CONF_ON_PROGRESS_TRIGGER_ID): cv.declare_id(
OTAProgressTrigger
),
}
),
cv.Optional(CONF_ON_END): automation.validate_automation(
{
cv.GenerateID(CONF_ON_END_TRIGGER_ID): cv.declare_id(OTAEndTrigger),
}
),
}
).extend(cv.COMPONENT_SCHEMA)
async def to_code(config):
var = await cg.get_variable(config[CONF_ID])
for conf in config.get(CONF_ON_BEGIN, []):
trigger = cg.new_Pvariable(conf[CONF_ON_BEGIN_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_PROGRESS, []):
trigger = cg.new_Pvariable(conf[CONF_ON_PROGRESS_TRIGGER_ID], var)
await automation.build_automation(trigger, [(float, "x")], conf)
for conf in config.get(CONF_ON_END, []):
trigger = cg.new_Pvariable(conf[CONF_ON_END_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
for conf in config.get(CONF_ON_ERROR, []):
trigger = cg.new_Pvariable(conf[CONF_ON_ERROR_TRIGGER_ID], var)
await automation.build_automation(trigger, [(int, "x")], conf)

+ 56
- 0
components/ota_triggers/automation.h View File

@ -0,0 +1,56 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "esphome/components/ota/ota_component.h"
namespace esphome {
namespace ota {
class OTAStartTrigger : public Trigger<> {
public:
explicit OTAStartTrigger(OTAComponent *parent) {
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
if (state == OTAState::Started && !parent->is_failed()) {
trigger();
}
});
}
};
class OTAProgressTrigger : public Trigger<float> {
public:
explicit OTAProgressTrigger(OTAComponent *parent) {
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
if (state == OTAState::InProgress && !parent->is_failed()) {
trigger(progress);
}
});
}
};
class OTAEndTrigger : public Trigger<> {
public:
explicit OTAEndTrigger(OTAComponent *parent) {
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
if (state == OTAState::Completed && !parent->is_failed()) {
trigger();
}
});
}
};
class OTAErrorTrigger : public Trigger<int> {
public:
explicit OTAErrorTrigger(OTAComponent *parent) {
parent->add_on_state_callback([this, parent](OTAState state, float progress, uint8_t error) {
if (state == OTAState::Error && !parent->is_failed()) {
trigger(error);
}
});
}
};
} // namespace ota
} // namespace esphome

+ 41
- 0
example.yaml View File

@ -200,3 +200,44 @@ sensor:
id: ${id_light}
brightness: !lambda return x;
# These OTA triggers are used to provide some visual feedback during the OTA
# flashing process. The light is turned blue when the upgrade starts, the
# brightness indicator will represent the update progress (fills up from 0%
# to 100%), the light will flash red when the upgrade fails or green when the
# upgrade succeeds.
# You can safely remove this section if you don't want the visual feedback.
ota_triggers:
on_begin:
then:
- light.disco_on:
id: ${id_light}
red: 0%
green: 0%
blue: 100%
brightness: 2%
transition_length: 0s
on_progress:
then:
- output.set_level:
id: ${id_front_panel_illumination}
level: !lambda return (x / 100.0f);
on_end:
then:
- light.disco_on:
id: ${id_light}
red: 0%
green: 100%
blue: 0%
brightness: 2%
transition_length: 0s
on_error:
then:
- light.disco_on:
id: ${id_light}
red: 100%
green: 0%
blue: 0%
brightness: 2%
- delay: 1s
- light.disco_off:
id: ${id_light}

Loading…
Cancel
Save