Files
home-assistant-blueprints/CLAUDE.md
John Ogle 14fadbe44e Add custom mode tutorial and update docs for pure blueprint architecture
Add ADDING_MODES.md tutorial covering:
- UI-created modes (recommended) and package-defined modes
- Complete schema reference with nested al_config
- Behavior types (adaptive_lighting, scene, script)
- Manual control support and advanced examples

Update all documentation to reflect:
- Zero YAML editing for room setup (UI-driven workflow)
- Convention-based mode lookup pattern
- Pure blueprint architecture (3 core + 3 optional blueprints)
- Extensibility via helpers instead of template copying
2025-12-21 17:44:47 -08:00

451 lines
15 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
This is a Home Assistant blueprints repository containing automation blueprints and a global package for Adaptive Lighting mode management. The repository uses a **pure blueprint architecture** with **convention-based entity lookup** for extensibility.
## Architecture
### Blueprint Structure
- **3 core blueprints** for Adaptive Lighting mode system (mode application + 2 weekend mode blueprints)
- **3 optional blueprints** for Inovelli switch integration and presence-based automation
- **Convention-based entity lookup**: Blueprints dynamically discover mode settings using naming convention (`adaptive_lighting_settings_{{mode}}`)
- **Optional input handling**: Blueprints use `default: {}` pattern for optional inputs
### Package Structure
- **1 global package** with 8 mode definitions (`adaptive_lighting_global.yaml`)
- **Nested JSON schema**: Each mode contains `behavior`, `manual_control`, `led_color`, and `al_config` fields
- **No room templates**: Room configuration done entirely via Home Assistant UI
### User Workflow
- **Zero YAML editing** for room setup
- Create helpers via Settings → Helpers (dropdowns, toggles, text inputs)
- Import blueprints via Settings → Blueprints
- Create automations from blueprints via UI
- Add custom modes by creating helpers following naming convention
## Core Blueprints
### Apply Lighting Mode Blueprint (`apply_lighting_mode.yaml`)
**Purpose**: Data-driven mode application using convention-based entity lookup
**Key features**:
- Convention-based entity lookup: `adaptive_lighting_settings_{{mode | lower | replace(' ', '_')}}`
- Behavior polymorphism: Supports "adaptive_lighting", "scene", and "script" behaviors
- Manual control support: Top-level `manual_control` attribute controls AL manual control state
- Optional LED color integration for Inovelli switches
- Mode: restart for debouncing rapid state changes
**Architecture patterns**:
- Dynamic entity ID construction from mode name
- Nested al_config extraction to avoid service validation errors
- Conditional execution based on behavior type
- Optional input handling with `default: {}`
### Weekend Mode Schedule Blueprint (`weekend_mode_schedule.yaml`)
**Purpose**: Auto-enable/disable weekend mode based on day of week
**Key features**:
- Single automation combines enable + disable logic using choose action
- Time trigger checks day of week
- Toggles input_boolean based on weekday condition
- Mode: single to prevent overlapping executions
### Weekend Mode Apply Settings Blueprint (`weekend_mode_apply_settings.yaml`)
**Purpose**: Apply AL adjustments when weekend mode toggles
**Key features**:
- Delayed sunrise time for sleeping in on weekends
- Extended sunset time for staying up later
- Reduced max brightness
- Reset to defaults when weekend mode turns off
- Triggers on boolean state change + HA restart
- Mode: restart for debouncing
## Development Workflow
### Adding New Modes
**Two methods**:
1. **UI-created modes** (recommended):
- Create input_text helper via Settings → Helpers
- Follow naming convention: `input_text.adaptive_lighting_settings_{{mode}}`
- Use nested schema: `{"behavior":"adaptive_lighting","manual_control":false,"led_color":170,"al_config":{...}}`
- No restart required
- Reference: ADDING_MODES.md tutorial
2. **Package-defined modes** (version controlled):
- Edit `adaptive_lighting_global.yaml`
- Add new input_text entity following existing patterns
- Use nested schema with behavior, manual_control, led_color, al_config
- Reload YAML configuration
**Key principle**: Modes are discovered by convention, not hardcoded. Adding a mode doesn't require blueprint changes.
### Blueprint Testing
Manual testing workflow (no automated testing framework for HA blueprints):
1. Import blueprint to Home Assistant
2. Create test helpers via UI
3. Create automation from blueprint
4. Test all input combinations
5. Verify automation traces for debugging
6. Check Home Assistant logs for errors
### Blueprint Best Practices
- **Convention-based entity naming** for extensibility (modes, devices)
- **Optional input handling** with `default: {}` for flexible configuration
- **Mode: restart** for debouncing state changes
- **Mode: single** for preventing overlapping executions
- **Nested JSON schema** to satisfy service validation constraints
- **Integration filters** (`domain: switch, integration: adaptive_lighting`) for user-friendly entity selection
- Use descriptive names and clear descriptions for inputs
- Provide sensible defaults for optional parameters
- Include comprehensive documentation in blueprint metadata
### Home Assistant Blueprint Format
Blueprints follow this structure:
```yaml
blueprint:
name: Blueprint Name
description: Clear description of what this blueprint does
domain: automation
input:
input_name:
name: User-Facing Name
description: Clear description of this input
default: {} # For optional inputs
selector:
entity:
domain: switch
integration: adaptive_lighting # Optional filter
mode: restart # or single, queued, parallel
max_exceeded: silent
trigger:
- platform: state
entity_id: !input input_name
variables:
var_name: !input input_name
derived_var: "{{ template_expression }}"
action:
- service: some.service
target:
entity_id: "{{ var_name }}"
data:
setting: "{{ derived_var }}"
```
### Input Selectors
Common selector types used in this repository:
**Entity selectors**:
```yaml
selector:
entity:
domain: input_select # Dropdown helpers
# or
domain: input_boolean # Toggle helpers
# or
domain: switch
integration: adaptive_lighting # Filter by integration
# or
domain: number # Number entities (LED color)
```
**Time selector**:
```yaml
selector:
time: # HH:MM:SS time picker
```
**Number selector**:
```yaml
selector:
number:
min: 1
max: 100
step: 1
unit_of_measurement: "%"
```
**Action selector**:
```yaml
selector:
action: # Full action sequence builder
```
### Mode Settings Schema
Each mode uses this nested JSON structure:
```json
{
"behavior": "adaptive_lighting", // or "scene", "script"
"manual_control": false, // Controls AL manual control state
"led_color": 170, // 0-255 hue value for Inovelli LED
"al_config": { // Nested object for AL settings
"min_brightness": 20,
"max_brightness": 80,
"min_color_temp": 2000,
"max_color_temp": 4000,
"transition": 5
}
}
```
**Why nested?**: The `adaptive_lighting.change_switch_settings` service performs strict key validation, rejecting unknown keys. The nested structure isolates AL-specific settings in `al_config`, while metadata like `behavior` and `led_color` remain at the top level.
**Manual control**: The `manual_control` attribute (defaults to `false`) controls whether AL manual control is enabled for the mode. When `true`, AL is paused and won't adjust lights. The blueprint always calls `adaptive_lighting.set_manual_control` with this value.
## File Organization
```
/
├── blueprints/
│ └── automation/
│ ├── apply_lighting_mode.yaml # Core: Data-driven mode application
│ ├── weekend_mode_schedule.yaml # Core: Auto-enable/disable weekend mode
│ ├── weekend_mode_apply_settings.yaml # Core: Apply weekend AL adjustments
│ ├── inovelli_mode_cycling.yaml # Optional: Config button mode cycling
│ ├── inovelli_button_actions.yaml # Optional: Multi-tap button actions
│ ├── presence_mode_reset.yaml # Optional: Auto-reset on room exit
│ └── occupancy_controlled_lights.yaml # Standalone: Occupancy-based lighting
├── packages/
│ └── adaptive_lighting_global.yaml # Global mode definitions (8 modes)
├── hardware/
│ └── inovelli/
│ └── blue-dimmer-2-in-1-vzt31.md # Inovelli Blue Dimmer documentation
├── README.md # Main documentation
├── PACKAGE_SETUP_GUIDE.md # Global package installation
├── ROOM_CONFIGURATION_GUIDE.md # UI-driven room setup
├── ADDING_MODES.md # Custom mode creation tutorial
└── CLAUDE.md # This file
```
## Home Assistant Blueprint Conventions
### Input Types
- `entity`: Entity selector for picking Home Assistant entities
- `action`: Action sequence selector for automation actions
- `number`: Numeric input with min/max/step validation
- `boolean`: True/false toggle
- `text`: String input fields
- `time`: Time picker (HH:MM:SS format)
### Template Usage
- Use `!input` to reference blueprint inputs
- Template conditions with `{{ }}` syntax for dynamic logic
- Variable assignment and reference within action sequences
- Jinja2 filters for string manipulation (`lower`, `replace`, `from_json`)
### Automation Modes
- `restart`: Stops current execution and restarts on new trigger (used for debouncing)
- `single`: Ignores new triggers while running
- `parallel`: Allows multiple simultaneous executions
- `queued`: Queues triggers and executes sequentially
### Pattern References
**Optional input handling** (`presence_mode_reset.yaml:98-116`):
```yaml
input:
optional_entity:
default: {}
selector:
entity:
domain: input_select
# Later in action:
- if:
- condition: template
value_template: "{{ optional_entity not in [none, {}, ''] }}"
then:
- service: some.service
target:
entity_id: "{{ optional_entity }}"
```
**Integration filter** (`inovelli_button_actions.yaml:36-42`):
```yaml
selector:
entity:
domain: switch
integration: adaptive_lighting
```
**Choose action pattern** (for behavior polymorphism):
```yaml
- choose:
- conditions: "{{ behavior == 'adaptive_lighting' }}"
sequence:
- service: adaptive_lighting.change_switch_settings
data: "{{ al_config }}"
- conditions: "{{ behavior == 'scene' }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ settings.scene_entity }}"
- conditions: "{{ behavior == 'script' }}"
sequence:
- service: script.turn_on
target:
entity_id: "{{ settings.script_entity }}"
```
## Import URLs
Blueprints are hosted at:
- Base URL: `https://git.johnogle.info/johno/home-assistant-blueprints/raw/branch/main/`
- Pattern: `{base_url}/blueprints/automation/{blueprint_name}.yaml`
Example: `https://git.johnogle.info/johno/home-assistant-blueprints/raw/branch/main/blueprints/automation/apply_lighting_mode.yaml`
## Design Principles
### Convention Over Configuration
**Key insight**: Extend the blueprint once to add a capability, then use that capability unlimited times via helpers.
Examples:
- Want 100 adaptive_lighting modes? Create 100 helpers following naming convention (no blueprint changes)
- Want scene-based modes? Blueprint already supports it (no changes needed)
- Want custom "Bowling" mode? Create one helper with correct entity ID (no changes needed)
**This is the power of convention-based design.**
### Zero YAML Editing for Users
Room configuration workflow:
1. Create helpers via UI (dropdowns, toggles)
2. Create automations from blueprints via UI
3. Test by switching modes via UI
4. Add custom modes by creating text helpers via UI
No template copying, no YAML editing, no search/replace, no package files per room.
### Nested Schema for Service Validation
Why nested `al_config`?
- Home Assistant services perform strict validation
- Unknown keys cause errors
- Nested structure separates metadata from service parameters
- Only `al_config` is passed to `adaptive_lighting.change_switch_settings`
- Top-level fields (`behavior`, `manual_control`, `led_color`) used by blueprint logic
### Behavior Polymorphism
Modes can have different behaviors:
- **adaptive_lighting**: Apply AL settings (default)
- **scene**: Activate Home Assistant scene
- **script**: Run Home Assistant script
This enables complex use cases (movie scenes, light shows) without modifying blueprint core logic.
## Migration Notes
**No migration needed** - repository contains only blueprints and one global package, no deployed room configurations.
**For future users**: If this becomes public, users would migrate from template packages to blueprint + UI workflow by:
1. Creating helpers via UI matching their room names
2. Importing blueprints
3. Creating automations from blueprints
4. Deleting old package files
5. Reloading YAML configuration
## Performance Considerations
No performance concerns:
- Automations trigger only on mode changes (user-initiated, infrequent)
- JSON parsing is fast and cached by Home Assistant
- Convention-based lookup is simple string templating
- No polling, no external services, no heavy computation
- Mode: restart prevents rapid-fire executions
## Common Issues and Solutions
### Service Validation Errors
**Symptom**: "extra keys not allowed" in logs
**Cause**: Passing top-level fields to `adaptive_lighting.change_switch_settings`
**Solution**: Only pass `al_config` nested object to service
### Missing Mode Entities
**Symptom**: Blueprint fails to find mode settings
**Cause**: Entity ID doesn't match naming convention
**Solution**: Verify entity ID follows pattern `input_text.adaptive_lighting_settings_{{mode | lower | replace(' ', '_')}}`
### LED Color Not Updating
**Symptom**: Mode changes but LED stays same color
**Causes**:
1. LED entity not configured (left empty)
2. Incorrect entity ID
3. Inovelli switch firmware issue
**Solution**: Check automation configuration, verify entity ID, test LED manually
## Testing Guidelines
Since Home Assistant blueprints have no automated testing framework, all testing is manual:
1. **Blueprint Import**: Verify imports without errors in HA
2. **Helper Creation**: Create test helpers via UI
3. **Automation Creation**: Create test automations from blueprints
4. **Mode Switching**: Test all mode combinations
5. **Custom Modes**: Create custom mode and verify convention-based lookup
6. **LED Integration**: Verify LED colors update (if configured)
7. **Weekend Mode**: Test schedule and AL adjustments
8. **HA Restart**: Verify persistence across restarts
9. **Error Handling**: Test missing entities, invalid JSON, etc.
10. **Logs**: Check for errors in Settings → System → Logs
Always check automation traces (Settings → Automations → [automation] → Traces) for debugging.
## Key Differences from Traditional Approach
**Old approach** (template packages):
- Copy package file per room
- Search/replace entity IDs
- Edit YAML to add modes
- Hardcoded choose blocks for each mode
- Adding mode requires editing every room
**New approach** (pure blueprints):
- Create helpers via UI
- Create automations via UI
- Zero YAML editing for rooms
- Convention-based mode lookup
- Adding mode = create ONE helper
**Benefits**:
- Lower friction for users
- No YAML syntax errors from manual editing
- Extensible without code changes
- Easier to maintain
- Better user experience
## Resources
- [Home Assistant Blueprint Documentation](https://www.home-assistant.io/docs/blueprint/)
- [Adaptive Lighting Integration](https://github.com/basnijholt/adaptive-lighting)
- [Jinja2 Template Reference](https://jinja.palletsprojects.com/)
- [YAML Specification](https://yaml.org/)