A native SwiftUI app for iOS 17+, iPadOS, and macOS 14+ that communicates with MeshCore LoRa mesh-network nodes via Bluetooth Low Energy.
- BLE connectivity — connects to MeshCore nodes using the Nordic UART Service (NUS) protocol
- Direct Messages — E2E-addressed DMs with full ACK lifecycle (pending → sent → acked); grouped chat bubbles with animations and time-section headers
- Channel Messaging — public, hashtag, and private channels with per-message sender-name display
- Room Server support — Room Servers appear as contacts; inline login prompt on first open; DMs and replies work seamlessly
- Contacts — full 32-byte public key storage with path-length, routing flags, and isFavorite support
- Repeater management — login, status requests, and CLI commands via
RepeaterService - Map view — SwiftUI Map with node markers, type/time filters, MGRS coordinates, Line-of-Sight calculation and offline tile caching
- Network tab — live node list grouped by type (Repeater, Room Server, Chat); frequency display in kHz; tap any node to open a management screen with Info / Config / CLI segments
- Node CLI — send commands to the local node directly over BLE, or to remote Repeater/Room Server nodes via
RepeaterService - Settings tab — BLE scanner to connect/disconnect devices (device name shown during connecting); detailed sync-phase indicator (contacts → channels → messages); in-app log viewer with level filter and share export
- Full-text search — fast in-app search across all messages (SQLite FTS5)
- Multilingual — German and English (String Catalogs)
MeshTalk/
├── App/ # AppContainer (DI), LogStore, LocalNodeInfo
├── BLE/ # CoreBluetooth layer: BLEService, CommandQueue, BLEConstants
├── Protocol/ # MeshPacket (all types), PacketParser, MeshCommand, CommandEncoder
├── Database/ # GRDB fresh schema (v3), AppDatabase, Tables
├── Repository/ # ContactRepository, MessageRepository, ChannelRepository, NodeRepository
├── Services/ # InitService, RepeaterService, KeychainService
└── Features/
├── Map/ # MapView, MapViewModel, MGRSConverter, LineOfSightCalculator
├── Messages/ # MessagesView, ChatView, ChatViewModel, Conversation, MessageBubbleView
├── Network/ # NetworkView, NodeManagementView, NodeInfoView, NodeConfigView, NodeCLIView
└── Settings/ # SettingsView, SettingsViewModel, LogView
| Table | Key columns |
|---|---|
contacts |
public_key (64 hex), node_type ("chat"|"room_server"), flags, path_len, path_bytes |
messages |
sender_name, ack_tag, UNIQUE(conversation_id, timestamp, sender_key, text) |
channels |
index, name, type, keychain_ref |
nodes |
Repeaters + sensors (map/network only) |
message_relays |
Per-relay SNR/RSSI events for sent channel messages |
| Layer | Technology |
|---|---|
| UI | SwiftUI, @Observable (iOS 17 Observation) |
| BLE | CoreBluetooth, Nordic UART Service |
| Database | GRDB 6.x with FTS5 |
| Async | Swift Concurrency (actor, async/await), Combine |
| Project | xcodegen |
- Xcode 16+
- iOS 17.0+ / macOS 14.0+
- A MeshCore-compatible LoRa node (e.g. T-Beam, Heltec V3)
# Clone the repository
git clone https://github.com/Jarod1230/MeshTalk.git
cd MeshTalk
# Generate the Xcode project
xcodegen generate
# Open in Xcode
open MeshTalk.xcodeprojSelect the MeshTalk_iOS or MeshTalk_macOS scheme and run.
Create a gitignored Local.xcconfig with your Apple Developer Team ID:
DEVELOPMENT_TEAM = YOUR_TEAM_ID
The project uses Automatic Signing. The -allowProvisioningUpdates flag lets xcodebuild fetch and renew provisioning profiles automatically (required for a signed binary — without it the install will fail with "code object is not signed").
# 1. Build (automatically signed)
xcodebuild build \
-project MeshTalk.xcodeproj \
-scheme MeshTalk_iOS \
-destination 'id=YOUR_DEVICE_ID' \
-xcconfig Local.xcconfig \
-allowProvisioningUpdates
# 2. Resolve app path
APP=$(xcodebuild -project MeshTalk.xcodeproj -scheme MeshTalk_iOS \
-showBuildSettings -destination 'generic/platform=iOS' 2>/dev/null \
| grep "BUILT_PRODUCTS_DIR" | head -1 | awk '{print $3}')
# 3. Install
xcrun devicectl device install app --device YOUR_DEVICE_ID "$APP/MeshTalk.app"Find your device ID with:
xcrun devicectl list devicesxcodebuild test \
-project MeshTalk.xcodeproj \
-scheme MeshTalk_iOS \
-only-testing MeshTalkTests_iOS \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro Max'MeshTalk speaks the MeshCore BLE Companion Protocol. Communication happens over the Nordic UART Service (NUS):
- Service UUID
6E400001-B5A3-F393-E0A9-E50E24DCCA9E - TX (write)
6E400002-B5A3-F393-E0A9-E50E24DCCA9E - RX (notify)
6E400003-B5A3-F393-E0A9-E50E24DCCA9E
Packets are binary-encoded with a 1-byte type prefix. See MeshTalk/Protocol/ for the full parser and encoder.
Response packets (0x00–0x12): ok, error, contactStart/End, contact, selfInfo, deviceInfo, messageSent, contactMessage (V1+V3), channelMessage (V1+V3), channelInfo, battery, noMoreMessages, exportedContact
Push packets (0x80+): advertisement (0x80), pathUpdated (0x81), ack (0x82), messagesWaiting (0x83), loginSuccess (0x85), loginFail (0x86), statusResponse (0x87), logRxData (0x88), newAdvertisement (0x8A)
appStart, deviceQuery, setDeviceTime, getContacts, getContactByKey, getChannel, setChannel, getMessage, sendMessage, sendChannelMessage, sendCliCommand, sendLogin, sendStatusRequest, sendSelfAdvert, resetPath, addUpdateContact, removeContact, reboot, getBattery, getStats
GNU General Public License v3.0 — see LICENSE for details.
Commercial use restriction: Use of this software in any commercial product or service requires a separate commercial licence from the author. Contact jarod@e-post.me for enquiries.