fix: Handle None values from empty YAML fields to prevent AttributeError (fixes #212)#231
Merged
hugobloem merged 6 commits intohugobloem:mainfrom Feb 7, 2026
Merged
Conversation
Implements a two-layer defense strategy to prevent crashes when scenes.yaml contains empty YAML fields that are parsed as None values. ## Changes ### Prevention Layer - Filter None values when reading scene attributes from YAML - Location: StatefulScenes.py:734-737 - Prevents empty YAML fields from being copied as None attributes ### Defensive Layer - Add None handling to 4 helper functions in helpers.py: * get_id_from_entity_id() * get_name_from_entity_id() * get_icon_from_entity_id() * get_area_from_entity_id() - Update area_name() in StatefulScenes.py - Add UI fallback values in config_flow.py (3 locations) ## Semantic Preservation Preserves intentional None state values for "don't care" semantics while filtering unintentional None from empty YAML fields. Fixes AttributeError: 'NoneType' object has no attribute 'lower' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…rom-empty-yaml-fields fix: Handle None values from empty YAML fields to prevent AttributeError
Implements proper path resolution to support relative paths like "scenes.yaml" across Docker, HAOS, VM, and core installations. ## Changes ### Path Resolution (Core Fix) - Update load_scenes_file() to accept hass parameter - Use hass.config.path() to resolve relative paths - Absolute paths continue to work unchanged - Enhanced error messages with both input and resolved paths - Added validation for empty paths and directories ### Auto-Detection with Graceful Fallback - Add _detect_scenes_path() method to auto-detect scenes file - Tries common paths: scenes.yaml, scenes.yml, config/scenes.yaml - Pre-fills config flow form with detected path - Shows warning if path cannot be auto-detected - User can manually adjust if needed ### Updated Call Sites - Runtime setup in __init__.py (line 46) - Config flow validation in config_flow.py (line 83) ## Benefits - Users can use default "scenes.yaml" without specifying absolute paths - Works consistently across all installation methods - Backward compatible - existing absolute paths work unchanged - Better UX with auto-detection and pre-filling - Clear error messages for troubleshooting Fixes hugobloem#217 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…olution fix: Resolve scenes.yaml path across different HA installation methods
Owner
|
Many thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
My AI skills exceed my Python skills. Therefore, I have used Claude code and my debug skills to address this issue.
Problem
The integration crashes with
AttributeError: 'NoneType' object has no attribute 'lower'whenscenes.yamlcontains empty YAML fields. This occurs because the YAML parser (yaml.FullLoader) interprets empty fields asNonevalues, which are then passed to functions expecting string values.Example problematic YAML:
Error trace:
Root Cause
When YAML fields are left empty (e.g.,
brightness:,color_mode:), theyaml.FullLoaderparser returnsNonefor these values. The integration previously had no protection against these unintentionalNonevalues, causing crashes when:Noneinstead of expected string values for entity IDsNonereturns from helper functionsThis is distinct from the intentional use of
Nonefor "don't care" semantics in state values, which must be preserved for proper scene matching logic.Solution
Implemented a two-layer defense-in-depth strategy:
1. Prevention Layer (Primary Defense)
Filter out
Nonevalues at the source when reading scene attributes from YAML, preventing unintentionalNonevalues from entering the system.2. Defensive Layer (Robustness)
Add explicit
Nonehandling throughout the codebase to gracefully handle edge cases and improve overall robustness.This approach ensures:
Nonevalues from empty YAML fields are filtered outNonestate values for "don't care" semantics are preservedNonevalues slip through validationChanges Made
1. Prevention Layer
File:
/custom_components/stateful_scenes/StatefulScenes.pyLocation: Lines 734-737
Added
Nonevalue filtering when copying scene attributes from YAML:Impact: Prevents empty YAML fields from being copied as
Noneattributes to entity configurations2. Defensive Layer
File:
/custom_components/stateful_scenes/helpers.pyAdded
Nonehandling to 4 helper functions with updated type hints:get_id_from_entity_id()- Lines 10-15get_name_from_entity_id()- Lines 18-22get_icon_from_entity_id()- Lines 25-29get_area_from_entity_id()- Lines 32-45All functions now accept
str | Noneand returnstr | None, with earlyNonechecks.File:
/custom_components/stateful_scenes/StatefulScenes.pyLocation: Lines 35-42
Added
Nonecheck toarea_name()functionFile:
/custom_components/stateful_scenes/config_flow.pyAdded fallback values for UI display when helper functions return
None:Semantic Preservation
This fix carefully preserves the existing behavior where
Nonestate values are used intentionally to mean "don't care" during scene matching:state: Nonefor an entity matches regardless of current stateNonefrom attributes, not from state fieldsTesting
Tested scenarios:
NonereturnsBreaking Changes
None. This is a pure bug fix with no breaking changes:
Nonesemantics are preserved🤖 Generated with Claude Code