diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..711c01b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,112 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview +This is a Home Assistant Blueprints repository containing reusable automation templates for smart home systems. All blueprints are YAML configuration files that can be imported directly into Home Assistant. + +## Common Development Tasks + +### Testing & Validation +- **Blueprint Validation**: Use Home Assistant's built-in blueprint importer to validate YAML syntax +- **Template Testing**: Test Jinja2 templates in Home Assistant Developer Tools → Template tab +- **Live Testing**: Import blueprint into Home Assistant and create test automation to verify behavior + +### Working with Blueprints +When modifying or creating blueprints: +1. Follow the standard Home Assistant blueprint schema structure +2. Always include comprehensive descriptions for user clarity +3. Provide sensible defaults for all input parameters +4. Use proper selectors for entity inputs (entity, device, area selectors) +5. Test templates for edge cases (unavailable entities, null states) + +## Architecture & Code Structure + +### Blueprint Components +Every blueprint follows this structure: +- **blueprint:** Metadata section with name, description, domain (always "automation") +- **input:** User-configurable parameters with selectors and defaults +- **trigger:** Event triggers (state changes, time patterns, device events) +- **condition:** Optional conditional logic +- **variables:** Template variables for complex logic +- **action:** Automation actions to execute +- **mode:** Execution mode (single, restart, queued, parallel) + +### Key Patterns + +#### Template Safety +Always use fallback defaults in templates: +```yaml +{{ states('sensor.temperature') | float(0) }} +{{ state_attr('device.battery', 'battery_level') | int(100) }} +``` + +#### Entity Expansion +Use expand() for working with entity groups: +```yaml +{% for entity_id in expand(battery_sensors) | map(attribute='entity_id') | list %} +``` + +#### Z-Wave Event Handling +Z-Wave central scene events follow this pattern: +```yaml +trigger: + - platform: event + event_type: zwave_js_value_notification + event_data: + command_class: 91 # Central Scene + property_key: "001" # Scene ID +``` + +#### Complex State Calculations +Use namespace objects for accumulating values: +```yaml +{% set ns = namespace(total=0, count=0) %} +{% for entity in entities %} + {% set ns.total = ns.total + states(entity) | float(0) %} + {% set ns.count = ns.count + 1 %} +{% endfor %} +``` + +## Blueprint Categories + +### HVAC & Climate Control +- **hvac-failure-monitor.yaml**: Monitors HVAC performance using temperature differentials +- **fan-management.yaml**: Bathroom fan automation with light triggers +- **fan-cadence.yaml**: Periodic fan cycling with override protection + +### Power & Energy +- **power-monitoring.yaml**: Detects power spikes for appliance identification +- **battery-monitor.yaml**: Multi-device battery level monitoring + +### Smart Switches & Scenes +- **multi-tap-automation.yaml**: Z-Wave switch multi-tap scene control +- **multi-tap-automation-homeseer-and-zooz.yaml**: Enhanced multi-tap with HomeSeer/Zooz support +- **indication.yaml**: HomeSeer WD200+ LED indicator control + +### Security & Utility +- **simulated-presence.yaml**: Random light automation for security +- **state-opposite.yaml**: Bidirectional entity state synchronization + +## Important Implementation Notes + +### Input Validation +- Use proper selector types (number with min/max, boolean, entity with domain filter) +- Always provide defaults to prevent undefined errors +- Use multi-select for flexibility where appropriate + +### Error Handling +- Check entity availability before actions +- Use conditional sequences for optional actions +- Implement proper fallbacks for missing data + +### Performance Considerations +- Use appropriate automation modes (single for exclusive, restart for updates) +- Minimize template complexity in frequently-triggered automations +- Consider using time patterns instead of constant state monitoring + +### Common Issues & Solutions +- **Template errors**: Test in Developer Tools first +- **Entity unavailable**: Add availability checks in conditions +- **Z-Wave events not firing**: Verify device supports Central Scene command class +- **HVAC monitoring false positives**: Adjust temperature thresholds and time windows \ No newline at end of file diff --git a/motion-light-control.yaml b/motion-light-control.yaml new file mode 100644 index 0000000..7d1c83f --- /dev/null +++ b/motion-light-control.yaml @@ -0,0 +1,183 @@ +blueprint: + name: Motion-Activated Light Control + description: > + Turns lights on when motion is detected and keeps them on for a specified duration + after motion stops. Includes an optional quiet hours period where lights will not + turn on automatically (but can still be controlled manually). + + Features: + - Multiple light support + - Configurable timeout after motion stops + - Optional quiet hours (e.g., nighttime) when lights won't turn on + - Brightness control during activation + - Option to only activate when lights are currently off + domain: automation + input: + motion_sensor: + name: Motion Sensor + description: The motion sensor that will trigger the lights + selector: + entity: + domain: binary_sensor + device_class: + - motion + - occupancy + target_lights: + name: Lights to Control + description: The light(s) to turn on when motion is detected + selector: + target: + entity: + domain: light + no_motion_duration: + name: No Motion Duration + description: How long to wait after motion stops before turning lights off + default: 300 + selector: + number: + min: 10 + max: 3600 + unit_of_measurement: seconds + mode: slider + brightness_pct: + name: Brightness Percentage + description: Brightness level when turning on lights (0-100%) + default: 100 + selector: + number: + min: 1 + max: 100 + unit_of_measurement: "%" + mode: slider + enable_quiet_hours: + name: Enable Quiet Hours + description: Enable a period where lights won't turn on automatically + default: false + selector: + boolean: + quiet_hours_start: + name: Quiet Hours Start Time + description: Start of quiet hours (lights won't turn on during this period) + default: "22:00:00" + selector: + time: + quiet_hours_end: + name: Quiet Hours End Time + description: End of quiet hours + default: "06:00:00" + selector: + time: + only_when_off: + name: Only Activate When Lights Are Off + description: Only turn on lights if they are currently off (prevents interference with manual control) + default: true + selector: + boolean: + transition_time: + name: Transition Time + description: Transition time in seconds when turning lights on or off + default: 1 + selector: + number: + min: 0 + max: 10 + unit_of_measurement: seconds + mode: slider + +mode: restart +max_exceeded: silent + +variables: + quiet_hours_enabled: !input enable_quiet_hours + quiet_start: !input quiet_hours_start + quiet_end: !input quiet_hours_end + only_if_off: !input only_when_off + brightness: !input brightness_pct + transition: !input transition_time + lights: !input target_lights + + # Calculate if we're currently in quiet hours + in_quiet_hours: > + {% if quiet_hours_enabled %} + {% set current_time = now().strftime('%H:%M:%S') %} + {% if quiet_start < quiet_end %} + {{ quiet_start <= current_time < quiet_end }} + {% else %} + {{ current_time >= quiet_start or current_time < quiet_end }} + {% endif %} + {% else %} + false + {% endif %} + + # Check if any target lights are currently on + any_lights_on: > + {% set light_entities = [] %} + {% if lights.entity_id is defined %} + {% if lights.entity_id is string %} + {% set light_entities = [lights.entity_id] %} + {% else %} + {% set light_entities = lights.entity_id %} + {% endif %} + {% endif %} + {% if lights.device_id is defined %} + {% for device in lights.device_id %} + {% set light_entities = light_entities + device_entities(device) | select('match', 'light.*') | list %} + {% endfor %} + {% endif %} + {% if lights.area_id is defined %} + {% for area in lights.area_id %} + {% set light_entities = light_entities + area_entities(area) | select('match', 'light.*') | list %} + {% endfor %} + {% endif %} + {% for entity in light_entities %} + {% if states(entity) == 'on' %} + true + {% endif %} + {% else %} + false + {% endfor %} + +trigger: + - platform: state + entity_id: !input motion_sensor + to: "on" + id: motion_detected + - platform: state + entity_id: !input motion_sensor + to: "off" + for: + seconds: !input no_motion_duration + id: motion_stopped + +condition: [] + +action: + - choose: + # Motion detected - turn on lights if conditions are met + - conditions: + - condition: trigger + id: motion_detected + - condition: template + value_template: "{{ not in_quiet_hours }}" + - condition: or + conditions: + - condition: template + value_template: "{{ not only_if_off }}" + - condition: template + value_template: "{{ not any_lights_on }}" + sequence: + - service: light.turn_on + target: !input target_lights + data: + brightness_pct: "{{ brightness }}" + transition: "{{ transition }}" + + # Motion stopped for duration - turn off lights + - conditions: + - condition: trigger + id: motion_stopped + sequence: + - service: light.turn_off + target: !input target_lights + data: + transition: "{{ transition }}" \ No newline at end of file