Messaging
The Meshcore Home Assistant integration provides comprehensive messaging capabilities for your mesh network, including sending, receiving, and logging messages.
Message Flow
Sending Messages
Messages can be sent using the integration's services:
- Direct Messages - Send to specific nodes by name or public key
- Channel Messages - Broadcast to all nodes on a channel
When you send a message:
- The service validates the recipient and message
- The message is transmitted via the Meshcore device
- A
meshcore_message_sentevent is fired - The message appears in the Home Assistant logbook
Receiving Messages
When messages are received:
- Raw SDK events (
EventType.CONTACT_MSG_RECVorEventType.CHANNEL_MSG_RECV) are processed - Contact information is resolved (name lookup from public key)
- A
meshcore_messageevent is fired with simplified data - The message is logged to the Home Assistant logbook
- Binary sensor entities track message activity
RX_LOG Correlation
When a channel message is received over the mesh network, it may arrive via multiple paths — directly from the sender and relayed through one or more repeaters. Each reception generates an RX_LOG entry containing radio metrics: signal-to-noise ratio (SNR), received signal strength (RSSI), hop count, and the routing path taken.
The integration automatically correlates these RX_LOG entries with the corresponding meshcore_message event and attaches them as rx_log_data. This gives automations and bots visibility into how a message traveled through the mesh.
Default Mode (Fixed Wait)
By default, the integration waits a fixed 500ms after receiving a channel message before firing the meshcore_message event. During this window, RX_LOG entries from repeater relays accumulate. After 500ms, all collected entries are attached to the event as rx_log_data.
This mode is simple and predictable. All available path data is present on the initial event, which is what most bots and automations expect.
Adaptive Mode (Opt-In)
When Adaptive Channel Message Delivery is enabled in Global Settings, the integration polls for RX_LOG data every 50ms instead of waiting the full 500ms. As soon as data arrives, the meshcore_message event fires immediately.
After the initial event, a background task makes two additional collection passes (at 0.5s and 1.0s) to pick up late-arriving repeater RX_LOGs. These are delivered via meshcore_delivery_update events — the same progressive pattern used for outgoing message delivery tracking.
In testing, RX_LOG data consistently arrived within the first 50ms poll, even for messages routed through 5 repeaters. This reduces typical message delivery latency from 500ms to ~50ms.
Tradeoffs
| Default (Fixed Wait) | Adaptive | |
|---|---|---|
| Latency | Always 500ms | ~50ms typical, 500ms ceiling |
rx_log_data on initial event | All available paths | First path(s) only |
| Late-arriving repeater data | Missed if >500ms | Delivered via meshcore_delivery_update |
| Automation complexity | Listen to one event | May need to handle progressive updates |
When to Enable Adaptive Mode
Enable adaptive mode if:
- You want lower-latency message delivery for dashboards or notifications
- Your automations don't depend on having all paths present on the initial event
- You're willing to listen for
meshcore_delivery_updateevents to get complete path data
Keep the default if:
- Your bots or automations report total path counts from the initial event
- You want the simplest integration with no progressive events to handle
- The 500ms delay is acceptable for your use case
Enabling Adaptive Mode
- Go to Settings → Devices & Services → Meshcore
- Click Configure → Global Settings
- Enable Adaptive Channel Message Delivery
No restart required. The change takes effect on the next received channel message.
Outgoing Message Delivery Tracking
Outgoing channel messages also use progressive RX_LOG collection, regardless of the adaptive mode setting. When you send a channel message, the integration makes 4 collection passes over 4 seconds, firing meshcore_delivery_update events as repeater reception data arrives. The final pass includes "progressive": false to signal that collection is complete.
This allows dashboards and bots to show delivery status updates in real time — for example, displaying how many repeaters relayed your message and which paths it took.
See Events — meshcore_delivery_update for the full event field reference.
Logbook Integration
All messages automatically appear in the Home Assistant logbook with appropriate formatting and icons.
Message Format in Logbook
Channel Messages
Display with channel prefix and sender name:
- Format:
<channel> Sender: Message - Icon:
mdi:message-bulleted - Examples:
<public> PonyBot: back at you<public> 🦄: Ignore this testing 2<public> Iris03: Good morning Tigard.
Channel 0 displays as <public>, other channels show as <1>, <2>, etc.
Direct Messages
Display as simple sender and message:
- Format:
Sender: Message - Icon:
mdi:message-text - Examples:
PonyBot: test🦄: Test 2Weather Station: Temperature 72°F
Outgoing Messages
When your node (e.g., "PonyBot") sends messages, they appear in the logbook with your node name as the sender:
- Channel:
<public> PonyBot: Your message here - Direct:
PonyBot: Your reply here
Logbook Features
- Automatic Sender Resolution - Public keys are resolved to friendly names
- Emoji Support - Full support for emoji in node names and messages
- Channel Identification - Channel 0 shows as "public"
- Message Truncation - Long messages are truncated with "..." in debug logs
- Timestamp Tracking - Shows relative time (e.g., "1 minute ago", "3 hours ago")
- Date Grouping - Messages grouped by date in the logbook
- Entity Linking - Messages link to their binary sensor entities
Message Events
The integration provides two types of message events for automations:
meshcore_message Event
Fired when any message is received. See Events documentation for field details.
Key Fields:
message- The message textsender_name- Resolved sender name (e.g., "🦄", "PonyBot")message_type- "channel" or "direct"entity_id- Related binary sensor
meshcore_message_sent Event
Fired when a message is sent. See Events documentation for field details.
Key Fields:
message- The sent messagereceiver- Recipient name or channelmessage_type- "channel" or "direct"
Binary Sensor Entities
Message activity creates binary sensor entities that track communication:
Channel Message Sensors
- Entity ID:
binary_sensor.meshcore_<device_pubkey>_ch_<number>_messages - Example:
binary_sensor.meshcore_a305ca_ch_0_messages - Created: On first message in channel
- State: Always "Active" when messages exist
- Attributes: Channel index
Contact Message Sensors
- Entity ID:
binary_sensor.meshcore_<device_pubkey>_<contact_pubkey>_messages - Example:
binary_sensor.meshcore_a305ca_f293ac_messages - Created: On first message from contact
- State: Always "Active" when messages exist
- Attributes: Public key
Channel Configuration
Meshcore devices support multiple channels with configurable names and hash-based encryption.
Hash-Based Channel Encryption
Channels use hash-based encryption where the channel name is hashed to derive the encryption key. Only nodes with the exact channel name can decrypt messages on that channel.
How it works:
- Each channel has a name and a hash derived from that name
- The hash is used as the encryption key for the channel
- Only devices configured with the same name+hash combination can communicate
- You can create private channels by using unique names and sharing them securely
Setting Channel Names
Use the set_channel command to configure channel names:
service: meshcore.execute_command
data:
command: "set_channel 1 #pdx {{ '#pdx' | sha256 | truncate(32, true, '') }}"
Important: When using # in YAML, the entire command must be quoted (as shown above) since # starts a comment in YAML.
Command Format
set_channel <channel_idx> <name> <hash>
- channel_idx: Channel number (e.g., 0, 1, 2, etc.)
- name: Display name (e.g.,
#pdx,private,work,my-secret-channel) - hash: SHA256 hash of the channel name, truncated to 32 characters
The template {{ '#pdx' | sha256 | truncate(32, true, '') }} automatically generates the correct hash from the name.
Note: The # prefix is a convention for public/community channels but is not required. You can name channels anything you want.
Channel Management UI Card
Create a dashboard card to manage your channels:
type: vertical-stack
cards:
- type: markdown
content: |
## Channel Configuration
Configure channels with hash-based encryption.
- type: entities
entities:
- entity: input_text.meshcore_channel_name
- entity: input_number.meshcore_channel_index
- type: button
name: Set Channel
icon: mdi:pound
tap_action:
action: call-service
service: meshcore.execute_command
data:
command: >
set_channel {{ states('input_number.meshcore_channel_index') | int }}
{{ states('input_text.meshcore_channel_name') }}
{{ states('input_text.meshcore_channel_name') | sha256 | truncate(32, true, '') }}
Required Helper Entities (create in Settings → Devices & Services → Helpers):
-
Channel Index (Number):
- Name:
Meshcore Channel Index - Entity ID:
input_number.meshcore_channel_index - Min: 0, Max: 99, Step: 1
- Icon:
mdi:numeric
- Name:
-
Channel Name (Text):
- Name:
Meshcore Channel Name - Entity ID:
input_text.meshcore_channel_name - Max length: 32
- Icon:
mdi:pound
- Name:
Example Channel Configurations
Public Channel (Convention: # prefix)
service: meshcore.execute_command
data:
command: "set_channel 0 #public {{ '#public' | sha256 | truncate(32, true, '') }}"
Regional Channel
service: meshcore.execute_command
data:
command: "set_channel 1 #pdx {{ '#pdx' | sha256 | truncate(32, true, '') }}"
Private Channel (Any name)
service: meshcore.execute_command
data:
command: "set_channel 2 my-secret-channel {{ 'my-secret-channel' | sha256 | truncate(32, true, '') }}"
Viewing Configured Channels
To see your currently configured channels, use the MeshCore Channel select entity:
- Entity ID:
select.meshcore_channel - Shows all configured channels with their names
- Displays as "Name (idx)" format (e.g., "#pdx (1)", "work (2)")
- Updates automatically when channels are configured
Use this select entity in your messaging UI to choose which channel to send to.
Message Services
Send messages using these services:
Send Direct Message
service: meshcore.send_message
data:
node_id: "🦄"
message: "Hello from PonyBot!"
Send Channel Message
service: meshcore.send_channel_message
data:
channel_idx: 0 # Public channel
message: "Good morning mesh!"
See Services documentation for complete service details.
Automation Examples
Forward Messages to Notifications
alias: Mesh Message Notifications
trigger:
- platform: event
event_type: meshcore_message
action:
- service: notify.mobile_app
data:
title: >
{% if trigger.event.data.message_type == 'channel' %}
Mesh Channel {{ trigger.event.data.channel_idx }}
{% else %}
DM from {{ trigger.event.data.sender_name }}
{% endif %}
message: "{{ trigger.event.data.message }}"
Auto-Reply to Direct Messages
alias: Auto Reply to Status Requests
trigger:
- platform: event
event_type: meshcore_message
event_data:
message_type: "direct"
condition:
- condition: template
value_template: "{{ 'status' in trigger.event.data.message.lower() }}"
action:
- service: meshcore.send_message
data:
pubkey_prefix: "{{ trigger.event.data.pubkey_prefix }}"
message: "PonyBot Status: Online, Battery: 95%, Temp: 72°F"
Morning Greeting
alias: Morning Mesh Greeting
trigger:
- platform: time
at: "08:00:00"
action:
- service: meshcore.send_channel_message
data:
channel_idx: 0
message: "Good morning mesh! ☀️"
Message Rate Limiting
alias: Hourly Status Broadcast
trigger:
- platform: time_pattern
hours: "*"
minutes: "0"
action:
- service: meshcore.send_channel_message
data:
channel_idx: 0
message: >
PonyBot Status: {{ states('sensor.meshcore_battery_percentage') }}% battery,
{{ states('sensor.meshcore_node_count') }} nodes online
Message Filtering
By Specific Sender
trigger:
- platform: event
event_type: meshcore_message
condition:
- condition: template
value_template: "{{ trigger.event.data.sender_name == '🦄' }}"
By Channel
trigger:
- platform: event
event_type: meshcore_message
event_data:
message_type: "channel"
channel_idx: 0 # Public channel
By Message Content
trigger:
- platform: event
event_type: meshcore_message
condition:
- condition: template
value_template: "{{ 'test' in trigger.event.data.message.lower() }}"
Exclude Own Messages
trigger:
- platform: event
event_type: meshcore_message
condition:
- condition: template
value_template: "{{ trigger.event.data.sender_name != 'PonyBot' }}"
Message History
Viewing in Logbook
- Navigate to History in Home Assistant
- Select the Logbook tab
- Filter by "Meshcore" domain to see only mesh messages
- Messages show with relative timestamps and are grouped by date
Recent Messages Example
<public> PonyBot: back at you
11:17:11 AM - 1 minute ago
<public> 🦄: Ignore this testing 2
11:08:47 AM - 9 minutes ago
<public> Roamer 2: Ack
10:17:55 AM - 1 hour ago
<public> Iris03: Good morning Tigard.
8:31:03 AM - 3 hours ago
Querying via Templates
# Count today's messages
{{ states.binary_sensor
| selectattr('entity_id', 'match', 'binary_sensor.meshcore.*messages')
| list | length }}
# Check if specific contact sent messages
{{ states('binary_sensor.meshcore_abc123_messages') }}
Performance Considerations
Message Processing
- Messages are processed asynchronously to avoid blocking
- Sender name resolution is cached for performance
- Long messages (>50 chars) are truncated in debug logs only
Event Handling
- Use event filters to reduce automation triggers
- Consider using
mode: queuedfor message handlers - Batch message processing when handling multiple messages
Binary Sensors
- Created dynamically on first message
- Minimal state changes (always "Active")
- Use attributes for additional data without state changes
Troubleshooting
Messages Not Appearing in Logbook
- Verify the Meshcore device is connected
- Check that the sender exists in contacts
- Review debug logs for processing errors
Missing Sender Names
- Sender must be in the contact list for name resolution
- Unknown senders show as "Unknown (pubkey)"
- Channel messages extract sender from "Name: Message" format
Binary Sensors Not Created
- Sensors are created on first message only
- Check entity registry for existing sensors
- Verify entity naming follows the pattern
Own Messages Not Showing
- Ensure your node name is configured correctly
- Check that message send services complete successfully
- Verify
meshcore_message_sentevents are firing
Related Documentation
- Services - Sending messages
- Events - Message event details
- Automation - Message automation examples