Mastering Custom MQTT Sensors and Switches: Bridging External Scripts to Home Assistant

Represent Mastering Custom MQTT Sensors and Switches: Bridging External Scripts to Home Assistant article
5m read

Intro

Are you a tinkerer looking to pull data from a unique sensor connected to your Raspberry Pi, or perhaps trigger a custom script on your server directly from Home Assistant? Many powerful devices and custom solutions lack direct, pre-built Home Assistant integrations. This is where MQTT (Message Queuing Telemetry Transport) shines. Acting as a lightweight, publish-subscribe messaging protocol, MQTT provides an incredibly flexible bridge, allowing virtually anything that can execute a script to communicate seamlessly with Home Assistant. This guide will walk you through setting up custom MQTT sensors and switches, transforming your shell scripts and external programs into first-class Home Assistant entities.

Setting Up an MQTT Broker (If Needed)

Before diving into custom sensors and switches, ensure you have an MQTT broker running and configured. The Mosquitto broker add-on is highly recommended for Home Assistant OS/Supervised users due to its ease of setup. For other installations (Docker, Core), you can install Mosquitto independently on your network. Make sure Home Assistant's MQTT integration is configured to connect to your broker.

Publishing Custom Sensor Data from a Shell Script

Let's create a custom sensor that reports your Raspberry Pi's CPU temperature. This can be adapted for any script that outputs a single value.

1. Create Your Script

On your Raspberry Pi or host system, create a script (e.g., /config/scripts/get_cpu_temp.sh):

#!/bin/bash
CPU_TEMP=$(vcgencmd measure_temp | egrep -o '[0-9]*\.[0-9]*')
mosquitto_pub -h your_mqtt_broker_ip -p 1883 -u your_mqtt_user -P your_mqtt_password -t 'homeassistant/rpi_cpu/temperature' -m "$CPU_TEMP" -r

Replace your_mqtt_broker_ip, your_mqtt_user, and your_mqtt_password with your MQTT broker details. The -r flag (retain) is crucial, ensuring the last reported value persists even if the broker restarts, so Home Assistant always has a state.

Make the script executable: chmod +x /config/scripts/get_cpu_temp.sh

2. Automate Script Execution

Use Home Assistant's command_line sensor or a cron job to periodically run this script. For simplicity and Home Assistant's awareness, using a command_line sensor is often preferred.

# configuration.yaml
sensor:
  - platform: command_line
    name: RPi CPU Temp Script Runner
    command: "/config/scripts/get_cpu_temp.sh"
    scan_interval: 30 # Run every 30 seconds (adjust as needed)
    unit_of_measurement: '°C' # Optional, for the sensor in HA
    value_template: "{{ value }}" # Required, even if not used directly

Note: The command_line sensor itself isn't directly displaying the temperature; it's merely triggering the script that publishes to MQTT. We still need the MQTT sensor.

3. Configure Home Assistant MQTT Sensor

# configuration.yaml
mqtt:
  sensor:
    - name: "Raspberry Pi CPU Temperature"
      state_topic: "homeassistant/rpi_cpu/temperature"
      unit_of_measurement: "°C"
      value_template: "{{ value | float }}"
      device_class: "temperature"
      state_class: "measurement"

Restart Home Assistant. You should now see a new sensor entity (e.g., sensor.raspberry_pi_cpu_temperature) reporting your CPU temperature.

Controlling a Custom Switch via MQTT and a Shell Script

Now let's create an MQTT switch in Home Assistant that triggers a script on an external system, such as restarting a service or toggling a power outlet controlled by a custom script.

1. Create Your Control Script

On your target system, create a script (e.g., /config/scripts/control_custom_device.sh). This script will subscribe to MQTT and listen for commands.

#!/bin/bash

TOPIC="homeassistant/custom_device/set"
ACTION_ON="ON"
ACTION_OFF="OFF"

# Function to execute when 'ON' command is received
function do_on_action() {
  echo "Custom device ON action triggered."
  # Example: Execute another script or command
  # /path/to/your/on_script.sh
}

# Function to execute when 'OFF' command is received
function do_off_action() {
  echo "Custom device OFF action triggered."
  # Example: Execute another script or command
  # /path/to/your/off_script.sh
}

# Subscribe to the topic and act on messages
mosquitto_sub -h your_mqtt_broker_ip -p 1883 -u your_mqtt_user -P your_mqtt_password -t "$TOPIC" | while read line
do
  if [ "$line" = "$ACTION_ON" ]; then
    do_on_action
    # Publish state back to HA
    mosquitto_pub -h your_mqtt_broker_ip -p 1883 -u your_mqtt_user -P your_mqtt_password -t 'homeassistant/custom_device/state' -m 'ON' -r
  elif [ "$line" = "$ACTION_OFF" ]; then
    do_off_action
    # Publish state back to HA
    mosquitto_pub -h your_mqtt_broker_ip -p 1883 -u your_mqtt_user -P your_mqtt_password -t 'homeassistant/custom_device/state' -m 'OFF' -r
  else
    echo "Received unknown command: $line"
  fi
done

Make it executable: chmod +x /config/scripts/control_custom_device.sh. You'll want to run this script continuously, perhaps using systemd (see Advanced Config).

2. Configure Home Assistant MQTT Switch

# configuration.yaml
mqtt:
  switch:
    - name: "Custom Device Toggle"
      command_topic: "homeassistant/custom_device/set"
      state_topic: "homeassistant/custom_device/state"
      payload_on: "ON"
      payload_off: "OFF"
      # Optional: optimistic: true if you don't receive state feedback immediately
      # initial_state: 'off' # If you want to ensure it starts off
      retain: true # Keep the last state on the broker

