Home Assistant Complete Management & Development
The ultimate comprehensive skill for Home Assistant covering:
-
Administration: Configuration analysis, REST API, automation management, entity monitoring
-
Wireless Protocols: Zigbee (ZHA + Zigbee2MQTT), Z-Wave JS, Thread, Matter
-
ESPHome: Full device building with YAML, sensors, GPIO, I2C, SPI, custom components
-
Troubleshooting: Log analysis, automation traces, debug logging, performance tuning
-
Database: Recorder optimization, MariaDB/PostgreSQL, entity filtering, long-term statistics
-
Security: SSL/TLS, authentication, IP banning, secrets management
-
Development: Custom integrations, advanced Jinja2 templating, config flows
-
Dashboards: HACS cards, themes, animations, responsive layouts, floor plans
Session Configuration
CRITICAL: Connection Setup
When the user first requests a Home Assistant operation, collect the necessary connection details:
I need Home Assistant connection details. Please provide what applies:
For Configuration File Access:
- Config Path: Local path OR SSH details to HA config directory
- Local: /config, /homeassistant, or custom path
- SSH: user@host:/path/to/config
For REST API Access (optional but recommended): 2. HA URL: (e.g., http://192.168.1.100:8123 or https://ha.example.com) 3. Long-Lived Access Token: (Create at Profile > Security > Long-Lived Access Tokens)
Example response:
- Config Path: /home/user/homeassistant
- HA URL: http://192.168.1.100:8123
- Token: eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...
After receiving details:
-
Store them in working memory for the session
-
Use for ALL subsequent HA operations without re-prompting
-
NEVER write tokens/credentials to files or logs
Cross-Platform SSH Support
CRITICAL: SSH authentication handling differs by platform.
When accessing Home Assistant configuration via SSH, the method depends on your operating system.
Authentication Priority
-
SSH Keys (RECOMMENDED) - Works on all platforms without additional tools
-
REST API - Works everywhere, preferred for most operations
-
Python SSH Helper - Works on all platforms with paramiko library
-
sshpass - Linux/macOS only (not available on Windows)
Platform-Specific SSH Commands
With SSH Keys (All Platforms):
Direct SSH command - keys are used automatically if configured
ssh -o StrictHostKeyChecking=accept-new user@<HA-HOST> "cat /config/configuration.yaml"
With Password - Windows:
Use Python helper (paramiko-based)
python scripts/ssh_helper.py --host <HA-HOST> --user homeassistant --password "<password>" --command "cat /config/configuration.yaml"
Download config file
python scripts/ssh_helper.py --host <HA-HOST> --user homeassistant --password "<password>" --download /config/configuration.yaml --local-path ./configuration.yaml
With Password - macOS/Linux:
Using sshpass (if installed)
sshpass -p '<password>' ssh -o StrictHostKeyChecking=accept-new user@<HA-HOST> "cat /config/configuration.yaml"
Or use Python helper (cross-platform)
python3 scripts/ssh_helper.py --host <HA-HOST> --user homeassistant --password "<password>" --command "cat /config/configuration.yaml"
Setting Up SSH Keys for Home Assistant
Generate key if you don't have one
ssh-keygen -t ed25519 -C "ha-admin"
For Home Assistant OS (via Terminal add-on or SSH add-on)
Add your public key to the authorized_keys in the SSH add-on configuration
SSH Access by Installation Type
Installation SSH Available Username Config Path
Home Assistant OS Via SSH Add-on root
/config/
Home Assistant Container Via Docker host Host user Mounted path
Home Assistant Core Via host SSH User running HA ~/.homeassistant/
Recommendation: Use the REST API for most operations - it's cross-platform and doesn't require SSH setup.
Quick Reference
File Structure (Home Assistant OS)
/config/ # Main configuration directory ├── configuration.yaml # Primary configuration file ├── automations.yaml # UI-created automations ├── scripts.yaml # UI-created scripts ├── scenes.yaml # UI-created scenes ├── secrets.yaml # Sensitive credentials (NEVER share) ├── known_devices.yaml # Device tracker known devices ├── customize.yaml # Entity customizations ├── home-assistant.log # Current session log ├── home-assistant.log.1 # Previous session log ├── .storage/ # Internal state storage (DO NOT EDIT) │ ├── auth # Authentication data │ ├── core.config_entries # Integration configs │ ├── core.entity_registry # Entity registry │ ├── core.device_registry # Device registry │ └── lovelace # Dashboard configs ├── custom_components/ # HACS and manual integrations ├── www/ # Static web assets ├── blueprints/ # Automation blueprints │ ├── automation/ │ └── script/ ├── packages/ # Package configurations └── tts/ # Text-to-speech cache
REST API Base
Base URL: http://<HA_HOST>:8123/api/ Auth Header: Authorization: Bearer <LONG_LIVED_TOKEN> Content-Type: application/json
Configuration Analysis
Reading Configuration Files
Read main configuration
cat /config/configuration.yaml
Check for syntax errors (via API)
curl -X POST "http://HA_HOST:8123/api/config/core/check_config"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
List all YAML files
find /config -name "*.yaml" -type f
Search for specific configuration
grep -r "sensor:" /config/.yaml grep -r "automation:" /config/.yaml
Configuration Best Practices Check
When analyzing configuration, look for:
-
Secrets Usage: Ensure sensitive data uses !secret references
-
Split Configuration: Large configs should use !include directives
-
Deprecated Syntax: Check for legacy platform syntax vs modern format
-
Proper Indentation: YAML requires consistent spacing (2 spaces recommended)
-
Entity Naming: Consistent, descriptive entity_id patterns
-
Automation Organization: Group related automations logically
Modern vs Legacy Configuration
Modern Format (Preferred):
template:
- sensor:
- name: "My Sensor" state: "{{ states('sensor.source') }}"
Legacy Format (Deprecated):
sensor:
- platform: template sensors: my_sensor: value_template: "{{ states('sensor.source') }}"
REST API Reference
Core Endpoints
Method Endpoint Description
GET /api/
API status check
GET /api/config
Current configuration
GET /api/states
All entity states
GET /api/states/<entity_id>
Specific entity state
POST /api/states/<entity_id>
Set entity state
GET /api/services
Available services by domain
POST /api/services/<domain>/<service>
Call a service
GET /api/events
Event types and listeners
POST /api/events/<event_type>
Fire an event
GET /api/history/period/<timestamp>
Historical states
GET /api/logbook/<timestamp>
Logbook entries
GET /api/error_log
Error log (plain text)
POST /api/template
Render a template
POST /api/config/core/check_config
Validate configuration
GET /api/components
Loaded components
GET /api/calendars
Calendar entities
Common API Operations
Get All Entity States:
curl -s "http://HA_HOST:8123/api/states"
-H "Authorization: Bearer TOKEN" | jq '.'
Get Specific Entity:
curl -s "http://HA_HOST:8123/api/states/light.living_room"
-H "Authorization: Bearer TOKEN" | jq '.'
Call a Service (Turn On Light):
curl -X POST "http://HA_HOST:8123/api/services/light/turn_on"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"entity_id": "light.living_room", "brightness": 255}'
Call a Service (Run Script):
curl -X POST "http://HA_HOST:8123/api/services/script/turn_on"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"entity_id": "script.my_script"}'
Trigger Automation:
curl -X POST "http://HA_HOST:8123/api/services/automation/trigger"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"entity_id": "automation.my_automation"}'
Render Template:
curl -X POST "http://HA_HOST:8123/api/template"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"template": "{{ states("sensor.temperature") }}"}'
Check Configuration:
curl -X POST "http://HA_HOST:8123/api/config/core/check_config"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
Get History:
curl -s "http://HA_HOST:8123/api/history/period/2024-01-01T00:00:00?filter_entity_id=sensor.temperature&end_time=2024-01-02T00:00:00"
-H "Authorization: Bearer TOKEN" | jq '.'
Automation Management
Automation YAML Structure
automation:
-
id: 'unique_automation_id' alias: "Descriptive Automation Name" description: "What this automation does" mode: single # single, restart, queued, parallel
trigger:
- platform: state entity_id: binary_sensor.motion to: 'on'
- platform: time at: '07:00:00'
- platform: sun event: sunset offset: '-00:30:00'
condition:
- condition: state entity_id: input_boolean.automation_enabled state: 'on'
- condition: time after: '06:00:00' before: '23:00:00'
action:
- service: light.turn_on target: entity_id: light.living_room data: brightness_pct: 100
- delay: seconds: 5
- service: notify.mobile_app data: message: "Motion detected!"
Common Trigger Platforms
Platform Use Case Example
state
Entity state changes to: 'on' , from: 'off'
numeric_state
Numeric thresholds above: 25 , below: 10
time
Specific time at: '07:00:00'
time_pattern
Recurring pattern minutes: '/5' (every 5 min)
sun
Sunrise/sunset event: sunset , offset: '-00:30:00'
zone
Location zones entity_id: person.john , zone: zone.home , event: enter
device
Device triggers Device-specific events
webhook
External webhooks webhook_id: 'my_webhook'
event
HA events event_type: 'my_event'
mqtt
MQTT messages topic: 'home/sensor'
template
Template evaluation value_template: "{{ condition }}"
Automation Debugging
Via API - Get automation trace:
curl -s "http://HA_HOST:8123/api/states/automation.my_automation"
-H "Authorization: Bearer TOKEN" | jq '.attributes'
Enable debug logging:
In configuration.yaml
logger: default: info logs: homeassistant.components.automation: debug
Automation Trace (UI):
-
Navigate to Settings > Automations & Scenes
-
Click the automation > Click "Traces" (top right)
-
View step-by-step execution history
Entity Management
Entity Domains
Domain Description Example
light
Lighting control light.living_room
switch
On/off switches switch.garage_door
sensor
Sensor readings sensor.temperature
binary_sensor
Boolean sensors binary_sensor.motion
climate
HVAC/thermostats climate.nest
cover
Blinds/doors/gates cover.garage
fan
Fan control fan.bedroom
media_player
Media devices media_player.tv
camera
Camera feeds camera.front_door
person
Person tracking person.john
device_tracker
Device location device_tracker.phone
input_boolean
Virtual toggles input_boolean.guest_mode
input_number
Virtual numbers input_number.brightness
input_select
Dropdown options input_select.mode
input_text
Text inputs input_text.message
input_datetime
Date/time inputs input_datetime.alarm
group
Entity groups group.all_lights
scene
Preset states scene.movie_time
script
Executable scripts script.morning_routine
automation
Automations automation.sunrise_lights
Template Sensors
template:
-
sensor:
- name: "Average Temperature" unit_of_measurement: "°F" state: > {{ ((states('sensor.living_room_temp') | float) + (states('sensor.bedroom_temp') | float)) / 2 | round(1) }} availability: > {{ states('sensor.living_room_temp') not in ['unknown', 'unavailable'] and states('sensor.bedroom_temp') not in ['unknown', 'unavailable'] }}
-
binary_sensor:
- name: "Anyone Home" state: > {{ is_state('person.john', 'home') or is_state('person.jane', 'home') }} device_class: presence
Helper Entities (Input Helpers)
input_boolean for manual toggles
input_boolean: vacation_mode: name: Vacation Mode icon: mdi:airplane
input_number for adjustable values
input_number: notification_volume: name: Notification Volume min: 0 max: 100 step: 5 unit_of_measurement: "%"
input_select for mode selection
input_select: home_mode: name: Home Mode options: - Home - Away - Night - Guest
Security Auditing
Security Checklist
Run these checks when auditing a Home Assistant installation:
- Secrets File Usage:
Find hardcoded credentials (should use !secret)
grep -rE "(password|api_key|token|secret):" /config/*.yaml | grep -v "!secret"
- secrets.yaml Protection:
Verify secrets.yaml exists and has restricted permissions
ls -la /config/secrets.yaml
Should be: -rw------- (600) or -rw-r----- (640)
- Exposed Ports:
Check what ports HA is listening on
netstat -tulpn | grep -E "(8123|8124)"
- Authentication Review:
Check auth configuration
grep -A 10 "homeassistant:" /config/configuration.yaml
Look for: auth_providers, trusted_networks, ip_ban_enabled
- Add-on Security:
Review add-on configurations for:
- Unnecessary privileged access
- Exposed ports
- Disabled SSL
Security Best Practices
configuration.yaml security settings
homeassistant: auth_providers: - type: homeassistant
Uncomment for trusted networks (use carefully)
auth_providers:
- type: trusted_networks
trusted_networks:
- 192.168.1.0/24
http:
Enable SSL (recommended)
ssl_certificate: /ssl/fullchain.pem ssl_key: /ssl/privkey.pem
IP banning for failed logins
ip_ban_enabled: true login_attempts_threshold: 5
Restrict to local only (if not using remote access)
server_host: 127.0.0.1
Enable recorder purging to manage database size
recorder: purge_keep_days: 10 commit_interval: 1
secrets.yaml Structure
secrets.yaml - NEVER commit this file to git
Add to .gitignore: secrets.yaml
API Keys
openweathermap_api_key: "your-api-key-here" google_api_key: "your-google-key"
Passwords
mqtt_password: "secure-password" influxdb_password: "another-password"
Tokens
telegram_bot_token: "bot123456:ABC-DEF..." pushover_api_token: "your-token"
URLs with credentials
database_url: "mysql://user:pass@localhost/hass"
GPS coordinates (privacy)
home_latitude: 40.7128 home_longitude: -74.0060
Troubleshooting
Log Analysis
View Current Logs:
Via filesystem
tail -f /config/home-assistant.log
Via API
curl -s "http://HA_HOST:8123/api/error_log"
-H "Authorization: Bearer TOKEN"
Enable Debug Logging:
configuration.yaml
logger: default: warning logs: homeassistant.core: debug homeassistant.components.automation: debug homeassistant.components.script: debug custom_components.my_integration: debug
Filter Logs for Specific Component:
grep "homeassistant.components.sensor" /config/home-assistant.log
Common Issues & Solutions
Issue Diagnostic Solution
Entity unavailable Check integration status Restart integration, check device connectivity
Automation not triggering Check automation trace Verify trigger conditions, check if enabled
YAML syntax error Run config check Fix indentation, quote strings properly
Integration not loading Check logs for errors Verify credentials, check network
Database errors Check disk space Purge old data, increase disk
Slow dashboard Check entity count Reduce entities per view, optimize templates
Service call fails Check service parameters Use Developer Tools > Services to test
Configuration Validation
Check configuration via CLI (HA OS)
ha core check
Check configuration via API
curl -X POST "http://HA_HOST:8123/api/config/core/check_config"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
Response on success:
{"result": "valid", "errors": null}
Response on error:
{"result": "invalid", "errors": "Error details..."}
Developer Tools
Access via HA UI: Developer Tools section
Tool Purpose
States View/modify entity states
Services Test service calls
Template Test Jinja2 templates
Events Fire/listen to events
Statistics View long-term statistics
Actions Test action sequences
Zigbee Integration (ZHA & Zigbee2MQTT)
Coordinator Hardware Selection
Coordinator Chip Protocol Recommendation
Home Assistant Connect ZBT-2 EFR32MG21 EZSP Best - Native HA support
Home Assistant Yellow EFR32MG21 EZSP Excellent - Built-in
SONOFF ZBDongle-E EFR32MG21 EZSP Great - Affordable
SONOFF ZBDongle-P CC2652P Z-Stack Great - Popular
SMLIGHT SLZB-07 EFR32MG21 EZSP Great - Ethernet option
ConBee III deCONZ deCONZ Good - Requires deCONZ
CC2531 CC2531 Z-Stack Not recommended - Legacy
USB Placement Critical:
-
Use USB 2.0 ports only (USB 3.x causes RF interference)
-
Use USB extension cable (1-2m) to distance from computer
-
Keep away from WiFi routers, power supplies, SSDs
ZHA (Zigbee Home Automation) Setup
Initial Configuration:
-
Settings > Devices & Services > Add Integration > ZHA
-
Select serial port (use /dev/serial/by-id/ path for stability)
-
Allow network formation (creates PAN ID, channel)
YAML Configuration Options:
configuration.yaml
zha: zigpy_config: network: channel: 15 # Default, don't change unless necessary channels: [15, 20, 25] # Scan channels ota: otau_directory: /config/zigpy_ota ikea_provider: true ledvance_provider: true inovelli_provider: true device_config: # Override device type if misdetected "aa:bb:cc:dd:ee:ff:00:11-1": type: "switch" custom_quirks_path: /config/custom_zha_quirks/
Device Pairing:
Via UI: Settings > Devices & Services > ZHA > Add Device
Put device in pairing mode (usually hold button 5-10 sec)
Via service call (API):
curl -X POST "http://HA_HOST:8123/api/services/zha/permit"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"duration": 60}'
Network Visualization:
-
Settings > Devices & Services > ZHA > Configure > Visualization
-
Shows coordinator, routers, and end devices
-
Color coding: Green (good), Yellow (weak), Red (poor)
ZHA Toolkit (Advanced Operations):
Install via HACS: zha-toolkit
Available services:
service: zha_toolkit.execute data: command: scan_device ieee: "aa:bb:cc:dd:ee:ff:00:11"
Bind devices directly (bypasses HA for faster response)
service: zha_toolkit.bind_ieee data: source_ieee: "aa:bb:cc:dd:ee:ff:00:11" target_ieee: "11:22:33:44:55:66:77:88" cluster: 6 # On/Off cluster
Zigbee2MQTT Setup
Prerequisites:
-
MQTT broker (Mosquitto addon)
-
Zigbee coordinator
Installation:
-
Settings > Add-ons > Add-on Store
-
Add repository: https://github.com/zigbee2mqtt/hassio-zigbee2mqtt
-
Install Zigbee2MQTT addon
-
Configure serial port and MQTT
Configuration (addon config):
serial: port: /dev/serial/by-id/usb-Silicon_Labs_... adapter: ezsp # or zstack for CC2652 mqtt: server: mqtt://core-mosquitto:1883 user: mqtt_user password: mqtt_pass homeassistant: true permit_join: false frontend: port: 8080 advanced: channel: 15 network_key: GENERATE pan_id: GENERATE log_level: info last_seen: ISO_8601
Device Pairing in Z2M:
-
Open Zigbee2MQTT dashboard (sidebar)
-
Click "Permit Join (All)" or specific device
-
Put device in pairing mode
-
Device appears automatically
Z2M vs ZHA Comparison:
Feature ZHA Zigbee2MQTT
Setup Easier (built-in) More steps
Device Support Good Excellent (more quirks)
Configuration Limited YAML Full YAML control
Frontend Basic Rich dashboard
MQTT Required No Yes
Updates With HA Independent
Zigbee Network Optimization
Best Practices:
-
Router Devices: Add mains-powered devices first (they extend mesh)
-
Channel Selection: Stay on channel 15 (default), avoid WiFi overlap
-
Coordinator Placement: Central location, elevated
-
Max Direct Children: ~32 per coordinator, but hundreds via routers
Interference Mitigation:
Check WiFi channel overlap
Zigbee 11 = WiFi 1
Zigbee 15 = WiFi 1-6 (some overlap)
Zigbee 20 = WiFi 6-8
Zigbee 25 = WiFi 11-13
Zigbee 26 = WiFi 12-14
OTA Firmware Updates:
ZHA OTA - automatic for supported devices
Wake battery devices to receive updates
IKEA, Inovelli, Ledvance supported
Check update status in device info
Updates take ~10 minutes per device
Zigbee Troubleshooting
Issue Diagnosis Solution
Device won't pair Too far from coordinator Pair near coordinator, move after
Device drops offline Weak signal/no router nearby Add router device in between
Commands delayed Network congestion Add more routers, check interference
NCP failed state Serial communication lost Check USB connection, restart addon
Entity unavailable Device interview incomplete Remove and re-pair device
Debug Logging:
configuration.yaml
logger: default: warning logs: homeassistant.components.zha: debug zigpy: debug bellows: debug zhaquirks: debug
Z-Wave Integration (Z-Wave JS)
Z-Wave Controller Hardware
Controller Chip Generation Notes
Zooz ZST39 800LR Gen 8 Best - Long Range support
Aeotec Z-Stick 7 700 Gen 7 Excellent
Zooz ZST10 700 Gen 7 Great value
HUSBZB-1 500 Gen 5 Combined Zigbee (legacy)
USB Placement:
- Same as Zigbee: USB 2.0, extension cable, away from interference
Z-Wave JS Setup
Installation:
-
Settings > Add-ons > Z-Wave JS (official addon)
-
Configure serial port
-
Start addon
-
Settings > Devices & Services > Add Integration > Z-Wave
Security Keys (Auto-generated):
Keys stored in addon configuration
S0 Legacy - older secure devices (locks, garage doors)
S2 Unauthenticated - devices that don't verify user
S2 Authenticated - devices requiring PIN entry
S2 Access Control - door locks, secure access
View keys: Settings > Add-ons > Z-Wave JS > Configuration
Device Inclusion:
SmartStart (Preferred for S2 devices):
1. Scan QR code from device
2. Device auto-joins when powered
Classic Inclusion:
1. Settings > Devices & Services > Z-Wave > Add Device
2. Put device in inclusion mode
3. Enter PIN if prompted (for S2)
Exclusion (remove from old network):
1. Click "Remove Device" in Z-Wave panel
2. Put device in exclusion mode
Z-Wave JS UI (Advanced)
Install Z-Wave JS UI addon for:
-
Full network visualization
-
Device parameter configuration
-
Firmware updates
-
Advanced diagnostics
Configuration:
Z-Wave JS UI addon config
serial: port: /dev/serial/by-id/usb-... network_key: # Auto-generated or from old network s0_legacy: # S0 key s2_unauthenticated: # S2 key s2_authenticated: # S2 key s2_access_control: # S2 key
Z-Wave Network Management
Network Healing:
Rebuild routes after moving devices
Settings > Devices & Services > Z-Wave > Heal Network
Or via service:
curl -X POST "http://HA_HOST:8123/api/services/zwave_js/heal_network"
-H "Authorization: Bearer TOKEN"
Device Interview:
Re-interview device to refresh capabilities
service: zwave_js.refresh_value data: entity_id: switch.device_name
Or refresh entire device
service: zwave_js.refresh_node_info data: device_id: device_id_here
Z-Wave Troubleshooting
Issue Diagnosis Solution
Device shows "Dead" Communication lost Check range, heal network
No entities Interview incomplete Wait or re-interview
S2 pairing fails Wrong PIN Check device documentation
Intermittent control Weak mesh Add more nodes, heal network
USB not detected Driver issue Check system logs, try USB 2.0 hub
Debug Logging:
logger: logs: homeassistant.components.zwave_js: debug zwave_js_server: debug
Thread & Matter Integration
Thread Network Setup
Thread Border Router Options:
-
Home Assistant Yellow - Built-in Thread radio
-
Home Assistant Connect ZBT-1/ZBT-2 - USB Thread adapter
-
Apple HomePod Mini - Apple ecosystem
-
Google Nest Hub (2nd gen) - Google ecosystem
OpenThread Border Router Addon:
Install addon: OpenThread Border Router
Configure for Thread radio
Settings > Devices & Services > Thread
View network credentials, preferred network
Thread Credential Sharing:
Share HA Thread network to phone:
Settings > Devices & Services > Thread > Configure
"Send credentials to phone"
Import existing Thread network:
Use Companion App > Settings > Troubleshooting
"Sync Thread credentials"
Matter Integration
Prerequisites:
-
Home Assistant 2023.1+
-
Matter Server addon (auto-installed with integration)
-
Companion App (for commissioning)
-
Thread border router (for Thread devices)
Setup:
-
Settings > Devices & Services > Add Integration > Matter
-
Matter Server addon starts automatically
Device Commissioning:
iOS:
1. HA App > Settings > Devices & Services
2. Add Matter device > "No, it's new"
3. Scan QR code or enter setup code
Android:
1. Same steps as iOS
2. May need to add device to Google Developer Console for test devices
Commissioning can take several minutes
Multi-Admin (Multi-Fabric):
Matter devices support up to 5 controllers
Share from Apple Home or Google Home to HA:
1. In Apple/Google app, get sharing QR code
2. In HA, add Matter device using that code
No factory reset needed!
Matter Device Types Supported:
-
Lights (on/off, dimming, color)
-
Switches and plugs
-
Sensors (temperature, humidity, motion, contact)
-
Locks
-
Thermostats
-
Window coverings
-
Bridges (Philips Hue, etc.)
Thread/Matter Troubleshooting
Issue Solution
"Matter is unavailable" Wait 24h for Google Play Services update, update Companion App
Commissioning fails Ensure phone on same WiFi network as HA
Thread device won't join Verify border router active and nearby
Device shows offline Check Thread network in Thread integration
Can't share to phone Sync Thread credentials via Companion App
Debug Logging:
logger: logs: homeassistant.components.matter: debug homeassistant.components.thread: debug matter_server: debug
ESPHome Device Builder
ESPHome Fundamentals
Installation:
-
Settings > Add-ons > ESPHome (official addon)
-
Open ESPHome dashboard from sidebar
Supported Hardware:
-
ESP8266 (NodeMCU, Wemos D1, Sonoff)
-
ESP32 (DevKit, WROOM, various modules)
-
ESP32-S2, ESP32-S3, ESP32-C3
-
RP2040 (Raspberry Pi Pico W)
YAML Configuration Structure
Basic Device Template:
esphome: name: living-room-sensor friendly_name: Living Room Sensor
esp32: board: esp32dev framework: type: arduino # or esp-idf
wifi: ssid: !secret wifi_ssid password: !secret wifi_password
Fallback hotspot
ap: ssid: "Sensor Fallback" password: "fallback123"
captive_portal:
Enable logging
logger: level: DEBUG
Enable Home Assistant API
api: encryption: key: !secret api_encryption_key
ota:
- platform: esphome password: !secret ota_password
Optional web server
web_server: port: 80
Common Sensor Configurations
DHT Temperature/Humidity:
sensor:
- platform: dht pin: GPIO4 model: DHT22 # or DHT11, AM2302 temperature: name: "Temperature" filters: - offset: -2.0 # Calibration offset humidity: name: "Humidity" update_interval: 60s
BME280 (I2C Temperature/Humidity/Pressure):
i2c: sda: GPIO21 scl: GPIO22 scan: true
sensor:
- platform: bme280_i2c address: 0x76 # or 0x77 temperature: name: "Temperature" oversampling: 16x humidity: name: "Humidity" pressure: name: "Pressure" update_interval: 60s
PIR Motion Sensor:
binary_sensor:
- platform: gpio
pin: GPIO14
name: "Motion"
device_class: motion
filters:
- delayed_off: 30s # Stay on for 30s after motion stops
Door/Window Contact:
binary_sensor:
- platform: gpio pin: number: GPIO5 mode: input: true pullup: true inverted: true name: "Door" device_class: door
Analog Sensor (Moisture/Light):
sensor:
- platform: adc
pin: GPIO34
name: "Soil Moisture"
update_interval: 60s
unit_of_measurement: "%"
filters:
- calibrate_linear:
- 3.3 -> 0.0 # Dry
- 1.5 -> 100.0 # Wet attenuation: 11db
- calibrate_linear:
Ultrasonic Distance:
sensor:
- platform: ultrasonic
trigger_pin: GPIO12
echo_pin: GPIO14
name: "Tank Level"
update_interval: 60s
filters:
- lambda: return (1.0 - x) * 100; # Convert to percentage unit_of_measurement: "%"
Output Configurations
GPIO Switch (Relay):
switch:
- platform: gpio pin: GPIO5 name: "Relay" id: relay1 restore_mode: RESTORE_DEFAULT_OFF
PWM LED/Dimmer:
output:
- platform: ledc pin: GPIO16 id: pwm_output frequency: 1000Hz
light:
- platform: monochromatic name: "LED" output: pwm_output gamma_correct: 2.8
RGB LED Strip (Addressable):
light:
- platform: neopixelbus
type: GRB
variant: WS2812
pin: GPIO5
num_leds: 60
name: "LED Strip"
effects:
- random:
- rainbow:
- color_wipe:
- scan:
Servo Motor:
servo:
- id: my_servo output: pwm_servo
output:
- platform: ledc id: pwm_servo pin: GPIO18 frequency: 50Hz
Control via number component
number:
- platform: template
name: "Servo Position"
min_value: -100
max_value: 100
step: 1
set_action:
- servo.write: id: my_servo level: !lambda 'return x / 100.0;'
Communication Protocols
I2C Bus:
i2c: sda: GPIO21 scl: GPIO22 scan: true id: bus_a frequency: 400kHz
SPI Bus:
spi: clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO19
UART (Serial):
uart: tx_pin: GPIO1 rx_pin: GPIO3 baud_rate: 9600 id: uart_bus
Dallas 1-Wire (DS18B20):
dallas:
- pin: GPIO4
sensor:
- platform: dallas address: 0x1234567890ABCDEF name: "Temperature" resolution: 12
Advanced ESPHome Features
Lambda Expressions:
sensor:
- platform: template name: "Calculated Value" lambda: |- float temp = id(temperature_sensor).state; float hum = id(humidity_sensor).state; // Calculate heat index return temp + (0.5 * (temp + 61.0 + ((temp-68.0)1.2) + (hum0.094))); update_interval: 60s unit_of_measurement: "°F"
Automation (On-Device):
binary_sensor:
- platform: gpio
pin: GPIO14
name: "Motion"
on_press:
- light.turn_on: id: led_light brightness: 100%
- delay: 5min
- light.turn_off: led_light
Time-Based Actions:
time:
- platform: homeassistant
id: ha_time
on_time:
- seconds: 0
minutes: 0
hours: 7
then:
- switch.turn_on: morning_light
- seconds: 0
minutes: 0
hours: 7
then:
Substitutions (Variables):
substitutions: device_name: living-room friendly_name: "Living Room" update_interval: 60s
esphome: name: ${device_name} friendly_name: ${friendly_name}
sensor:
- platform: dht update_interval: ${update_interval}
Packages (Reusable Configs):
common.yaml
wifi: ssid: !secret wifi_ssid password: !secret wifi_password
api: encryption: key: !secret api_key
device.yaml
packages: common: !include common.yaml
esphome: name: my-device
ESPHome Flashing & Updates
Initial Flash (USB):
-
Connect device via USB
-
In ESPHome dashboard, click "Install"
-
Select "Plug into this computer"
-
Choose serial port
OTA Updates (Wireless):
ota:
- platform: esphome password: "secure_ota_password" safe_mode: true
Updates happen automatically when config changes
Or manually: Install > Wirelessly
Secrets Management:
secrets.yaml (in ESPHome config directory)
wifi_ssid: "MyNetwork" wifi_password: "MyPassword" api_encryption_key: "base64_encoded_32_byte_key" ota_password: "ota_secure_pass"
Usage in device config
wifi: ssid: !secret wifi_ssid password: !secret wifi_password
ESPHome Troubleshooting
Issue Solution
Won't connect to WiFi Check credentials, signal strength, 2.4GHz only
API connection fails Check encryption key, firewall
Sensor reads incorrectly Add calibration filters
Device reboots randomly Check power supply (3.3V devices need stable power)
OTA update fails Ensure enough flash space, try safe mode
Compile error Check YAML syntax, pin conflicts
Debug Output:
logger: level: DEBUG # VERBOSE for even more logs: sensor: DEBUG wifi: INFO api: DEBUG
Advanced Troubleshooting
Log Analysis Deep Dive
Log Locations:
Home Assistant OS
/config/home-assistant.log # Current log /config/home-assistant.log.1 # Previous log
Docker
docker logs homeassistant
Core (venv)
~/.homeassistant/home-assistant.log
Log Levels:
configuration.yaml
logger: default: warning # critical, fatal, error, warning, info, debug logs: # Per-component logging homeassistant.core: warning homeassistant.components.automation: debug homeassistant.components.script: debug homeassistant.components.zha: info homeassistant.components.zwave_js: info
# Third-party libraries
zigpy: debug
zwave_js_server: debug
aiohttp: warning
# Custom components
custom_components.my_integration: debug
Real-time Log Monitoring:
Via API
curl -s "http://HA_HOST:8123/api/error_log"
-H "Authorization: Bearer TOKEN"
Via SSH (HA OS)
tail -f /config/home-assistant.log | grep -i error
Via Docker
docker logs -f homeassistant 2>&1 | grep -i error
Log Filtering Patterns:
Find all errors
grep -i "error|exception|traceback" home-assistant.log
Find specific integration issues
grep "homeassistant.components.zha" home-assistant.log
Find startup issues
grep -A 5 "Setup of" home-assistant.log | grep -i "fail|error"
Find automation execution
grep "automation" home-assistant.log | grep -i "triggered|executed"
Automation Debugging
Automation Traces:
-
Settings > Automations & Scenes
-
Click automation > Three-dot menu > Traces
-
View step-by-step execution path
-
Check variable values at each step
Increase Trace Storage:
In automation definition
automation:
- id: my_automation alias: "My Automation" trace: stored_traces: 25 # Default is 5
Template Testing:
Developer Tools > Template
Test Jinja2 expressions before using in automations
Example test:
{{ states('sensor.temperature') | float > 75 }} {{ trigger.to_state.state }} # Only works in automation context
Manual Automation Trigger:
Via API (with conditions)
curl -X POST "http://HA_HOST:8123/api/services/automation/trigger"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"entity_id": "automation.my_auto", "skip_condition": false}'
Via API (skip conditions)
curl -X POST "http://HA_HOST:8123/api/services/automation/trigger"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"entity_id": "automation.my_auto", "skip_condition": true}'
Common Automation Issues:
Issue Diagnosis Solution
Never triggers Check trigger conditions in trace Verify entity_id, states match
Triggers too often Review trigger type Add conditions or throttle
Actions don't execute Check condition block in trace Fix condition logic
Template error Test in Developer Tools Fix Jinja2 syntax
Wrong entity controlled entity_id mismatch Check entity registry
Variables not available Scope issue Use trigger variables correctly
Performance Diagnostics
System Metrics:
Add system monitoring
sensor:
- platform: systemmonitor
resources:
- type: processor_use
- type: memory_use_percent
- type: disk_use_percent arg: /
- type: load_1m
- type: load_5m
- type: network_in arg: eth0
- type: network_out arg: eth0
Entity Count Impact:
Check entity count via API
curl -s "http://HA_HOST:8123/api/states"
-H "Authorization: Bearer TOKEN" | jq 'length'
Target: < 1000 entities for smooth performance
> 2000 entities: Consider recorder optimization
Startup Time Analysis:
Enable startup timing
homeassistant: debug: true
Check logs for:
"Setup of integration X took X.XX seconds"
Database & Recorder Optimization
Recorder Configuration
Basic Optimization:
configuration.yaml
recorder: purge_keep_days: 7 # Reduce from default 10 commit_interval: 5 # Seconds between writes (default 1)
Exclude high-frequency entities
exclude: domains: - automation - updater - camera entity_globs: - sensor.date_* - sensor.time_* - sensor.uptime_* entities: - sensor.last_boot - sun.sun
Aggressive Filtering:
recorder: purge_keep_days: 5 commit_interval: 10
Include only what you need
include: domains: - sensor - binary_sensor - switch - light - climate entities: - person.john - person.jane
Still exclude noisy entities
exclude: entity_globs: - sensor._linkquality - sensor.battery* - sensor.signal
MariaDB Migration (Recommended)
Install MariaDB Addon:
-
Settings > Add-ons > MariaDB
-
Configure with strong password
-
Start addon
Configuration:
configuration.yaml
recorder: db_url: mysql://homeassistant:PASSWORD@core-mariadb/homeassistant?charset=utf8mb4 purge_keep_days: 14 commit_interval: 1
MariaDB Tuning (Advanced):
Custom mariadb options (in addon config)
innodb_buffer_pool_size = 256M innodb_log_file_size = 64M innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT
PostgreSQL Migration
Docker Setup:
docker-compose.yml addition
postgres: image: postgres:15 environment: POSTGRES_DB: homeassistant POSTGRES_USER: homeassistant POSTGRES_PASSWORD: secure_password volumes: - ./postgres_data:/var/lib/postgresql/data
Configuration:
recorder: db_url: postgresql://homeassistant:secure_password@postgres/homeassistant
Long-Term Statistics (InfluxDB)
Use Case: Keep detailed history for years without database bloat
InfluxDB Addon Setup:
-
Install InfluxDB addon
-
Create database and user
-
Configure integration
Configuration:
configuration.yaml
influxdb: host: a0d7b954-influxdb port: 8086 database: homeassistant username: homeassistant password: !secret influxdb_password max_retries: 3
Only send important sensors
include: domains: - sensor entities: - climate.thermostat
Exclude noisy data
exclude: entity_globs: - sensor.*_battery
Database Maintenance
Manual Purge:
Via service call
curl -X POST "http://HA_HOST:8123/api/services/recorder/purge"
-H "Authorization: Bearer TOKEN"
-H "Content-Type: application/json"
-d '{"keep_days": 5, "repack": true}'
Statistics Cleanup:
Remove old statistics
service: recorder.purge_entities data: entity_id: - sensor.old_entity keep_days: 0
Database Size Check (SQLite):
Via SSH
ls -lh /config/home-assistant_v2.db
Should be < 1GB for smooth operation
If larger, increase filtering or migrate to MariaDB
Security Hardening
SSL/TLS Configuration
Let's Encrypt with DuckDNS:
Install DuckDNS addon
Configure with your subdomain and token
configuration.yaml
http: ssl_certificate: /ssl/fullchain.pem ssl_key: /ssl/privkey.pem server_port: 443
Self-Signed Certificate:
Generate certificate
openssl req -x509 -newkey rsa:4096
-keyout /ssl/privkey.pem
-out /ssl/fullchain.pem
-days 365 -nodes
-subj "/CN=homeassistant.local"
configuration.yaml
http: ssl_certificate: /ssl/fullchain.pem ssl_key: /ssl/privkey.pem
Nginx Proxy Manager:
Use NPM addon for SSL termination
Supports Let's Encrypt auto-renewal
Reverse proxy to HA on port 8123
Authentication Hardening
IP Banning:
http: ip_ban_enabled: true login_attempts_threshold: 5
Banned IPs stored in /config/ip_bans.yaml
Trusted Networks:
homeassistant: auth_providers: - type: homeassistant - type: trusted_networks trusted_networks: - 192.168.1.0/24 - 10.0.0.0/8 trusted_users: 192.168.1.100: - user_id_here allow_bypass_login: true # Skip login from trusted networks
Multi-Factor Authentication:
-
Profile > Security > Multi-factor auth modules
-
Enable TOTP (Time-based One-Time Password)
-
Scan QR code with authenticator app
Network Security
Firewall Rules (Linux):
Allow only local network to HA
sudo ufw allow from 192.168.1.0/24 to any port 8123
Block external access
sudo ufw deny 8123
Reverse Proxy Headers:
http: use_x_forwarded_for: true trusted_proxies: - 192.168.1.1 # Your proxy IP - 172.30.33.0/24 # Docker network
Secrets Management Best Practices
secrets.yaml Structure:
/config/secrets.yaml
CRITICAL: Add to .gitignore
API Keys
openweathermap_api: "abc123..." google_api_key: "xyz789..."
Passwords
mqtt_password: "secure_mqtt_pass" mariadb_password: "secure_db_pass" influxdb_password: "secure_influx_pass"
Tokens
telegram_bot_token: "bot123:ABC..." pushover_api_key: "po_key..."
Sensitive URLs
database_url: "mysql://user:pass@host/db"
Coordinates (privacy)
home_latitude: 40.7128 home_longitude: -74.0060 home_elevation: 10
Encryption keys
api_encryption_key: "base64_32_byte_key..."
Environment Variables (Docker):
docker-compose.yml
environment:
- HASS_HTTP_SSL_CERTIFICATE=/ssl/fullchain.pem
- HASS_HTTP_SSL_KEY=/ssl/privkey.pem
Security Audit Checklist
1. Check for hardcoded secrets
grep -rE "(password|api_key|token):" /config/*.yaml | grep -v "!secret"
2. Verify secrets.yaml permissions
ls -la /config/secrets.yaml # Should be 600 or 640
3. Check exposed ports
netstat -tlnp | grep -E "8123|1883|8080"
4. Review auth providers
grep -A 10 "auth_providers" /config/configuration.yaml
5. Check for default passwords
grep -r "password: admin|password: homeassistant" /config/
6. Verify SSL is enabled
grep -A 5 "http:" /config/configuration.yaml | grep ssl
7. Check IP ban status
cat /config/ip_bans.yaml 2>/dev/null || echo "No bans"
Custom Integration Development
Project Structure
custom_components/ └── my_integration/ ├── init.py # Integration setup ├── manifest.json # Integration metadata ├── config_flow.py # UI configuration ├── const.py # Constants ├── sensor.py # Sensor platform ├── switch.py # Switch platform ├── strings.json # English strings └── translations/ └── en.json # Translations
manifest.json
{ "domain": "my_integration", "name": "My Integration", "version": "1.0.0", "documentation": "https://github.com/user/my_integration", "issue_tracker": "https://github.com/user/my_integration/issues", "dependencies": [], "codeowners": ["@username"], "requirements": ["some_library==1.0.0"], "config_flow": true, "iot_class": "local_polling" }
IoT Classes:
-
local_push
-
Device pushes updates
-
local_polling
-
HA polls device locally
-
cloud_push
-
Cloud pushes updates
-
cloud_polling
-
HA polls cloud API
-
calculated
-
Derived from other entities
Basic Integration (init.py)
"""My Integration.""" from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant
DOMAIN = "my_integration" PLATFORMS = ["sensor", "switch"]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up from a config entry.""" hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = entry.data
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) if unload_ok: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok
Config Flow (UI Setup)
"""Config flow for My Integration.""" import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_HOST, CONF_PASSWORD from .const import DOMAIN
class MyIntegrationConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow."""
VERSION = 1
async def async_step_user(self, user_input=None):
"""Handle the initial step."""
errors = {}
if user_input is not None:
# Validate input
try:
# Test connection
await self._test_connection(user_input[CONF_HOST])
except ConnectionError:
errors["base"] = "cannot_connect"
else:
return self.async_create_entry(
title=user_input[CONF_HOST],
data=user_input
)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema({
vol.Required(CONF_HOST): str,
vol.Optional(CONF_PASSWORD): str,
}),
errors=errors,
)
async def _test_connection(self, host):
"""Test connection to device."""
# Implement connection test
pass
Sensor Platform
"""Sensor platform for My Integration.""" from homeassistant.components.sensor import ( SensorEntity, SensorDeviceClass, SensorStateClass, ) from homeassistant.const import UnitOfTemperature
async def async_setup_entry(hass, entry, async_add_entities): """Set up sensor platform.""" async_add_entities([MySensor(entry)])
class MySensor(SensorEntity): """My sensor entity."""
_attr_device_class = SensorDeviceClass.TEMPERATURE
_attr_state_class = SensorStateClass.MEASUREMENT
_attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
def __init__(self, entry):
"""Initialize sensor."""
self._attr_name = "My Temperature"
self._attr_unique_id = f"{entry.entry_id}_temperature"
self._attr_native_value = None
async def async_update(self):
"""Update sensor state."""
# Fetch data from device/API
self._attr_native_value = 21.5
Async Patterns
"""Async data coordinator pattern.""" from datetime import timedelta from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
class MyCoordinator(DataUpdateCoordinator): """Data coordinator for My Integration."""
def __init__(self, hass, client):
"""Initialize coordinator."""
super().__init__(
hass,
_LOGGER,
name="My Integration",
update_interval=timedelta(seconds=30),
)
self.client = client
async def _async_update_data(self):
"""Fetch data from API."""
try:
return await self.client.async_get_data()
except ApiError as err:
raise UpdateFailed(f"Error fetching data: {err}")
Advanced Jinja2 Templating
Template Fundamentals
Testing Templates:
-
Developer Tools > Template
-
Live preview as you type
-
Access to all entities and states
Basic Syntax:
{# Comment - not rendered #} {{ expression }} {# Output expression result #} {% statement %} {# Control flow #}
State Access
{# Get entity state #} {{ states('sensor.temperature') }}
{# Get attribute #} {{ state_attr('sensor.temperature', 'unit_of_measurement') }}
{# Check state #} {{ is_state('light.living_room', 'on') }}
{# Get all attributes #} {{ states.sensor.temperature.attributes }}
{# Last changed timestamp #} {{ states.sensor.temperature.last_changed }}
Filters & Functions
{# Type conversion #} {{ states('sensor.temp') | float }} {{ states('sensor.count') | int }} {{ 'true' | bool }}
{# Math operations #} {{ (states('sensor.temp') | float) * 1.8 + 32 }} {{ states('sensor.value') | float | round(2) }} {{ [1, 2, 3] | sum }} {{ [1, 2, 3] | average }}
{# String operations #} {{ 'hello world' | upper }} {{ 'HELLO' | lower }} {{ 'hello' | capitalize }} {{ 'hello world' | title }} {{ 'text' | replace('e', 'a') }} {{ 'a,b,c' | split(',') }}
{# Date/time #} {{ now() }} {{ now().strftime('%Y-%m-%d %H:%M') }} {{ as_timestamp(now()) }} {{ as_datetime(states('sensor.timestamp')) }} {{ relative_time(states.sensor.motion.last_changed) }}
{# Default values #} {{ states('sensor.maybe_missing') | default('N/A') }} {{ states('sensor.temp') | float(0) }} {# Default if conversion fails #}
Control Structures
{# Conditionals #} {% if is_state('light.living_room', 'on') %} Light is on {% elif is_state('light.living_room', 'unavailable') %} Light is unavailable {% else %} Light is off {% endif %}
{# Ternary operator #} {{ 'Occupied' if is_state('binary_sensor.motion', 'on') else 'Empty' }}
{# Loops #} {% for light in states.light %} {{ light.entity_id }}: {{ light.state }} {% endfor %}
{# Loop with filter #} {% for light in states.light | selectattr('state', 'eq', 'on') %} {{ light.name }} is on {% endfor %}
{# Loop with index #} {% for item in ['a', 'b', 'c'] %} {{ loop.index }}: {{ item }} {% endfor %}
Advanced Templates
Count Entities by State:
{{ states.light | selectattr('state', 'eq', 'on') | list | count }}
{# With area filter #} {{ states.light | selectattr('state', 'eq', 'on') | selectattr('attributes.area_id', 'eq', 'living_room') | list | count }}
List All Entities in State:
{% set on_lights = states.light | selectattr('state', 'eq', 'on') | map(attribute='name') | list %} {{ on_lights | join(', ') if on_lights else 'No lights on' }}
Time-Based Logic:
{% set hour = now().hour %} {% if hour < 6 %}Night {% elif hour < 12 %}Morning {% elif hour < 18 %}Afternoon {% else %}Evening{% endif %}
{# Is it daytime? #} {{ is_state('sun.sun', 'above_horizon') }}
{# Minutes until sunset #} {{ ((as_timestamp(state_attr('sun.sun', 'next_setting')) - as_timestamp(now())) / 60) | round }}
Sensor Aggregation:
{% set temps = [ states('sensor.living_room_temp') | float, states('sensor.bedroom_temp') | float, states('sensor.kitchen_temp') | float ] %} Average: {{ (temps | sum / temps | length) | round(1) }}° Max: {{ temps | max }}° Min: {{ temps | min }}°
Custom Template Sensors
configuration.yaml
template:
-
sensor:
-
name: "Lights On Count" unique_id: lights_on_count state: > {{ states.light | selectattr('state', 'eq', 'on') | list | count }} icon: mdi:lightbulb-group
-
name: "Average Indoor Temperature" unique_id: avg_indoor_temp state: > {% set temps = [ states('sensor.living_room_temp'), states('sensor.bedroom_temp'), states('sensor.office_temp') ] | map('float', 0) | select('>', 0) | list %} {{ (temps | sum / temps | count) | round(1) if temps else 'unknown' }} unit_of_measurement: "°F" device_class: temperature state_class: measurement availability: > {{ states('sensor.living_room_temp') not in ['unavailable', 'unknown'] }}
-
-
binary_sensor:
-
name: "Anyone Home" unique_id: anyone_home state: > {{ states.person | selectattr('state', 'eq', 'home') | list | count > 0 }} device_class: presence
-
name: "Windows Open" unique_id: windows_open state: > {{ states.binary_sensor | selectattr('attributes.device_class', 'eq', 'window') | selectattr('state', 'eq', 'on') | list | count > 0 }} device_class: window
-
Macros (Reusable Functions)
Create in custom_templates/macros.jinja
{% macro light_status(entity) %} {% if is_state(entity, 'on') %} {{ state_attr(entity, 'brightness') | int(0) / 255 * 100 | round }}% {% else %} Off {% endif %} {% endmacro %}
{% macro format_duration(seconds) %} {% set hours = (seconds // 3600) | int %} {% set minutes = ((seconds % 3600) // 60) | int %} {{ hours }}h {{ minutes }}m {% endmacro %}
Using Macros:
configuration.yaml
homeassistant: packages: !include_dir_named packages
In templates, import with:
{% from 'macros.jinja' import light_status, format_duration %}
JavaScript in Button-Card
type: custom:button-card
entity: sensor.temperature
name: |
[[[
return Temperature: ${entity.state}°F;
]]]
icon: |
[[[
const temp = parseFloat(entity.state);
if (temp > 80) return 'mdi:thermometer-alert';
if (temp > 70) return 'mdi:thermometer';
return 'mdi:thermometer-low';
]]]
styles:
icon:
- color: |
[[[
const temp = parseFloat(entity.state);
if (temp > 80) return '#ff5722';
if (temp > 70) return '#ff9800';
if (temp > 60) return '#4caf50';
return '#2196f3';
]]]
card:
- background: |
[[[
const temp = parseFloat(entity.state);
const hue = Math.max(0, Math.min(240, 240 - (temp - 50) * 4));
return hsl(${hue}, 70%, 20%);
]]]
Dashboard Pro - Design & Customization
Dashboard Design Workflow
CRITICAL: When building a new dashboard, first ask the user:
What type of dashboard are you creating?
-
Wall-mounted tablet (10-15" fixed display)
- Larger touch targets, always-visible info
- Optimized for landscape orientation
- Pop-ups for detailed controls
-
Mobile phone (handheld, responsive)
- Compact cards, vertical scrolling
- Bottom navigation for easy thumb access
- Quick glance information
-
Desktop/laptop browser (large screen)
- Multi-column layouts, more data density
- Side-by-side comparisons
- Advanced graphs and charts
-
All devices (fully responsive)
- Uses layout-card with media queries
- Adapts to screen size automatically
HACS Setup (Required for Custom Cards)
Install HACS:
Via SSH to Home Assistant
wget -O - https://get.hacs.xyz | bash -
Or manually download to /config/custom_components/hacs/
Enable in configuration.yaml:
Not required for newer HACS versions, but ensure custom resources work
frontend: extra_module_url: - /hacsfiles/lovelace-card-mod/card-mod.js
Essential HACS Frontend Resources:
Card Purpose Install Priority
card-mod
CSS styling for ANY card Required
mushroom
Clean, modern card collection Required
bubble-card
Pop-ups, buttons, separators Required
button-card
Ultimate customizable buttons Required
layout-card
Responsive grid layouts Required
apexcharts-card
Advanced data visualization High
mini-graph-card
Simple, clean graphs High
stack-in-card
Remove card borders in stacks High
auto-entities
Dynamic entity lists Medium
browser-mod
Browser control, pop-ups Medium
Theme Setup (Dark/Modern Style)
Enable themes in configuration.yaml:
frontend: themes: !include_dir_merge_named themes extra_module_url: - /hacsfiles/lovelace-card-mod/card-mod.js
Recommended Dark Themes (via HACS):
Theme Style Best For
Noctis Dark blue, clean Wall tablets, general use
Waves Noctis + Caule blend Modern dark aesthetic
Bubble Minimalist dark Mobile-first dashboards
Mushroom Soft dark Mushroom card pairing
Caule Black True black AMOLED Battery saving on OLED
iOS Dark Apple-style iOS users
Install Noctis Theme:
-
HACS > Frontend > Search "Noctis"
-
Install and restart HA
-
Profile > Theme > Select "Noctis"
Theme with card-mod enhancements:
themes/noctis.yaml (add card-mod styling)
noctis:
Base colors
primary-color: "#5294E2" accent-color: "#5294E2"
Card styling via card-mod
card-mod-theme: noctis card-mod-card-yaml: | .: | ha-card { border-radius: 12px; box-shadow: none; border: 1px solid rgba(255,255,255,0.1); }
Blur effect on more-info dialogs
card-mod-more-info-yaml: | $: | .mdc-dialog .mdc-dialog__scrim { backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); background: rgba(0,0,0,.6); }
Mushroom Cards (Foundation for Clean UIs)
Available Card Types:
Card Use Case
mushroom-entity-card
General entity display
mushroom-light-card
Light with brightness slider
mushroom-switch-card
Simple toggle
mushroom-fan-card
Fan with speed control
mushroom-cover-card
Blinds/covers with position
mushroom-climate-card
Thermostat control
mushroom-media-player-card
Media controls
mushroom-person-card
Person with location
mushroom-alarm-control-panel-card
Security panel
mushroom-template-card
Fully customizable
mushroom-chips-card
Status chips row
mushroom-title-card
Section headers
Basic Mushroom Light Card:
type: custom:mushroom-light-card entity: light.living_room name: Living Room icon: mdi:ceiling-light use_light_color: true show_brightness_control: true show_color_control: true collapsible_controls: true
Mushroom Chips Card (Status Row):
type: custom:mushroom-chips-card chips:
- type: menu
- type: weather entity: weather.home show_conditions: true show_temperature: true
- type: entity entity: person.john icon: mdi:face-man
- type: entity entity: alarm_control_panel.home
- type: conditional
conditions:
- entity: binary_sensor.front_door state: "on" chip: type: template icon: mdi:door-open icon_color: red content: Door Open!
Mushroom Template Card (Advanced):
type: custom:mushroom-template-card entity: sensor.living_room_temperature primary: Living Room secondary: "{{ states(entity) }}°F" icon: mdi:thermometer icon_color: |- {% set temp = states(entity) | float %} {% if temp > 75 %}red {% elif temp > 70 %}orange {% elif temp < 65 %}blue {% else %}green{% endif %} tap_action: action: more-info card_mod: style: | ha-card { background: linear-gradient(135deg, rgba(82,148,226,0.2), transparent); }
Bubble Card (Pop-ups & Modern Buttons)
Card Types:
-
pop-up
-
Full-screen overlay for detailed controls
-
button
-
Versatile button with sub-buttons
-
separator
-
Visual dividers
-
horizontal-buttons-stack
-
Row of buttons
-
cover
-
Cover/blind controls
-
media-player
-
Media controls
-
empty-column
-
Spacing
Pop-up Setup:
Step 1: Create pop-up card (place at TOP of view)
type: custom:bubble-card card_type: pop-up hash: '#living-room' name: Living Room icon: mdi:sofa bg_color: var(--primary-color) bg_opacity: 0.8
Optional: blur background
styles: | .bubble-pop-up-container { backdrop-filter: blur(10px); }
Step 2: Add content cards inside the pop-up
cards:
- type: custom:mushroom-light-card entity: light.living_room
- type: custom:mushroom-climate-card entity: climate.living_room
Button with Sub-buttons:
type: custom:bubble-card card_type: button button_type: state entity: light.living_room name: Living Room icon: mdi:sofa show_state: true card_layout: large sub_button:
- name: Ceiling icon: mdi:ceiling-light entity: light.ceiling show_state: true tap_action: action: toggle
- name: Lamp icon: mdi:lamp entity: light.lamp show_state: true tap_action: action: toggle
- name: LED Strip icon: mdi:led-strip entity: light.led_strip show_background: false tap_action: action: toggle
Navigation Button to Pop-up:
type: custom:bubble-card card_type: button button_type: name name: Living Room icon: mdi:sofa tap_action: action: navigate navigation_path: '#living-room' styles: | .bubble-icon-container { background: linear-gradient(135deg, #667eea, #764ba2) !important; }
Horizontal Button Stack:
type: custom:bubble-card card_type: horizontal-buttons-stack buttons:
- name: Living icon: mdi:sofa tap_action: action: navigate navigation_path: '#living-room'
- name: Kitchen icon: mdi:silverware-fork-knife tap_action: action: navigate navigation_path: '#kitchen'
- name: Bedroom icon: mdi:bed tap_action: action: navigate navigation_path: '#bedroom'
Button-Card (Ultimate Customization)
Basic Button:
type: custom:button-card entity: light.living_room name: Living Room icon: mdi:ceiling-light show_state: true tap_action: action: toggle styles: card: - border-radius: 12px - background-color: var(--card-background-color) icon: - color: var(--primary-color)
Button with State-based Styling:
type: custom:button-card entity: light.living_room name: Living Room icon: mdi:ceiling-light show_state: true color_type: icon state:
- value: "on" color: gold styles: card: - background: linear-gradient(to bottom, rgba(255,215,0,0.3), transparent) icon: - animation: pulse 2s ease-in-out infinite
- value: "off" color: gray styles: card: - background: var(--card-background-color)
Button-Card Templates (Reusable Styles):
Create in ui-lovelace.yaml or button_card_templates.yaml :
button_card_templates:
Base template for all room cards
room_card: show_state: true show_name: true show_icon: true color_type: icon tap_action: action: navigate styles: card: - border-radius: 16px - padding: 16px - background: var(--card-background-color) grid: - grid-template-areas: '"i n" "i s"' - grid-template-columns: 40% 1fr - grid-template-rows: min-content min-content icon: - width: 50px - color: var(--primary-color) name: - font-size: 16px - font-weight: bold - justify-self: start state: - font-size: 12px - justify-self: start - color: var(--secondary-text-color)
Light button with animated icon when on
light_button: template: room_card state: - value: "on" styles: icon: - color: gold - filter: drop-shadow(0 0 10px gold) card: - background: linear-gradient(135deg, rgba(255,215,0,0.2), transparent)
Temperature sensor with color coding
temp_sensor:
show_state: true
show_name: true
show_icon: true
state_display: '[[[ return ${entity.state}°F ]]]'
styles:
icon:
- color: |
[[[
var temp = parseFloat(entity.state);
if (temp > 80) return '#ff5722';
if (temp > 75) return '#ff9800';
if (temp > 70) return '#4caf50';
if (temp > 65) return '#03a9f4';
return '#2196f3';
]]]
Using Templates:
type: custom:button-card template: light_button entity: light.living_room name: Living Room tap_action: action: navigate navigation_path: '#living-room'
Card-Mod (CSS Styling for ANY Card)
Basic Styling:
type: entities entities:
- entity: light.living_room card_mod: style: | ha-card { background: linear-gradient(135deg, #1a1a2e, #16213e); border-radius: 16px; border: 1px solid rgba(255,255,255,0.1); box-shadow: 0 8px 32px rgba(0,0,0,0.3); }
Animate Icons Based on State:
type: custom:mushroom-entity-card entity: fan.bedroom card_mod: style: mushroom-shape-icon$: | .shape { {% if is_state('fan.bedroom', 'on') %} --shape-animation: spin 1s linear infinite; {% endif %} } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
Glassmorphism Effect:
card_mod: style: | ha-card { background: rgba(255, 255, 255, 0.05) !important; backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; }
Conditional Styling with Jinja2:
card_mod: style: | ha-card { {% if is_state('binary_sensor.motion', 'on') %} border: 2px solid #ff9800; animation: pulse 1s ease-in-out infinite; {% else %} border: 1px solid rgba(255,255,255,0.1); {% endif %} } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.7; } }
Card-Mod in Themes (Apply Globally):
themes/my-theme.yaml
my-theme: card-mod-theme: my-theme
Style all cards
card-mod-card-yaml: | .: | ha-card { border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.2); }
Style the sidebar
card-mod-root-yaml: | ha-sidebar { background: #1a1a2e !important; }
Layout-Card (Responsive Grids)
Basic Grid Layout:
type: custom:layout-card layout_type: grid layout: grid-template-columns: repeat(3, 1fr) grid-gap: 16px cards:
- type: custom:mushroom-light-card entity: light.living_room
- type: custom:mushroom-light-card entity: light.kitchen
- type: custom:mushroom-light-card entity: light.bedroom
Responsive Layout with Media Queries:
type: custom:layout-card layout_type: grid layout: grid-template-columns: repeat(4, 1fr) grid-gap: 16px mediaquery: # Tablet (768px - 1024px) "(max-width: 1024px)": grid-template-columns: repeat(3, 1fr) # Large phone (480px - 768px) "(max-width: 768px)": grid-template-columns: repeat(2, 1fr) # Small phone (< 480px) "(max-width: 480px)": grid-template-columns: 1fr cards:
- type: custom:mushroom-light-card entity: light.living_room
... more cards
Grid with Spanning Cards:
type: custom:layout-card layout_type: grid layout: grid-template-columns: repeat(4, 1fr) grid-template-rows: auto grid-gap: 16px cards:
Weather spans 2 columns
- type: weather-forecast entity: weather.home view_layout: grid-column: span 2
Graph spans full width
- type: custom:mini-graph-card
entities:
- sensor.temperature view_layout: grid-column: span 4
Regular cards
- type: custom:mushroom-light-card entity: light.living_room
ApexCharts Card (Advanced Data Visualization)
Basic Line Chart:
type: custom:apexcharts-card header: show: true title: Temperature History show_states: true colorize_states: true graph_span: 24h series:
- entity: sensor.living_room_temperature name: Living Room stroke_width: 2 color: '#5294E2'
- entity: sensor.outdoor_temperature name: Outside stroke_width: 2 color: '#ff9800'
Radial Bar (Gauge Style):
type: custom:apexcharts-card chart_type: radialBar header: show: false series:
- entity: sensor.cpu_usage name: CPU color: '#5294E2' apex_config: plotOptions: radialBar: hollow: size: '60%' dataLabels: name: show: true fontSize: '14px' value: show: true fontSize: '24px'
Energy Usage (Area Chart with Gradient):
type: custom:apexcharts-card header: show: true title: Energy Today show_states: true graph_span: 24h span: start: day series:
- entity: sensor.energy_usage type: area stroke_width: 2 color: '#4CAF50' opacity: 0.3 curve: smooth statistics: type: state period: hour apex_config: chart: height: 200 fill: type: gradient gradient: shadeIntensity: 0.8 opacityFrom: 0.7 opacityTo: 0.2
Multi-Series with Comparison:
type: custom:apexcharts-card header: show: true title: Temperature Comparison graph_span: 7d span: start: week series:
- entity: sensor.indoor_temp name: Indoor group_by: func: avg duration: 1d
- entity: sensor.outdoor_temp name: Outdoor group_by: func: avg duration: 1d apex_config: chart: type: bar plotOptions: bar: horizontal: false columnWidth: '60%'
Mini-Graph-Card (Simple Clean Graphs)
Basic Graph:
type: custom:mini-graph-card entities:
- sensor.living_room_temperature name: Living Room Temp hours_to_show: 24 points_per_hour: 2 line_width: 2
Multiple Entities with Styling:
type: custom:mini-graph-card entities:
- entity: sensor.living_room_temp name: Living Room color: '#5294E2'
- entity: sensor.bedroom_temp name: Bedroom color: '#ff9800' show_state: true state_adaptive_color: true name: Home Temperatures hours_to_show: 24 line_width: 2 font_size: 75 show: labels: true labels_secondary: true extrema: true average: true fill: fade
Bar Graph for Daily Stats:
type: custom:mini-graph-card entities:
- entity: sensor.daily_energy name: Energy hours_to_show: 168 aggregate_func: max group_by: date show: graph: bar state: true name: true
Floor Plan Dashboard (Picture Elements)
Basic Floor Plan Setup:
type: picture-elements image: /local/floorplan/home.png elements:
Light icons
- type: state-icon entity: light.living_room tap_action: action: toggle style: top: 45% left: 30% "--paper-item-icon-active-color": gold
Temperature label
- type: state-label entity: sensor.living_room_temp style: top: 50% left: 30% color: white font-size: 12px
Room navigation
- type: icon icon: mdi:sofa tap_action: action: navigate navigation_path: '#living-room' style: top: 55% left: 30% color: var(--primary-color)
Interactive Floor Plan with Overlays:
type: picture-elements image: /local/floorplan/home_dark.png elements:
Light overlay (shows when on)
- type: image entity: light.living_room tap_action: action: toggle state_image: "on": /local/floorplan/overlays/living_room_light.png "off": /local/floorplan/transparent.png style: top: 50% left: 50% width: 100% opacity: 0.6
Motion indicator
- type: conditional
conditions:
- entity: binary_sensor.living_room_motion state: "on" elements:
- type: icon icon: mdi:motion-sensor style: top: 40% left: 35% color: '#ff9800' "--mdc-icon-size": 24px
3D Floor Plan Tips:
-
Create in SweetHome3D (free software)
-
Export as PNG with transparent background
-
Create "light on" overlays for each room
-
Use conditional elements for dynamic states
-
Layer images for lighting effects
Animations & Effects
Spinning Icon (Fan, Loading):
card_mod: style: mushroom-shape-icon$: | .shape { --shape-animation: spin 1s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
Pulsing Glow (Alerts):
card_mod: style: | ha-card { animation: glow 2s ease-in-out infinite; } @keyframes glow { 0%, 100% { box-shadow: 0 0 5px rgba(255,152,0,0.5); } 50% { box-shadow: 0 0 20px rgba(255,152,0,0.8); } }
Color Transition:
card_mod: style: | ha-card { transition: background-color 0.3s ease, transform 0.2s ease; } ha-card:hover { transform: translateY(-2px); background-color: rgba(255,255,255,0.1); }
Breathing Effect:
card_mod: style: | ha-card { animation: breathe 3s ease-in-out infinite; } @keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.85; } }
Gradient Animation:
card_mod: style: | ha-card { background: linear-gradient(270deg, #667eea, #764ba2, #f093fb); background-size: 600% 600%; animation: gradientShift 10s ease infinite; } @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
Complete Dashboard Examples
Mobile-First Home View:
title: Home views:
-
title: Home path: home type: custom:layout-card layout_type: grid layout: grid-template-columns: 1fr grid-gap: 8px mediaquery: "(min-width: 768px)": grid-template-columns: repeat(2, 1fr) "(min-width: 1200px)": grid-template-columns: repeat(3, 1fr) cards:
Status chips at top
- type: custom:mushroom-chips-card
chips:
- type: weather entity: weather.home
- type: entity entity: person.john
- type: entity entity: alarm_control_panel.home view_layout: grid-column: 1 / -1
Room cards
- type: custom:mushroom-template-card entity: light.living_room primary: Living Room secondary: "{{ states('sensor.living_room_temp') }}°F" icon: mdi:sofa tap_action: action: navigate navigation_path: '#living-room'
More room cards...
- type: custom:mushroom-chips-card
chips:
Tablet Wall Dashboard:
title: Wall Panel views:
- title: Main
path: main
panel: true
cards:
-
type: custom:layout-card layout_type: grid layout: grid-template-columns: 2fr 1fr grid-template-rows: auto 1fr grid-gap: 16px height: 100vh cards:
Left side - Floor plan
- type: picture-elements
image: /local/floorplan.png
view_layout:
grid-row: span 2
elements:
... floor plan elements
Right side - Quick controls
- type: vertical-stack
cards:
- type: custom:mushroom-chips-card
... chips
- type: horizontal-stack
cards:
... room buttons
- type: custom:mushroom-chips-card
Right side bottom - Weather & info
- type: vertical-stack
cards:
- type: weather-forecast entity: weather.home
- type: custom:mini-graph-card
entities:
- sensor.outdoor_temp
- type: picture-elements
image: /local/floorplan.png
view_layout:
grid-row: span 2
elements:
-
Dashboard YAML Mode Setup
Enable YAML Mode:
configuration.yaml
lovelace: mode: yaml resources: - url: /hacsfiles/button-card/button-card.js type: module - url: /hacsfiles/lovelace-card-mod/card-mod.js type: module - url: /hacsfiles/lovelace-mushroom/mushroom.js type: module - url: /hacsfiles/bubble-card/bubble-card.js type: module - url: /hacsfiles/lovelace-layout-card/layout-card.js type: module - url: /hacsfiles/apexcharts-card/apexcharts-card.js type: module - url: /hacsfiles/mini-graph-card/mini-graph-card-bundle.js type: module
Dashboard Structure:
ui-lovelace.yaml
title: My Home button_card_templates: !include button_card_templates.yaml views:
- !include views/home.yaml
- !include views/lights.yaml
- !include views/climate.yaml
- !include views/security.yaml
Dashboard Troubleshooting
Issue Solution
Custom card not showing Clear browser cache, check Resources in dashboard settings
card-mod styles not working Ensure card-mod is loaded as module, check Shadow DOM paths
Pop-up not opening Verify hash matches exactly (case-sensitive)
Layout not responsive Check mediaquery syntax, use browser dev tools to test
Animations choppy Reduce animation complexity, check device performance
Theme not applying Restart HA after theme changes, check YAML syntax
Icons not spinning Use correct Shadow DOM selector for card type
Graphs not loading Check entity exists, verify time range has data
Backup & Restore
Backup Locations
HA OS - Full backup
/backup/
Manual backup targets
/config/ # All configuration /config/.storage/ # Entity/device registries /config/custom_components/ # Custom integrations
Backup Commands
Cross-Platform (Python - Recommended for Windows):
Use the Python backup script (works on Windows, macOS, Linux)
python scripts/backup.py /path/to/config
Specify custom backup destination
python scripts/backup.py /path/to/config /path/to/backups
Windows example
python scripts/backup.py C:\Users\user\homeassistant C:\backups
The script automatically:
- Excludes logs, databases, cache files
- Creates timestamped .tar.gz archives
- Cleans up old backups (keeps last 10)
- Shows compression statistics
macOS/Linux (Bash):
Create config backup
tar -czvf ha-config-backup-$(date +%Y%m%d).tar.gz
--exclude='home-assistant.log*'
--exclude='.storage'
--exclude='tts'
/config/
Backup with storage (includes registries)
tar -czvf ha-full-backup-$(date +%Y%m%d).tar.gz /config/
Or use the bash script (macOS/Linux only)
bash scripts/backup.sh /path/to/config
Restore Process
-
Stop Home Assistant
-
Backup current config (safety)
-
Extract backup to /config/
-
Restart Home Assistant
-
Verify all integrations load
Installation-Specific Notes
Home Assistant OS (Recommended)
-
Full Supervisor support
-
Add-ons available
-
Config at /config/ or /homeassistant/
-
SSH via Terminal add-on or SSH add-on
Home Assistant Container (Docker)
-
No Supervisor/Add-ons
-
Config mounted from host
-
Example: -v /path/to/config:/config
Home Assistant Core (Python venv)
-
Manual Python installation
-
No Supervisor/Add-ons
-
Config typically at ~/.homeassistant/
When to Use This Skill
Configuration & Administration:
-
"Check my Home Assistant configuration"
-
"Find YAML errors in my config"
-
"What's the state of my living room lights?"
-
"Turn on the bedroom fan"
-
"Create an automation for motion lights"
-
"Debug why my automation isn't working"
-
"Review my HA security settings"
-
"Help me set up a template sensor"
-
"What's in my Home Assistant logs?"
-
"Backup my Home Assistant configuration"
-
"List all my entities"
-
"Call a service via the API"
Dashboard Design & Customization:
-
"Create a beautiful dashboard for my tablet"
-
"Help me design a mobile-friendly dashboard"
-
"Set up Mushroom cards for my lights"
-
"Create pop-ups using Bubble Card"
-
"Make my cards have animations"
-
"Set up a dark theme with Noctis"
-
"Create a floor plan dashboard"
-
"Add graphs for my temperature sensors"
-
"Make my dashboard responsive for all devices"
-
"Style my cards with custom CSS"
-
"Create reusable button-card templates"
-
"Set up ApexCharts for energy monitoring"
-
"Add spinning icons when my fan is on"
-
"Create a glassmorphism effect on my cards"
When NOT to Use This Skill
-
ESPHome device configuration (use ESPHome skill)
-
Zigbee/Z-Wave device pairing (use HA UI)
-
Network/router configuration (use network tools)
-
Creating 3D floor plan images (use SweetHome3D or similar)
Additional Resources
-
REST API Reference - Complete API endpoint documentation
-
Helper Scripts - Cross-platform Python scripts:
-
ha_client.py
-
REST API client library
-
config_audit.py
-
Configuration security auditor
-
backup.py
-
Cross-platform backup (Windows/macOS/Linux)
-
backup.sh
-
Bash backup script (macOS/Linux only)
-
ssh_helper.py
-
Cross-platform SSH with password auth
-
Official HA Docs
-
HA Developer Docs
-
HA Community