This is my attempt at creating a rust-based MQTT client to connect my PC to home assistant. I used go-hass-agent at first, and while it is an extremely mature piece of software, it didn't quite fit my needs and wants.
Fair warning: This app is heavily vibe-coded, and while I have plans to rewrite a lot of it, I am not sure when. For now it works for me, but I can't (yet at least) commit to any further improvements, in case anyone cares.
- Reads configuration from a TOML file
- Connects to MQTT broker with authentication
- Subscribes to multiple topics
- Prints received messages with timestamps
- Automatic reconnection on connection failures
- Home Assistant button integration with auto-discovery
- Execute shell commands via button presses
- Home Assistant switch integration with auto-discovery
- Execute shell commands with state management via switch toggles
- System monitoring with Home Assistant sensor discovery
- CPU load percentage (reported every 60 seconds)
- CPU frequency (if available)
- Memory usage: total RAM, free RAM in GB, and free percentage (reported every 30 seconds)
Edit config.toml to configure the daemon:
hostname = "my-device-01" # Client identifier
mqtt_url = "your.mqtt.broker.com" # MQTT broker URL
mqtt_port = 1883 # MQTT broker port
username = "your_username" # MQTT username
password = "your_password" # MQTT password
topics = [ # List of topics to subscribe to
"sensors/temperature",
"sensors/humidity",
"alerts/motion"
]
update_interval_ms = 5000 # Reconnection interval (ms)
# Home Assistant Buttons (optional)
[[button]]
name = "Suspend" # Button name shown in Home Assistant
exec = "systemctl suspend" # Shell command to execute on button press
[[button]]
name = "Reboot"
exec = "sudo reboot"
[[button]]
name = "Update System"
exec = "sudo apt update && sudo apt upgrade -y"
# Home Assistant Switches (optional)
[[switch]]
name = "Test Switch" # Switch name shown in Home Assistant
exec = "echo Switch state:" # Shell command to execute with "on" or "off" argument
# Alternative: D-Bus switch
[[switch]]
name = "Idle inhibit"
dbus = { service = "org.guayusa.IdleInhibitor", path = "/", interface = "org.guayusa.Idle", method = "SetInhibit" }-
Build the daemon:
cargo build --release
-
Run the daemon:
cargo run
Or run the compiled binary:
./target/release/mqtt-daemon
The daemon automatically publishes Home Assistant discovery messages for configured buttons. When you start the daemon:
- Discovery: The daemon publishes discovery messages to
homeassistant/button/{hostname}_{button_name}/config - Button Creation: Home Assistant automatically creates button entities
- Button Press: When pressed in Home Assistant, it sends "PRESS" to
homeassistant/button/{hostname}_{button_name}/set - Command Execution: The daemon executes the configured shell command
For a device with hostname hp-steffen and a button named Suspend:
- Discovery topic:
homeassistant/button/hp-steffen_suspend/config - Command topic:
homeassistant/button/hp-steffen_suspend/set
The daemon will automatically handle the naming and topic generation.
The daemon supports two types of switch actions:
- Shell Command Switches: Execute shell commands with "on" or "off" arguments
- D-Bus Method Switches: Call D-Bus methods with boolean true/false values
Switch integration follows this flow:
- Discovery: The daemon publishes discovery messages to
homeassistant/switch/{hostname}_{switch_name}/config - Switch Creation: Home Assistant automatically creates switch entities
- Switch Command: When toggled in Home Assistant, it sends "ON" or "OFF" to
homeassistant/switch/{hostname}_{switch_name}/set - Command Execution:
- For
execswitches: The daemon executes the configured shell command with "on" or "off" as an argument - For
dbusswitches: The daemon calls the specified D-Bus method with booleantrue(for "ON") orfalse(for "OFF")
- For
- State Publishing: If the command succeeds, the current state is published to the state topic. If it fails, an empty payload is published.
For a device with hostname rust-daemon and a switch named Test Switch:
- Discovery topic:
homeassistant/switch/rust-daemon_test_switch/config - Command topic:
homeassistant/switch/rust-daemon_test_switch/set - State topic:
homeassistant/switch/rust-daemon_test_switch/state
The app exposes a notifications component that forwards messages to the session dbus. In home assistant, use the notify.send_message action, and use a message like
{"summary":"Hi","message":"Hello, hello, hello", "importance": "low"}
The importance can be omitted and defaults to "normal". The other options are "low" and "high".
The daemon automatically creates Home Assistant sensors for system monitoring:
-
CPU Load: Reports system load average (1-minute) as a percentage
- Topic:
homeassistant/sensor/{hostname}/cpu_load/state - Update interval: 60 seconds
- Unit: %
- Topic:
-
CPU Frequency: Reports current CPU frequency (if available)
- Topic:
homeassistant/sensor/{hostname}/cpu_frequency/state - Update interval: 60 seconds
- Unit: MHz
- Topic:
-
Memory Total: Total system RAM
- Topic:
homeassistant/sensor/{hostname}/memory_total/state - Update interval: 30 seconds
- Unit: GB
- Topic:
-
Memory Free: Available system RAM
- Topic:
homeassistant/sensor/{hostname}/memory_free/state - Update interval: 30 seconds
- Unit: GB
- Topic:
-
Memory Free %: Free memory percentage
- Topic:
homeassistant/sensor/{hostname}/memory_free_pct/state - Update interval: 30 seconds
- Unit: %
- Topic:
All sensors are automatically discovered by Home Assistant and include proper device associations.
To run as a systemd service on Linux:
- Copy the binary to
/usr/local/bin/ - Create a service file at
/etc/systemd/system/mqtt-daemon.service - Enable and start the service
Example service file:
[Unit]
Description=MQTT Daemon
After=network.target
[Service]
Type=simple
User=mqtt-daemon
WorkingDirectory=/opt/mqtt-daemon
ExecStart=/usr/local/bin/mqtt-daemon
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetrumqttc- MQTT client librarytokio- Async runtimeserde- Serialization frameworktoml- TOML parserserde_json- JSON serialization for Home Assistant discoverytracing- Structured loggingtracing-subscriber- Logging output formatting and filtering