Hermes: Meshtastic
Commander
Home Assistant integration bridging a Meshtastic mesh radio and the home: authorized nodes send text commands that run actions and get a reply, and Home Assistant sends broadcast notifications onto the mesh from automations. All configured from the card, no YAML. Distributed via HACS.
What it is
Hermes is a Home Assistant integration that bridges a Meshtastic mesh radio and the smart home. It carries text across the boundary between two worlds, in both directions:
- Commands coming in from the mesh: an authorized node sends a keyword, Hermes runs the Home Assistant action mapped to it and replies over the radio.
- Notifications going out onto the mesh: the
hermes.broadcastandhermes.send_directservices can be called from any automation, including scheduled ones, so alarms, events and reminders reach people with no phone signal.
It’s an application layer on top of the official Meshtastic integration: it doesn’t manage the node connection (TCP, serial or BLE), it listens to its events and uses its services. All configuration happens from the card, with no hand-written YAML, no raw Jinja2 and no Lovelace resource to add.
Why the name Hermes
Hermes (Greek Ἑρμῆς, the Roman Mercury) is the god of messengers, travelers, boundaries and communication, the herald who carries messages between worlds and crosses every frontier with his winged helmet and sandals. The name fits literally: Hermes is a herald that carries text across a boundary, turning the commands coming in from the LoRa mesh into home actions and carrying the home’s notifications back out onto the radio network.
The name sits alongside its sibling project Chronos, from the same Greek-deity naming line.
What it does
Commands built by clicking. Commands are built by picking an entity and clicking: Read buttons insert a live value into the reply, Do buttons run something. You never type a service name, and values are offered within the range the device actually accepts.
Byte-safe split. Every outgoing message is split to fit the Meshtastic payload, with a (1/3) header, never cutting a multi-byte character in half.
Silence by default. A node whitelist gates commands, and unauthorized senders get no reply at all, since answering would confirm that a Home Assistant is listening.
The card
One card holds everything you need for the mesh, in tabs:
| Tab | What it holds |
|---|---|
| Status | Whether messages get through and why not, the gateway radio, counters |
| Chat | Conversations by channel and by node, with replies sent from here |
| Log | What Hermes decided about each message, including the ones it ignored |
| Devices | Every node with battery, signal, hops and last heard |
| Map | Nodes as points, optionally the whole mesh, with a radius filter |
| Messages | Building commands and quick-send presets |
| Home Assistant | Which entities your commands use, and whether they still exist |
| Settings | Everything configurable, the radio included |
Two more cards ship alongside the main one, for a dashboard you already use for something else: Hermes summary (the state as a list of parameters that reflows to one value per line when the column is narrow) and Hermes chat (reading and sending messages). Both take only the height they need and change no setting.
Security
The principle behind it all: a channel tells you things, a direct message changes them.
On a channel the only protection is the shared key: messages carry a sender but nothing proves it, so anyone holding the key can claim to be any node, and there the authorized-nodes list is a weak defence. On a direct message with PKC (firmware 2.5 and later) the sender is verified by the protocol before the message reaches Home Assistant, and the list means what it says.
The recommended shape is two instances: status queries on a channel, anything that acts on direct messages. Adding the integration twice costs nothing, and it keeps a leaked channel key from becoming someone else’s control of your house. A command runs as Home Assistant itself, with no user and no confirmation, so the command list is the permission list: the sender never supplies a service, an entity or a template; the only thing a message contributes is the keyword and, where allowed, one number, parsed strictly and range checked.
From v1.2 this guarantee is no longer just theoretical: by reading the packet metadata, Hermes can enforce that only messages encrypted for this node (PKC) get through, refuse ones bridged over MQTT and drop ones too old or already handled, with a condition entity and a cooldown to stop replays. The switches start off, since they depend on fields the firmware and base integration must report, and the Status tab shows what the arriving messages actually carried, so you confirm before relying on them.
Services
Scheduling is achieved by composing standard Home Assistant automations with these services; there is no internal scheduler.
| Service | Description |
|---|---|
hermes.broadcast |
Sends a message on the instance’s channel or DM |
hermes.send_direct |
Sends a direct message to a single node |
Both pass through the byte-safe split engine (up to 200 bytes per part, (i/n) header, no multi-byte character cut in half).
Requirements and installation
Hermes works on top of the official Meshtastic integration (domain: meshtastic), which has to be installed and connected first: it owns the connection to the radio, and only one integration can hold it. You need firmware with PKC (≥ 2.5) if you want to use DMs as a trustworthy channel.
Installation is via HACS with the My Home Assistant badges (one click opens HACS with the repository pre-filled, another starts the config flow). The card registers itself, so there’s no Lovelace resource to add by hand, and a Panel (1 card) view suits it best, since it fills the screen.
Status
Hermes has reached its first stable release (1.0), with the split engine covered by tests (it’s pure Python, verifiable without Home Assistant). Some values (send timing, byte limit, the base integration’s event schema) remain reasonable defaults to tune on the real radio hardware, as noted in the repository docs.
License
Distributed under the MIT license.