Browse Source

Visualize OTA progress (#41)

* Added OTA progress to the example.yaml.
* Updated the changelog for the ota progress support in the example.yaml.
* Implemented front_panel.set_level action for easier control of the slider LEDs.
pull/44/head
Maurice Makaay 3 years ago
committed by GitHub
parent
commit
cd74e367dc
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 134 additions and 30 deletions
  1. +7
    -2
      CHANGELOG.md
  2. +21
    -22
      components/xiaomi_bslamp2/front_panel_hal.h
  3. +30
    -5
      components/xiaomi_bslamp2/output/__init__.py
  4. +15
    -0
      components/xiaomi_bslamp2/output/automation.h
  5. +10
    -1
      components/xiaomi_bslamp2/output/output.h
  6. +11
    -0
      doc/configuration.md
  7. +40
    -0
      example.yaml

+ 7
- 2
CHANGELOG.md View File

@ -6,7 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.1.0]
**Note**: This release requires ESPHome v1.19.0 or newer.
**Note**: This release requires ESPHome v1.20.0 or newer.
### Added
- It is now possible to address the LEDs in the front panel of the device individually.
@ -14,7 +14,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
used by the original firmware to represent the lamp's current brightness setting.
The `output` component for the lamp was updated to provide access to the individual LEDs.
Check out the [documentation guide](https://github.com/mmakaay/esphome-xiaomi_bslamp2/blob/main/doc/configuration.md)
for details on how to control the individual LEDs.
for details on how to control these.
Thanks to @Stewie3112 for the feature request that triggered this development!
- Implemented support for visual feedback during the OTA update process in the
`example.yaml` file: the light becomes blue during flahsing, the brightness slider
represents the progress, on failure the light flashes red and on success the
light flashes green.
### Changed
- Made it possible to use lambdas with the `preset.activate` automation. This makes it


+ 21
- 22
components/xiaomi_bslamp2/front_panel_hal.h View File

@ -22,20 +22,21 @@ using EVENT = uint16_t;
// LED_1 is the slider LED closest to the power button.
// LED_10 is the one closest to the color button.
enum FrontPanelLEDs {
LED_ALL = 16384 + 4096 + 1023,
LED_POWER = 16384,
LED_COLOR = 4096,
LED_1 = 512,
LED_2 = 256,
LED_3 = 128,
LED_4 = 64,
LED_5 = 32,
LED_6 = 16,
LED_7 = 8,
LED_8 = 4,
LED_9 = 2,
LED_10 = 1,
LED_NONE = 0,
LED_ALL = 16384 + 4096 + 1023,
LED_ALL_SLIDER = 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1,
LED_POWER = 16384,
LED_COLOR = 4096,
LED_1 = 512,
LED_2 = 256,
LED_3 = 128,
LED_4 = 64,
LED_5 = 32,
LED_6 = 16,
LED_7 = 8,
LED_8 = 4,
LED_9 = 2,
LED_10 = 1,
LED_NONE = 0,
};
// This I2C command is used during front panel event handling.
@ -272,20 +273,18 @@ class FrontPanelHAL : public Component, public i2c::I2CDevice {
}
/**
* Sets the front panel illumination to the provided level (0.0 - 1.0).
* Sets the front panel slider illumination to the provided level,
* based on a float input (0.0 - 1.0).
*
* This implements the behavior of the original firmware for representing
* the lamp's brightness.
*
* Level 0.0 means: turn off the front panel illumination.
* The other levels are translated to one of the available levels,
* represented by the level indicator (i.e. the illumination of the
* slider bar.) The power and color button are also turned on.
* Level 0.0 means: turn off the slider illumination.
* The other levels are translated to one of the available levels.
*/
void set_light_level(float level) {
turn_off_leds(LED_ALL);
void set_slider_level(float level) {
turn_off_leds(LED_ALL_SLIDER);
if (level == 0.00f) return;
turn_on_leds(LED_POWER | LED_COLOR | LED_1);
if (level >= 0.15f) turn_on_leds(LED_2);
if (level >= 0.25f) turn_on_leds(LED_3);
if (level >= 0.35f) turn_on_leds(LED_4);


+ 30
- 5
components/xiaomi_bslamp2/output/__init__.py View File

@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import output
from esphome.const import CONF_ID
from esphome.const import CONF_ID, CONF_LEVEL
from esphome import automation
from .. import (
bslamp2_ns, CODEOWNERS,
@ -14,6 +14,7 @@ AUTO_LOAD = ["xiaomi_bslamp2"]
XiaomiBslamp2FrontPanelOutput = bslamp2_ns.class_(
"XiaomiBslamp2FrontPanelOutput", output.FloatOutput, cg.Component)
SetLEDsAction = bslamp2_ns.class_("SetLEDsAction", automation.Action)
SetLevelAction = bslamp2_ns.class_("SetLevelAction", automation.Action)
UpdateLEDsAction = bslamp2_ns.class_("UpdateLEDsAction", automation.Action)
CONFIG_SCHEMA = output.FLOAT_OUTPUT_SCHEMA.extend(
@ -31,6 +32,13 @@ def to_code(config):
front_panel_hal_var = yield cg.get_variable(config[CONF_FRONT_PANEL_HAL_ID])
cg.add(var.set_parent(front_panel_hal_var))
def maybe_simple_level_value(schema):
def validator(value):
if isinstance(value, dict):
return schema(value)
return schema({ "level": value })
return validator
def maybe_simple_leds_value(schema):
def validator(value):
if isinstance(value, dict):
@ -42,13 +50,30 @@ FRONT_PANEL_SCHEMA = cv.Schema({
cv.GenerateID(CONF_ID): cv.use_id(XiaomiBslamp2FrontPanelOutput),
})
FRONT_PANEL_LEVEL_SCHEMA = cv.Schema(
maybe_simple_level_value(FRONT_PANEL_SCHEMA.extend(
{
cv.Required(CONF_LEVEL): cv.templatable(cv.percentage),
}
))
)
FRONT_PANEL_LED_SCHEMA = cv.Schema(
maybe_simple_leds_value(cv.Schema({
cv.GenerateID(CONF_ID): cv.use_id(XiaomiBslamp2FrontPanelOutput),
cv.Required(CONF_LEDS): cv.ensure_list(cv.enum(FRONT_PANEL_LED_OPTIONS, upper=True)),
}))
maybe_simple_leds_value(FRONT_PANEL_SCHEMA.extend(
{
cv.Required(CONF_LEDS): cv.ensure_list(cv.enum(FRONT_PANEL_LED_OPTIONS, upper=True)),
}
))
)
@automation.register_action("front_panel.set_level", SetLevelAction, FRONT_PANEL_LEVEL_SCHEMA)
async def set_level_to_code(config, action_id, template_arg, args):
output_var = await cg.get_variable(config[CONF_ID])
action_var = cg.new_Pvariable(action_id, template_arg, output_var)
template_ = await cg.templatable(config[CONF_LEVEL], args, float)
cg.add(action_var.set_level(template_))
return action_var
@automation.register_action("front_panel.set_leds", SetLEDsAction, FRONT_PANEL_LED_SCHEMA)
async def set_leds_to_code(config, action_id, template_arg, args):
output_var = await cg.get_variable(config[CONF_ID])


+ 15
- 0
components/xiaomi_bslamp2/output/automation.h View File

@ -37,6 +37,21 @@ template<typename... Ts> class SetLEDsAction : public Action<Ts...> {
XiaomiBslamp2FrontPanelOutput *parent_;
};
template<typename... Ts> class SetLevelAction : public Action<Ts...> {
public:
explicit SetLevelAction(XiaomiBslamp2FrontPanelOutput *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(float, level)
void play(Ts... x) override {
parent_->set_level(this->level_.value(x...));
parent_->update_leds();
}
protected:
XiaomiBslamp2FrontPanelOutput *parent_;
};
template<typename... Ts> class UpdateLEDsAction : public Action<Ts...> {
public:
explicit UpdateLEDsAction(XiaomiBslamp2FrontPanelOutput *parent) : parent_(parent) {}


+ 10
- 1
components/xiaomi_bslamp2/output/output.h View File

@ -20,7 +20,16 @@ class XiaomiBslamp2FrontPanelOutput : public output::FloatOutput, public Compone
}
void write_state(float level) {
front_panel_->set_light_level(level);
if (level > 0) {
turn_on_leds(LED_POWER | LED_COLOR);
set_level(level);
} else {
turn_off_leds(LED_ALL);
}
}
void set_level(float level) {
front_panel_->set_slider_level(level);
}
void set_leds(uint16_t leds) {


+ 11
- 0
doc/configuration.md View File

@ -435,6 +435,17 @@ The LEDs to affect are specified in the same wat as above for `front_panel.set_l
This action turns off the provided LEDs, and leaves the rest of the LEDs as-is.
The LEDs to affect are specified in the same wat as above for `front_panel.set_leds`.
#### `front_panel.set_level` Action
This action works like the `output.set_level` action, but it only updates the
LEDs of the slider. The LEDs for the power and color button are left as-is.
```yaml
on_...:
then:
- front_panel.set_leds: 0.5
```
#### `front_panel.update_leds` Action
The previous actions only modify the required state for the front panel LEDs.


+ 40
- 0
example.yaml View File

@ -58,6 +58,46 @@ api:
ota:
password: "Password-For-Flashing-This-Device-Over-The-Air"
# 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 these if you don't want the visual feedback.
on_begin:
then:
- light.disco_on:
id: ${id_light}
red: 0%
green: 0%
blue: 100%
brightness: 2%
transition_length: 0s
on_progress:
then:
- front_panel.set_level: !lambda return (x / 100.0f);
- front_panel.update_leds:
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}
# The log level can be raised when needed for debugging the firmware. For
# production, a low log level is recommended. Mainly because high volume log
# output might interfere with the API/WiFi connection stability. So when


Loading…
Cancel
Save