Messaging Views
MeshDash has two messaging views: Direct Messages (P2P between nodes) and Channels (broadcast within a channel). Both share the same underlying message API but target different recipients.
Direct Messages (/dmes)
The DM view has a two-panel layout: a contact list on the left and a chat panel on the right.
Contact List
All known nodes (from window.meshState.nodes) are listed as contacts. A filter box at the top searches by name or node ID. Contacts with unread messages show a badge. The list is sorted by most recently active node first.
Click a contact to open the chat panel for that node. The panel header shows:
- The node's long name and ID
- An OFFLINE pill (OFFLINE) if the node has not been heard in over 1 hour
- A status dot (green = online in last hour, grey = offline)
Sending a Direct Message
Type in the input box (max 230 characters — Meshtastic firmware limit). The character counter N/230 updates as you type. Click TRANSMIT or press Enter to send.
This calls POST /api/messages with the target node's ID as destination. The message is optimistically added to the chat log immediately with status SENT.
Delivery Status
Message bubbles show a status icon that updates via the SSE message_status_update event:
| Status | Icon | Meaning |
|---|---|---|
SENT | Single tick | Packet queued and sent by radio |
DELIVERED | Double tick (green) | ACK received from destination node |
FAILED | ✗ (red) | Routing error received — node unreachable |
BROADCAST | Broadcast icon | Sent to all — no ACK expected |
History
On opening a DM conversation, the view loads history from GET /api/messages/history?from_id=&to_id=&limit=100. Messages are displayed in chronological order (oldest at top, newest at bottom).
Unread Badges
When a message arrives for a node that is not the currently open conversation, the contact row gets an unread count badge. The sidebar nav item for Direct Message also shows a total unread count. Unread counts are cleared when you open the conversation. They are tracked in window.meshState.dmUnread.
Channels (/channels)
The Channels view works like DM but targets a channel index rather than a specific node.
Channel List
Channels are loaded from GET /api/channels on view init. Each channel entry shows its name, role (PRIMARY / SECONDARY), and index number. Channels with unread messages show a badge.
The currently selected channel's name and metadata (role, PSK indicator) appear in the chat panel header.
Sending a Broadcast
Messages sent from the Channels view use destination: "^all" and the selected channel index. They reach every node that shares the same channel PSK. The character counter and Enter-to-send behaviour are identical to DM.
The footer hint shows the encryption state — PENDING LINK until the radio connects, then updates to show whether the channel has a PSK set.
Auto-Scroll
Both views have an AUTO_SCROLL checkbox (checked by default). When enabled, the chat log scrolls to the newest message on every update. Uncheck it to read back through history without being interrupted.
Message Fetch on First Open
When you first open a DM conversation or channel, the view fetches the last 100 messages from the database via GET /api/messages/history. They are displayed oldest-first (earliest at the top of the chat log). From that point on, new messages arrive via the SSE packet event and are appended to the bottom in real time without re-fetching history.
Message Bubble Layout
Outbound messages (sent by your local node) are right-aligned with a different background colour. Inbound messages are left-aligned. Each bubble shows:
- Sender name (or "You" for outbound)
- Message text
- Timestamp
- Delivery status icon (outbound only): ✓ SENT, ✓✓ DELIVERED (green), ✗ FAILED (red)
- SNR / RSSI of the received packet (inbound only, if available)
Channel Encryption Hint
The footer of the Channels view shows:
- PENDING LINK — radio not yet connected, channels not loaded
- 🔒 AES-256 — selected channel has a PSK set (encrypted over the air)
- 🔓 OPEN — selected channel has no PSK (unencrypted)
This is informational only — the encryption is performed by the Meshtastic radio firmware. MeshDash transmits the plaintext message to the radio, which encrypts it before RF transmission.
230-Character Limit
Meshtastic's maximum packet payload is approximately 228–237 bytes depending on firmware version and headers. MeshDash enforces a 230-character soft limit in the input field. The character counter turns amber at 200 characters and red at 225 as a visual warning. Messages longer than 230 characters will be truncated by the radio.
Unread Count Reset
Unread counts reset when:
- DM: You click on the contact in the list (the conversation opens)
- Channels: You click on the channel in the channel list (the log is shown)
Counts do not persist across page refreshes — they reset to zero on reload because they are tracked in window.meshState.dmUnread and window.meshState.channelUnread which are in-memory only.