Skip to content

Commit 4e3c147

Browse files
authored
Merge pull request #58 from Snuffy2/Fix-value-should-be-a-list-error-in-config_flow
Fix light selector in config_flow
2 parents 57c4461 + 82947de commit 4e3c147

File tree

3 files changed

+54
-41
lines changed

3 files changed

+54
-41
lines changed

custom_components/animated_scenes/config_flow.py

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import voluptuous as vol
1414

1515
from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult, OptionsFlow
16-
from homeassistant.const import CONF_BRIGHTNESS, CONF_ICON, CONF_LIGHTS, CONF_NAME
16+
from homeassistant.const import CONF_BRIGHTNESS, CONF_ICON, CONF_LIGHTS, CONF_NAME, Platform
1717
from homeassistant.core import callback
1818
from homeassistant.helpers import selector
1919
import homeassistant.helpers.config_validation as cv
@@ -76,6 +76,7 @@
7676
ERROR_CHANGE_FREQUENCY_NOT_INT_OR_RANGE,
7777
ERROR_COLORS_IS_BLANK,
7878
ERROR_COLORS_MALFORMED,
79+
ERROR_MUST_SELECT_LIGHTS,
7980
ERROR_TRANSITION_NOT_INT_OR_RANGE,
8081
TRANSITION_MAX,
8182
TRANSITION_MIN,
@@ -285,7 +286,7 @@ def _get_default(key: str, fallback_default: Any = None) -> Any:
285286
): selector.IconSelector(selector.IconSelectorConfig()),
286287
}
287288
)
288-
return build_schema.extend(
289+
build_schema = build_schema.extend(
289290
{
290291
vol.Optional(
291292
CONF_PRIORITY, default=_get_default(CONF_PRIORITY, DEFAULT_PRIORITY)
@@ -339,11 +340,18 @@ def _get_default(key: str, fallback_default: Any = None) -> Any:
339340
CONF_RESTORE_POWER,
340341
default=_get_default(CONF_RESTORE_POWER, DEFAULT_RESTORE_POWER),
341342
): selector.BooleanSelector(selector.BooleanSelectorConfig()),
342-
vol.Required(CONF_LIGHTS, default=_get_default(CONF_LIGHTS)): selector.EntitySelector(
343-
selector.EntitySelectorConfig(domain="light", multiple=True),
343+
vol.Required(
344+
CONF_LIGHTS, default=_get_default(CONF_LIGHTS, [])
345+
): selector.EntitySelector(
346+
selector.EntitySelectorConfig(domain=[Platform.LIGHT], multiple=True),
344347
),
348+
}
349+
)
350+
351+
return build_schema.extend(
352+
{
345353
vol.Required(
346-
CONF_COLOR_SELECTOR_MODE, default=_get_default(CONF_COLOR_SELECTOR_MODE)
354+
CONF_COLOR_SELECTOR_MODE, default=_get_default(CONF_COLOR_SELECTOR_MODE, "")
347355
): selector.SelectSelector(
348356
selector.SelectSelectorConfig(
349357
options=COLOR_SELECTOR_OPTION_LIST,
@@ -475,7 +483,6 @@ def __init__(self) -> None:
475483
self._data: dict[str, Any] = {}
476484
self._data[CONF_COLOR_RGB_DICT] = {}
477485
self._data[CONF_COLORS] = {}
478-
self._errors: dict[str, Any] = {}
479486
self._entry = None
480487

481488
async def async_step_user(self, user_input: dict[str, Any] | None = None) -> ConfigFlowResult:
@@ -513,7 +520,7 @@ async def async_step_scene(
513520
configuration steps or creating the config entry.
514521
"""
515522

516-
self._errors = {}
523+
errors: dict[str, Any] = {}
517524

518525
# Defaults
519526
defaults = {
@@ -539,6 +546,8 @@ async def async_step_scene(
539546
self._data.get(CONF_CHANGE_AMOUNT),
540547
type(self._data.get(CONF_CHANGE_AMOUNT)),
541548
)
549+
if len(self._data.get(CONF_LIGHTS, [])) == 0:
550+
errors["base"] = ERROR_MUST_SELECT_LIGHTS
542551
change_amount_check, change_amount_value = _is_int_list_or_all(
543552
self._data.get(CONF_CHANGE_AMOUNT),
544553
CHANGE_AMOUNT_MIN,
@@ -547,7 +556,7 @@ async def async_step_scene(
547556
if change_amount_check:
548557
self._data.update({CONF_CHANGE_AMOUNT: change_amount_value})
549558
else:
550-
self._errors["base"] = ERROR_CHANGE_AMOUNT_NOT_INT_OR_ALL
559+
errors["base"] = ERROR_CHANGE_AMOUNT_NOT_INT_OR_ALL
551560
_LOGGER.debug(
552561
"Checking Transition: %s, type: %s",
553562
self._data.get(CONF_TRANSITION),
@@ -561,7 +570,7 @@ async def async_step_scene(
561570
if transition_check:
562571
self._data.update({CONF_TRANSITION: transition_value})
563572
else:
564-
self._errors["base"] = ERROR_TRANSITION_NOT_INT_OR_RANGE
573+
errors["base"] = ERROR_TRANSITION_NOT_INT_OR_RANGE
565574
_LOGGER.debug(
566575
"Checking Change Frequency: %s, type: %s",
567576
self._data.get(CONF_CHANGE_FREQUENCY),
@@ -575,7 +584,7 @@ async def async_step_scene(
575584
if change_frequency_check:
576585
self._data.update({CONF_CHANGE_FREQUENCY: change_frequency_value})
577586
else:
578-
self._errors["base"] = ERROR_CHANGE_FREQUENCY_NOT_INT_OR_RANGE
587+
errors["base"] = ERROR_CHANGE_FREQUENCY_NOT_INT_OR_RANGE
579588
_LOGGER.debug(
580589
"Checking Brightness: %s, type: %s",
581590
self._data.get(CONF_BRIGHTNESS),
@@ -589,7 +598,7 @@ async def async_step_scene(
589598
if brightness_check:
590599
self._data.update({CONF_BRIGHTNESS: brightness_value})
591600
else:
592-
self._errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
601+
errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
593602
self._data.update(
594603
{CONF_PRIORITY: round(self._data.get(CONF_PRIORITY, DEFAULT_PRIORITY))}
595604
)
@@ -604,7 +613,7 @@ async def async_step_scene(
604613
for k, v in defaults.items():
605614
self._data.setdefault(k, v)
606615
# _LOGGER.debug(f"[async_step_scene] self._data: {self._data}")
607-
if not self._errors:
616+
if not errors:
608617
if yaml_import:
609618
self._data.update({CONF_COLOR_SELECTOR_MODE: COLOR_SELECTOR_YAML})
610619
return self.async_create_entry(title=self._data[CONF_NAME], data=self._data)
@@ -618,33 +627,33 @@ async def async_step_scene(
618627
return self.async_show_form(
619628
step_id="scene",
620629
data_schema=await _async_build_schema(user_input, defaults),
621-
errors=self._errors,
630+
errors=errors,
622631
)
623632

624633
async def async_step_color_yaml(
625634
self, user_input: dict[str, Any] | None = None
626635
) -> ConfigFlowResult:
627636
"""Handle color configuration when the user chooses YAML input."""
628-
self._errors = {}
637+
errors: dict[str, Any] = {}
629638

630639
# Defaults
631640
defaults: dict[str, Any] = {}
632641

633642
if user_input is not None:
634643
self._data.update(user_input)
635644
if self._data.get(CONF_COLORS) is None or self._data.get(CONF_COLORS) == {}:
636-
self._errors["base"] = ERROR_COLORS_IS_BLANK
645+
errors["base"] = ERROR_COLORS_IS_BLANK
637646
if not isinstance(self._data.get(CONF_COLORS), list):
638-
self._errors["base"] = ERROR_COLORS_MALFORMED
647+
errors["base"] = ERROR_COLORS_MALFORMED
639648
for k, v in defaults.items():
640649
self._data.setdefault(k, v)
641650
# _LOGGER.debug(f"[async_step_color_yaml] self._data: {self._data}")
642-
if not self._errors:
651+
if not errors:
643652
return self.async_create_entry(title=self._data[CONF_NAME], data=self._data)
644653
return self.async_show_form(
645654
step_id="color_yaml",
646655
data_schema=await _async_build_color_yaml_schema(user_input, defaults),
647-
errors=self._errors,
656+
errors=errors,
648657
description_placeholders={
649658
"component_color_config_url": COMPONENT_COLOR_CONFIG_URL,
650659
},
@@ -654,7 +663,7 @@ async def async_step_color_rgb_ui(
654663
self, user_input: dict[str, Any] | None = None
655664
) -> ConfigFlowResult:
656665
"""Handle color configuration when the user uses the RGB UI selectors."""
657-
self._errors = {}
666+
errors: dict[str, Any] = {}
658667

659668
# Defaults
660669
defaults = {
@@ -680,7 +689,7 @@ async def async_step_color_rgb_ui(
680689
if brightness_check:
681690
user_input.update({CONF_BRIGHTNESS: brightness_value})
682691
else:
683-
self._errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
692+
errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
684693
user_input.update(
685694
{CONF_COLOR_WEIGHT: round(user_input.get(CONF_COLOR_WEIGHT, DEFAULT_COLOR_WEIGHT))}
686695
)
@@ -693,7 +702,7 @@ async def async_step_color_rgb_ui(
693702
)
694703
for k, v in defaults.items():
695704
user_input.setdefault(k, v)
696-
if not self._errors:
705+
if not errors:
697706
color_uuid = uuid.random_uuid_hex()
698707
self._data.get(CONF_COLOR_RGB_DICT, {}).update({color_uuid: user_input})
699708
# _LOGGER.debug(f"[async_step_color_rgb_ui] self._data: {self._data}")
@@ -712,7 +721,7 @@ async def async_step_color_rgb_ui(
712721
return self.async_show_form(
713722
step_id="color_rgb_ui",
714723
data_schema=await _async_build_color_rgb_ui_schema(user_input, defaults),
715-
errors=self._errors,
724+
errors=errors,
716725
description_placeholders={
717726
"color_count": str(len(self._data.get(CONF_COLOR_RGB_DICT, {})) + 1),
718727
},
@@ -741,7 +750,6 @@ def __init__(self, config_entry: ConfigEntry) -> None:
741750
"""Initialize."""
742751
self.config = config_entry
743752
self._data = dict(config_entry.data)
744-
self._errors: dict[str, Any] = {}
745753
rgb_dict = self._data.get(CONF_COLOR_RGB_DICT)
746754
if rgb_dict:
747755
self._rgb_ui_color_keys = list(self._data.get(CONF_COLOR_RGB_DICT, {}).keys())
@@ -765,7 +773,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
765773
color configuration steps or update the entry data.
766774
"""
767775

768-
self._errors = {}
776+
errors: dict[str, Any] = {}
769777

770778
# Defaults
771779
defaults = {
@@ -791,6 +799,8 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
791799
self._data.get(CONF_CHANGE_AMOUNT),
792800
type(self._data.get(CONF_CHANGE_AMOUNT)),
793801
)
802+
if len(self._data.get(CONF_LIGHTS, [])) == 0:
803+
errors["base"] = ERROR_MUST_SELECT_LIGHTS
794804
change_amount_check, change_amount_value = _is_int_list_or_all(
795805
self._data.get(CONF_CHANGE_AMOUNT),
796806
CHANGE_AMOUNT_MIN,
@@ -799,7 +809,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
799809
if change_amount_check:
800810
self._data.update({CONF_CHANGE_AMOUNT: change_amount_value})
801811
else:
802-
self._errors["base"] = ERROR_CHANGE_AMOUNT_NOT_INT_OR_ALL
812+
errors["base"] = ERROR_CHANGE_AMOUNT_NOT_INT_OR_ALL
803813
_LOGGER.debug(
804814
"Checking Transition: %s, type: %s",
805815
self._data.get(CONF_TRANSITION),
@@ -813,7 +823,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
813823
if transition_check:
814824
self._data.update({CONF_TRANSITION: transition_value})
815825
else:
816-
self._errors["base"] = ERROR_TRANSITION_NOT_INT_OR_RANGE
826+
errors["base"] = ERROR_TRANSITION_NOT_INT_OR_RANGE
817827
_LOGGER.debug(
818828
"Checking Change Frequency: %s, type: %s",
819829
self._data.get(CONF_CHANGE_FREQUENCY),
@@ -827,7 +837,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
827837
if change_frequency_check:
828838
self._data.update({CONF_CHANGE_FREQUENCY: change_frequency_value})
829839
else:
830-
self._errors["base"] = ERROR_CHANGE_FREQUENCY_NOT_INT_OR_RANGE
840+
errors["base"] = ERROR_CHANGE_FREQUENCY_NOT_INT_OR_RANGE
831841
_LOGGER.debug(
832842
"Checking Brightness: %s, type: %s",
833843
self._data.get(CONF_BRIGHTNESS),
@@ -841,7 +851,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
841851
if brightness_check:
842852
self._data.update({CONF_BRIGHTNESS: brightness_value})
843853
else:
844-
self._errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
854+
errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
845855
self._data.update(
846856
{CONF_PRIORITY: round(self._data.get(CONF_PRIORITY, DEFAULT_PRIORITY))}
847857
)
@@ -856,7 +866,7 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
856866
for k, v in defaults.items():
857867
self._data.setdefault(k, v)
858868
# _LOGGER.debug(f"[async_init_user] self._data: {self._data}")
859-
if not self._errors:
869+
if not errors:
860870
if (
861871
self._data.get(CONF_COLOR_SELECTOR_MODE, COLOR_SELECTOR_RGB_UI)
862872
== COLOR_SELECTOR_RGB_UI
@@ -867,29 +877,29 @@ async def async_step_scene(self, user_input: dict[str, Any] | None = None) -> Co
867877
return self.async_show_form(
868878
step_id="scene",
869879
data_schema=await _async_build_schema(user_input, self._data, options_flow=True),
870-
errors=self._errors,
880+
errors=errors,
871881
description_placeholders={"scene_name": self._data[CONF_NAME]},
872882
)
873883

874884
async def async_step_color_yaml(
875885
self, user_input: dict[str, Any] | None = None
876886
) -> ConfigFlowResult:
877887
"""Handle color configuration in YAML mode within the options flow."""
878-
self._errors = {}
888+
errors: dict[str, Any] = {}
879889

880890
# Defaults
881891
defaults: dict[str, Any] = {}
882892

883893
if user_input is not None:
884894
self._data.update(user_input)
885895
if self._data.get(CONF_COLORS) is None or self._data.get(CONF_COLORS) == {}:
886-
self._errors["base"] = ERROR_COLORS_IS_BLANK
896+
errors["base"] = ERROR_COLORS_IS_BLANK
887897
if not isinstance(self._data.get(CONF_COLORS), list):
888-
self._errors["base"] = ERROR_COLORS_MALFORMED
898+
errors["base"] = ERROR_COLORS_MALFORMED
889899
for k, v in defaults.items():
890900
self._data.setdefault(k, v)
891901
# _LOGGER.debug(f"[async_step_color_yaml] self._data: {self._data}")
892-
if not self._errors:
902+
if not errors:
893903
self._data.update({CONF_COLOR_RGB_DICT: {}})
894904
self.hass.config_entries.async_update_entry(
895905
self.config, data=self._data, options=self.config.options
@@ -900,7 +910,7 @@ async def async_step_color_yaml(
900910
return self.async_show_form(
901911
step_id="color_yaml",
902912
data_schema=await _async_build_color_yaml_schema(user_input, self._data),
903-
errors=self._errors,
913+
errors=errors,
904914
description_placeholders={
905915
"component_color_config_url": COMPONENT_COLOR_CONFIG_URL,
906916
},
@@ -910,7 +920,7 @@ async def async_step_color_rgb_ui(
910920
self, user_input: dict[str, Any] | None = None
911921
) -> ConfigFlowResult:
912922
"""Handle color configuration using the RGB UI selectors in options."""
913-
self._errors = {}
923+
errors: dict[str, Any] = {}
914924

915925
# Defaults
916926
defaults = {
@@ -941,14 +951,14 @@ async def async_step_color_rgb_ui(
941951
if brightness_check:
942952
color_data.update({CONF_BRIGHTNESS: brightness_value})
943953
else:
944-
self._errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
954+
errors["base"] = ERROR_BRIGHTNESS_NOT_INT_OR_RANGE
945955
color_data.update({CONF_COLOR_WEIGHT: round(color_data.get(CONF_COLOR_WEIGHT))})
946956
color_data.update(
947957
{CONF_COLOR_NEARBY_COLORS: round(color_data.get(CONF_COLOR_NEARBY_COLORS))}
948958
)
949959
for k, v in defaults.items():
950960
color_data.setdefault(k, v)
951-
if not self._errors:
961+
if not errors:
952962
if self._rgb_ui_color_index + 1 <= self._rgb_ui_color_max:
953963
self._data.get(CONF_COLOR_RGB_DICT, {}).update(
954964
{self._rgb_ui_color_keys[self._rgb_ui_color_index]: color_data}
@@ -987,7 +997,7 @@ async def async_step_color_rgb_ui(
987997
options_flow=True,
988998
is_last_color=(self._rgb_ui_color_index + 1 >= self._rgb_ui_color_max),
989999
),
990-
errors=self._errors,
1000+
errors=errors,
9911001
description_placeholders={
9921002
"component_color_config_url": COMPONENT_COLOR_CONFIG_URL,
9931003
"color_count": str(self._rgb_ui_color_index + 1),

custom_components/animated_scenes/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
ERROR_COLORS_IS_BLANK = "colors_is_blank"
8282
ERROR_COLORS_MALFORMED = "colors_malformed"
8383
ERROR_BRIGHTNESS_NOT_INT_OR_RANGE = "brightness_not_int_or_range"
84+
ERROR_MUST_SELECT_LIGHTS = "must_select_lights"
8485
ABORT_ACTIVITY_SENSOR_NO_OPTIONS = "activity_sensor_no_options"
8586
ABORT_INTEGRATION_NO_OPTIONS = "integration_no_options"
8687

custom_components/animated_scenes/translations/en.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"transition_not_int_or_range": "Transition Duration: Not an integer or range in format '[2,5]'. Min: 0, Max: 6553",
8080
"brightness_not_int_or_range": "Brightness: Not an integer or range in format '[125,255]'. Min: 0, Max: 255",
8181
"colors_is_blank": "Colors: Cannot be blank or empty",
82-
"colors_malformed": "Colors: Invalid format"
82+
"colors_malformed": "Colors: Invalid format",
83+
"must_select_lights": "You must select at least one light for the animation"
8384
}
8485
},
8586
"options": {
@@ -154,7 +155,8 @@
154155
"transition_not_int_or_range": "Transition Duration: Not an integer or range in format '[2,5]'. Min: 0, Max: 6553",
155156
"brightness_not_int_or_range": "Brightness: Not an integer or range in format '[125,255]'. Min: 0, Max: 255",
156157
"colors_is_blank": "Colors: Cannot be blank or empty",
157-
"colors_malformed": "Colors: Invalid format"
158+
"colors_malformed": "Colors: Invalid format",
159+
"must_select_lights": "You must select at least one light for the animation"
158160
},
159161
"abort": {
160162
"activity_sensor_no_options": "&nbsp;\n\nNo options are available for the Animated Scenes Activity Sensor",

0 commit comments

Comments
 (0)