Browse Source

Validate preset names and group names at compile time (fixes #15) (#47)

* Validate preset names and group names at compile time (fixes #15)

* Small fix for using a less confusing var name.

Co-authored-by: Maurice Makaay <mmakaay1@xs4all.net>
release/2021.8.0
Maurice Makaay 3 years ago
committed by GitHub
parent
commit
69b495a046
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 50 additions and 26 deletions
  1. +50
    -26
      components/xiaomi_bslamp2/light/__init__.py

+ 50
- 26
components/xiaomi_bslamp2/light/__init__.py View File

@ -2,7 +2,7 @@ import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.components import light from esphome.components import light
from esphome import automation from esphome import automation
from esphome.core import coroutine
from esphome.core import coroutine, Lambda
from esphome.const import ( from esphome.const import (
CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, CONF_COLOR_TEMPERATURE, CONF_RED, CONF_GREEN, CONF_BLUE, CONF_WHITE, CONF_COLOR_TEMPERATURE,
CONF_STATE, CONF_OUTPUT_ID, CONF_TRIGGER_ID, CONF_ID, CONF_STATE, CONF_OUTPUT_ID, CONF_TRIGGER_ID, CONF_ID,
@ -39,10 +39,10 @@ PRESETS_SCHEMA = cv.Schema({
}) })
}) })
def validate_preset(conf):
has_rgb = CONF_RED in conf or CONF_GREEN in conf or CONF_BLUE in conf
has_white = CONF_COLOR_TEMPERATURE in conf
has_effect = CONF_EFFECT in conf
def validate_preset(config):
has_rgb = CONF_RED in config or CONF_GREEN in config or CONF_BLUE in config
has_white = CONF_COLOR_TEMPERATURE in config
has_effect = CONF_EFFECT in config
# Check mutual exclusivity of preset options. # Check mutual exclusivity of preset options.
if (has_rgb + has_white + has_effect) > 1: if (has_rgb + has_white + has_effect) > 1:
@ -50,19 +50,19 @@ def validate_preset(conf):
# Check the color temperature value range. # Check the color temperature value range.
if has_white: if has_white:
if conf[CONF_COLOR_TEMPERATURE] < MIRED_MIN or conf[CONF_COLOR_TEMPERATURE] > MIRED_MAX:
if config[CONF_COLOR_TEMPERATURE] < MIRED_MIN or config[CONF_COLOR_TEMPERATURE] > MIRED_MAX:
raise cv.Invalid(f"The color temperature must be in the range {MIRED_MIN} - {MIRED_MAX}") raise cv.Invalid(f"The color temperature must be in the range {MIRED_MIN} - {MIRED_MAX}")
# When defining an RGB color, it is allowed to omit RGB components that have value 0. # When defining an RGB color, it is allowed to omit RGB components that have value 0.
if has_rgb: if has_rgb:
if CONF_RED not in conf:
conf[CONF_RED] = 0
if CONF_GREEN not in conf:
conf[CONF_GREEN] = 0
if CONF_BLUE not in conf:
conf[CONF_BLUE] = 0
if CONF_RED not in config:
config[CONF_RED] = 0
if CONF_GREEN not in config:
config[CONF_GREEN] = 0
if CONF_BLUE not in config:
config[CONF_BLUE] = 0
return conf
return config
PRESET_SCHEMA = cv.All( PRESET_SCHEMA = cv.All(
cv.Schema( cv.Schema(
@ -111,18 +111,18 @@ def maybe_simple_preset_action(schema):
if isinstance(value, dict): if isinstance(value, dict):
return schema(value) return schema(value)
value = value.lower() value = value.lower()
conf = {}
config = {}
if value == "next_group": if value == "next_group":
conf[CONF_NEXT] = CONF_GROUP
config[CONF_NEXT] = CONF_GROUP
elif value == "next_preset": elif value == "next_preset":
conf[CONF_NEXT] = CONF_PRESET
config[CONF_NEXT] = CONF_PRESET
elif "." not in value: elif "." not in value:
conf[CONF_GROUP] = value
config[CONF_GROUP] = value
else: else:
group, preset = value.split(".", 2) group, preset = value.split(".", 2)
conf[CONF_GROUP] = group
conf[CONF_PRESET] = preset
return schema(conf)
config[CONF_GROUP] = group
config[CONF_PRESET] = preset
return schema(config)
return validator return validator
@ -173,10 +173,21 @@ def disco_action_off_to_code(config, action_id, template_arg, args):
cg.add(var.set_disco_state(False)) cg.add(var.set_disco_state(False))
yield var yield var
USED_PRESETS = []
def register_preset_action(value):
if "group" in value and not isinstance(value["group"], Lambda):
if "preset" in value and not isinstance(value["preset"], Lambda):
preset_data = [value['group'], value['preset']]
else:
preset_data = [value["group"], None]
USED_PRESETS.append(preset_data)
return value
@automation.register_action( @automation.register_action(
"preset.activate", "preset.activate",
ActivatePresetAction, ActivatePresetAction,
cv.Schema(
cv.All(
maybe_simple_preset_action(cv.Any( maybe_simple_preset_action(cv.Any(
cv.Schema({ cv.Schema({
cv.GenerateID(CONF_PRESETS_ID): cv.use_id(PresetsContainer), cv.GenerateID(CONF_PRESETS_ID): cv.use_id(PresetsContainer),
@ -187,8 +198,9 @@ def disco_action_off_to_code(config, action_id, template_arg, args):
cv.GenerateID(CONF_PRESETS_ID): cv.use_id(PresetsContainer), cv.GenerateID(CONF_PRESETS_ID): cv.use_id(PresetsContainer),
cv.Required(CONF_NEXT): cv.one_of(CONF_GROUP, CONF_PRESET, lower=True) cv.Required(CONF_NEXT): cv.one_of(CONF_GROUP, CONF_PRESET, lower=True)
}) })
))
)
)),
register_preset_action
),
) )
def preset_activate_to_code(config, action_id, template_arg, args): def preset_activate_to_code(config, action_id, template_arg, args):
presets_var = yield cg.get_variable(config[CONF_PRESETS_ID]) presets_var = yield cg.get_variable(config[CONF_PRESETS_ID])
@ -219,9 +231,9 @@ def light_output_to_code(config):
@coroutine @coroutine
def on_brightness_to_code(config): def on_brightness_to_code(config):
light_output_var = yield cg.get_variable(config[CONF_OUTPUT_ID]) light_output_var = yield cg.get_variable(config[CONF_OUTPUT_ID])
for conf in config.get(CONF_ON_BRIGHTNESS, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], light_output_var)
yield automation.build_automation(trigger, [(float, "x")], conf)
for config in config.get(CONF_ON_BRIGHTNESS, []):
trigger = cg.new_Pvariable(config[CONF_TRIGGER_ID], light_output_var)
yield automation.build_automation(trigger, [(float, "x")], config)
@coroutine @coroutine
def preset_to_code(config, preset_group, preset_name): def preset_to_code(config, preset_group, preset_name):
@ -260,3 +272,15 @@ def to_code(config):
yield light_output_to_code(config) yield light_output_to_code(config)
yield on_brightness_to_code(config) yield on_brightness_to_code(config)
yield presets_to_code(config) yield presets_to_code(config)
def validate(config):
valid_presets = config.get(CONF_PRESETS, {});
for group, preset in USED_PRESETS:
if group not in valid_presets:
raise cv.Invalid(f"Invalid light preset group '{group}' used")
if preset is not None and preset not in valid_presets[group]:
raise cv.Invalid(f"Invalid light preset '{group}.{preset}' used")
return config
FINAL_VALIDATE_SCHEMA = cv.Schema(validate);

Loading…
Cancel
Save