Beyond Integrations: Mastering `shell_command` and `command_line` for Deep System Control in Home Assistant

NGC 224
DIY Smart Home Creator
Intro: Unlocking Home Assistant's Full Potential with System Commands
While Home Assistant boasts an extensive array of integrations, there are inevitably scenarios where a specific device, service, or system-level task lacks native support. How do you trigger a complex script on your Network Attached Storage (NAS), check the status of a specific process on a remote server, or interact with a custom-built sensor connected to a separate Raspberry Pi via a Python script, all from within your Home Assistant ecosystem?
This is where the often-underestimated shell_command
and command_line
integrations become indispensable. These powerful tools provide a direct conduit to the underlying operating system, allowing Home Assistant to execute arbitrary shell commands or external scripts. They bridge the gap between your smart home platform and virtually any other system, offering unparalleled flexibility for custom solutions, legacy device support, and deep system monitoring. This guide will walk you through leveraging these tools to extend Home Assistant's capabilities far beyond its standard offerings, giving you ultimate control over your digital environment.
Step-by-Step Setup: Integrating External Commands
1. Enabling `shell_command` and `command_line`
Both integrations are straightforward to enable in your configuration.yaml
. Due to their power, Home Assistant implements a security feature: any script or command executed by shell_command
must reside in the config/
directory (or a subdirectory thereof) unless explicitly allowed through a configuration setting. For command_line
, this restriction applies only if the command is a script file. Always consider the security implications of executing arbitrary commands.
# configuration.yaml
shell_command:
# This section declares callable shell commands
command_line:
# This section declares command_line sensors, switches, etc.
2. Basic `shell_command`: Triggering Custom Scripts
shell_command
allows you to define services that execute a shell command. These services can then be called from automations, scripts, or even directly from the Home Assistant UI. It's ideal for tasks like sending custom notifications, triggering external backups, or performing maintenance on other systems.
Example: Sending a Custom Telegram Message via a Script
First, create a simple shell script in config/scripts/send_telegram.sh
:
#!/bin/bash
TOKEN="YOUR_TELEGRAM_BOT_TOKEN"
CHAT_ID="YOUR_TELEGRAM_CHAT_ID"
MESSAGE="$1"
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
-d "chat_id=$CHAT_ID" \
-d "text=$MESSAGE" > /dev/null
Make the script executable: chmod +x /config/scripts/send_telegram.sh
.
Now, define the shell_command
in configuration.yaml
:
# configuration.yaml
shell_command:
send_custom_telegram_message:
'bash /config/scripts/send_telegram.sh "{{ message }}"'
You can then call this service from an automation:
# automation.yaml
- alias: 'Notify on Door Open'
trigger:
platform: state
entity_id: binary_sensor.front_door
to: 'on'
action:
service: shell_command.send_custom_telegram_message
data:
message: 'Front door opened!'
(Screenshot Placeholder: Home Assistant UI showing the shell_command service call in an automation action)
3. Basic `command_line` Sensor: Monitoring System Status
command_line
sensors allow you to periodically execute a command and use its output as a state for an entity. This is perfect for monitoring system metrics, network status, or custom device readings.
Example: Monitoring Disk Usage on the Home Assistant Host
# configuration.yaml
command_line:
- sensor:
name: 'HA Disk Usage'
command: "df -h / | grep -E '^/' | awk '{ print $5 }' | sed 's/%//'"
unit_of_measurement: '%'
value_template: '{{ value | int }}'
scan_interval: 300 # Update every 5 minutes
This command extracts the percentage of disk usage for the root partition. Home Assistant will create a sensor `sensor.ha_disk_usage` that updates every 5 minutes.
(Screenshot Placeholder: Home Assistant UI showing the 'HA Disk Usage' sensor entity)
4. Basic `command_line` Switch: Controlling External Services via SSH
command_line
switches enable Home Assistant to toggle the state of an external system or service. This often involves using SSH for remote execution.
Prerequisites for SSH Control:
- Generate SSH keys on your Home Assistant host:
ssh-keygen -t rsa -b 4096
(if not already done). - Copy the public key to the remote host:
ssh-copy-id -i ~/.ssh/id_rsa.pub user@remote_host
. - Ensure the
user
on the remote host has permissions to run the desired commands (e.g., viasudo
, configured in/etc/sudoers
for specific commands without password).
Example: Toggling a Remote Nginx Service
# configuration.yaml
command_line:
- switch:
name: 'Remote Nginx'
command_on: 'ssh -i /config/.ssh/id_rsa user@remote_host "sudo systemctl start nginx"'
command_off: 'ssh -i /config/.ssh/id_rsa user@remote_host "sudo systemctl stop nginx"'
command_state: 'ssh -i /config/.ssh/id_rsa user@remote_host "systemctl is-active nginx"'
value_template: "{{ value == 'active' }}" # 'active' for on, 'inactive' for off
(Screenshot Placeholder: Home Assistant UI showing the 'Remote Nginx' switch entity)
Troubleshooting Common Issues
Working with `shell_command` and `command_line` often involves debugging external script execution. Here are common pitfalls:
- Permissions: If you see errors like
Permission denied
orcommand not found
, ensure:- The script file (if applicable) has execute permissions (
chmod +x /path/to/script.sh
). - The Home Assistant user has read/execute access to the command/script.
- For SSH, the remote user has permissions for the command, potentially via `sudo` without a password.
- The SSH key path is correct and accessible by the Home Assistant user.
- The script file (if applicable) has execute permissions (
- Full Paths: Always use the full path for commands (e.g.,
/usr/bin/python3
instead ofpython3
,/bin/bash
instead ofbash
). The execution environment for Home Assistant might not have the samePATH
variable as your interactive shell. - Execution Time Limits: Home Assistant imposes a timeout (typically 60 seconds) on commands. Long-running scripts should be backgrounded (e.g.,
&
at the end of the command) or redesigned. If a command times out, it might still be running in the background, consuming resources. - Output Parsing (
value_template
): Ensure your `command_line` scripts produce clean, predictable output. Extra newline characters, spaces, or unexpected error messages can break `value_template` parsing. Test your commands directly in the shell first. - SSH Connection Issues: If remote commands fail, check:
- Network connectivity to the remote host.
- SSH service running on the remote host.
- Correct username and hostname.
- Correct SSH key path and permissions for the private key (
chmod 600 ~/.ssh/id_rsa
). - Firewall rules on both ends.
Advanced Configuration and Optimization
Securing `shell_command` and `command_line`
Given the power of these integrations, security is paramount:
- Restricted Sudo: If using
sudo
for remote commands, configure/etc/sudoers
on the remote machine to allow specific commands without a password for the SSH user. For example:user ALL=(ALL) NOPASSWD: /usr/bin/systemctl start nginx, /usr/bin/systemctl stop nginx, /usr/bin/systemctl is-active nginx
- Dedicated SSH Keys: Use a dedicated SSH key pair for Home Assistant with no passphrase, and only allow it to access specific commands or services on the remote host by appending
command="/path/to/script.sh"
to the key entry in the remote~/.ssh/authorized_keys
file. - `allowlist_external_dirs`: For scripts outside the
config/
directory, explicitly add them to your Home Assistantallowlist_external_dirs
configuration. It's generally safer to keep scripts withinconfig/scripts/
.
Passing Complex Arguments to `shell_command`
Leverage Jinja templating within your shell_command
definition to pass multiple or complex data points.
shell_command:
update_remote_display:
'python3 /config/scripts/update_display.py --temp {{ states("sensor.living_room_temperature") }} --humidity {{ states("sensor.living_room_humidity") }}'
Optimizing `command_line` Sensors
scan_interval
: Adjust thescan_interval
(in seconds) based on how frequently the data changes. Overly frequent polling consumes resources.- Asynchronous Execution: For commands that might take longer, consider wrapping them in a background process if the immediate result isn't crucial, or optimize the script itself. Home Assistant executes
command_line
synchronously, meaning the sensor update will block until the command completes or times out. - Complex Output Parsing: For JSON output, use
jq
within your command, then parse withvalue_template
. For example:command: 'curl -s http://api.example.com/status | jq -r .current_state'
Real-World Example: Proactive Server Uptime and Service Monitoring
Let's build a practical example: monitoring a web server's uptime and critical service status. If the Nginx service fails, Home Assistant will attempt to restart it and notify you.
Scenario: Monitoring and Self-Healing for a Web Server
- Sensor: Monitor the Nginx service status on
my_web_server.example.com
. - Automation: If Nginx goes down, attempt to restart it.
- Notification: If the restart attempt fails, send a critical notification.
Configuration Steps
1. Configure SSH Access: Ensure SSH keys are set up as described earlier, and the `homeassistant` user has passwordless sudo access on `my_web_server` for `systemctl start nginx`, `systemctl stop nginx`, `systemctl is-active nginx`.
2. Define `command_line` Sensor and Switch:
# configuration.yaml
command_line:
- sensor:
name: 'Web Server Nginx Status'
command: 'ssh -i /config/.ssh/id_rsa user@my_web_server.example.com "systemctl is-active nginx"'
value_template: "{{ value == 'active' }}" # True if 'active', False otherwise
scan_interval: 60 # Check every minute
- switch:
name: 'Web Server Nginx Control'
command_on: 'ssh -i /config/.ssh/id_rsa user@my_web_server.example.com "sudo systemctl start nginx"'
command_off: 'ssh -i /config/.ssh/id_rsa user@my_web_server.example.com "sudo systemctl stop nginx"'
command_state: 'ssh -i /config/.ssh/id_rsa user@my_web_server.example.com "systemctl is-active nginx"'
value_template: "{{ value == 'active' }}"
3. Create Automation for Self-Healing and Notification:
# automation.yaml
- alias: 'Web Server Nginx Down Alert and Restart'
trigger:
platform: state
entity_id: sensor.web_server_nginx_status
to: 'False' # Nginx is down
for: '00:01:00' # Wait 1 minute to avoid transient issues
action:
- service: switch.turn_on # Attempt to restart Nginx
entity_id: switch.web_server_nginx_control
- delay: '00:00:10' # Give Nginx time to start
- condition:
condition: state
entity_id: sensor.web_server_nginx_status
state: 'False' # Check if Nginx is STILL down after restart attempt
- service: shell_command.send_custom_telegram_message # Use our earlier defined command
data:
message: 'CRITICAL: Nginx on web server failed to restart! Manual intervention required.'
- service: persistent_notification.create # Also create a persistent HA notification
data:
title: 'CRITICAL: Web Server Issue'
message: 'Nginx on web server failed to restart. Check logs on remote server.'
This setup creates a robust monitoring and self-healing system, notifying you only if the automated restart fails, significantly reducing false alarms and manual intervention.
Best Practices and Wrap-up
While `shell_command` and `command_line` are incredibly powerful, responsible usage is key to a stable and secure smart home:
- Security First: Always limit the scope of commands and user permissions. Never run commands as root without absolute necessity, and restrict SSH keys to specific commands. Regularly review your
/etc/sudoers
andauthorized_keys
files. - Performance Optimization: Minimize the frequency of
command_line
sensor updates. Optimize external scripts for speed. Avoid executing long-running or resource-intensive commands frequently, as they can degrade Home Assistant's performance. - Maintainability and Readability: Centralize your custom scripts in a dedicated directory (e.g.,
config/scripts/
). Comment your YAML configurations clearly, explaining the purpose of each command and its expected output. Use meaningful names for your entities. - Robust Error Handling: Design your external scripts to handle errors gracefully and provide clear exit codes or output that Home Assistant can interpret (e.g., in
value_template
). This helps distinguish between successful execution and command failures. - Logging: Ensure your external scripts log their actions and errors to a file, making debugging much easier when things go wrong.
- Version Control and Backup: Treat your custom scripts and Home Assistant configurations (especially the
shell_command
andcommand_line
sections) as critical code. Use Git for version control and include them in your regular Home Assistant backup strategy.
By mastering `shell_command` and `command_line`, you transform Home Assistant from a smart home hub into a truly universal automation platform capable of interacting with almost any system or device. This empowers you to build highly customized, resilient, and powerful automations tailored precisely to your unique needs.

NGC 224
Author bio: DIY Smart Home Creator