Restart Home Assistant. You'll find a new switch entity (e.g., switch.custom_device_toggle). When you toggle it in Home Assistant, your script will receive the 'ON' or 'OFF' command.

Troubleshooting Common Issues

MQTT Connection Errors

Ensure your MQTT broker IP, port, username, and password are correct in all scripts and Home Assistant configurations. Test connectivity directly:

mosquitto_pub -h your_mqtt_broker_ip -t 'test/topic' -m 'hello'
mosquitto_sub -h your_mqtt_broker_ip -t 'test/topic'

If mosquitto_sub doesn't show 'hello', check broker logs and firewall rules.

Script Permissions and Paths

Verify your scripts are executable (chmod +x) and that the paths in Home Assistant's command_line sensor or systemd units are correct.

Payload Mismatches

Ensure the value_template for sensors correctly extracts the value (e.g., float conversion). For switches, payload_on and payload_off must exactly match what your script publishes/subscribes to.

Entity Not Appearing/Updating

Check Home Assistant logs for MQTT-related errors. If using retain: true, try publishing a dummy message to clear an old retained message if unexpected behavior occurs. Verify topics in scripts and HA config match precisely.

Advanced Configuration and Optimization

Using Python for Enhanced Logic

For more complex data processing or device control, replace shell scripts with Python. Python's Paho-MQTT client library offers robust MQTT interaction.

# publish_temp.py
import paho.mqtt.publish as publish
import subprocess
import time

MQTT_BROKER = "your_mqtt_broker_ip"
MQTT_USER = "your_mqtt_user"
MQTT_PASS = "your_mqtt_password"
TOPIC = "homeassistant/rpi_cpu/temperature"

def get_cpu_temperature():
    cmd = "vcgencmd measure_temp"
    output = subprocess.check_output(cmd, shell=True).decode('utf-8')
    temp = float(output.split('=')[1].split("'')[0])
    return temp

if __name__ == "__main__":
    temp = get_cpu_temperature()
    publish.single(TOPIC, str(temp), hostname=MQTT_BROKER, port=1883,
                   auth={'username': MQTT_USER, 'password': MQTT_PASS}, retain=True)
    print(f"Published CPU temperature: {temp}°C")

MQTT Discovery for Automatic Configuration

For a cleaner configuration.yaml, use MQTT Discovery. Your scripts publish a special "discovery" message to a topic like homeassistant/sensor/mydevice/temperature/config, containing the entity's configuration in JSON.

{
  "name": "RPi CPU Temp Discovery",
  "state_topic": "homeassistant/rpi_cpu/temperature",
  "unit_of_measurement": "°C",
  "device_class": "temperature",
  "state_class": "measurement",
  "unique_id": "rpi_cpu_temp_001"
}

Publish this JSON to homeassistant/sensor/mydevice/temperature/config with the -r (retain) flag. Then, your sensor script only needs to publish to homeassistant/rpi_cpu/temperature.

Managing Scripts with Systemd

For daemonized scripts (like the MQTT switch listener), use systemd for robust background execution, automatic restarts, and logging. Create a service file (e.g., /etc/systemd/system/custom_device_control.service):

[Unit]
Description=Custom Device MQTT Control Script
After=network.target

[Service]
ExecStart=/usr/bin/bash /config/scripts/control_custom_device.sh
WorkingDirectory=/config/scripts
StandardOutput=inherit
StandardError=inherit
Restart=always
User=your_user # e.g., pi or ha
Group=your_group # e.g., pi or ha

[Install]
WantedBy=multi-user.target

Then: sudo systemctl enable custom_device_control.service and sudo systemctl start custom_device_control.service.

Real-World Example: Smart Home Server Status Monitor

Imagine you run several services on a dedicated server (Plex, Nextcloud, etc.). You can create a script that checks the status of these services using systemctl is-active <service_name> and publishes "running" or "stopped" to separate MQTT topics. Home Assistant then picks these up as MQTT binary sensors, allowing you to quickly see server health and even automate notifications if a critical service goes down. You could extend this with an MQTT switch to remotely restart a service.

Best Practices and Wrap-up

Security

Always use a dedicated MQTT user with a strong password for Home Assistant and your publishing/subscribing scripts. Consider TLS/SSL encryption for MQTT traffic, especially if your broker is accessible from outside your local network.

Error Handling and Logging

Include error handling in your scripts (e.g., try-except blocks in Python, checking exit codes in bash) and log any issues. systemd will capture script output, making debugging easier.

Resource Efficiency

Avoid excessively frequent updates for sensors unless absolutely necessary. Too many MQTT messages can overwhelm your broker and Home Assistant. Use the scan_interval in command_line sensors judiciously.

Reliability with Retain Flag

Utilize the -r (retain) flag with mosquitto_pub for sensor states and discovery messages. This ensures that Home Assistant receives the last known state immediately upon startup or reconnection, preventing 'unknown' states.

Mastering custom MQTT integrations opens up a world of possibilities for tailoring Home Assistant to your precise needs. Whether it's integrating an obscure device, monitoring a server, or creating unique controls, MQTT provides the robust, flexible backbone for your most innovative smart home projects.

Avatar picture of NGC 224
Written by:

NGC 224

Author bio: DIY Smart Home Creator

There are no comments yet
loading...