feat: Rename to SAUL-T-MOTE + MapKit map with user & robot positions (Issue #681) #3

Open
sl-ios wants to merge 5 commits from sl-ios/saul-t-mote-map into main
Collaborator

Summary

  • App renamed SAUL-T-MOTE (display name, nav title, MQTT client ID)
  • New Map tab (MapKit, iOS 17 SwiftUI Map API) alongside existing Status tab
  • Robot GPS subscription via MQTT saltybot/phone/gps
  • iOS GPS publish to saltybot/ios/gps at 1 Hz unchanged (PR #2)

Map features

Feature Details
User marker Blue dot with glow, tracks iPhone GPS
Robot marker Orange car icon, driven by saltybot/phone/gps
Follow path Dashed yellow line: robot → user
User trail 60-point fading blue breadcrumb dots
Robot trail 60-point fading orange breadcrumb dots
Distance overlay Live distance between user and robot
Speed overlay Robot speed (m/s) from MQTT payload
Auto-follow Camera follows user; drag to explore; re-centre button

MQTT changes

  • MQTTClient now supports SUBSCRIBE (QoS 0): sends SUBSCRIBE packet, re-subscribes on reconnect after CONNACK
  • Incoming PUBLISH packets fully parsed (variable-length remaining-length, multi-packet frames handled)
  • onMessage callback dispatched to main queue

Test plan

  • Deploy to iPhone 15 Pro
  • Tap Start Follow-Me → Status tab shows sensor rates, WS connected
  • Switch to Map tab → blue dot appears at phone location
  • mosquitto_pub -h 192.168.87.29 -u mqtt_seb -P mqtt_pass -t saltybot/phone/gps -m '{"ts":1,"lat":43.45,"lon":-79.75,"speed_ms":1.2,"alt_m":100,"accuracy_m":3,"bearing_deg":90,"provider":"gps"}' → orange robot marker appears
  • Move phone → blue trail grows, distance updates
  • Publish new robot positions → orange trail grows, follow-path line updates

🤖 Generated with Claude Code

## Summary - App renamed **SAUL-T-MOTE** (display name, nav title, MQTT client ID) - New **Map tab** (MapKit, iOS 17 SwiftUI `Map` API) alongside existing Status tab - **Robot GPS subscription** via MQTT `saltybot/phone/gps` - iOS GPS publish to `saltybot/ios/gps` at 1 Hz unchanged (PR #2) ## Map features | Feature | Details | |---|---| | User marker | Blue dot with glow, tracks iPhone GPS | | Robot marker | Orange car icon, driven by `saltybot/phone/gps` | | Follow path | Dashed yellow line: robot → user | | User trail | 60-point fading blue breadcrumb dots | | Robot trail | 60-point fading orange breadcrumb dots | | Distance overlay | Live distance between user and robot | | Speed overlay | Robot speed (m/s) from MQTT payload | | Auto-follow | Camera follows user; drag to explore; re-centre button | ## MQTT changes - `MQTTClient` now supports **SUBSCRIBE** (QoS 0): sends `SUBSCRIBE` packet, re-subscribes on reconnect after CONNACK - Incoming `PUBLISH` packets fully parsed (variable-length remaining-length, multi-packet frames handled) - `onMessage` callback dispatched to main queue ## Test plan - [ ] Deploy to iPhone 15 Pro - [ ] Tap **Start Follow-Me** → Status tab shows sensor rates, WS connected - [ ] Switch to **Map tab** → blue dot appears at phone location - [ ] `mosquitto_pub -h 192.168.87.29 -u mqtt_seb -P mqtt_pass -t saltybot/phone/gps -m '{"ts":1,"lat":43.45,"lon":-79.75,"speed_ms":1.2,"alt_m":100,"accuracy_m":3,"bearing_deg":90,"provider":"gps"}'` → orange robot marker appears - [ ] Move phone → blue trail grows, distance updates - [ ] Publish new robot positions → orange trail grows, follow-path line updates 🤖 Generated with [Claude Code](https://claude.com/claude-code)
sl-ios added 5 commits 2026-04-04 11:41:28 -04:00
- SulTee SwiftUI app targeting iOS 17+, iPhone 15 Pro
- CoreLocation: dual-frequency GPS (L1+L5) continuous updates, background mode enabled
- CoreMotion: 100 Hz IMU (accel + gyro + attitude + gravity), magnetometer via device motion
- CMAltimeter: barometer relative altitude + pressure streaming
- CLLocationManager heading updates for magnetometer heading
- URLSessionWebSocketTask client connecting to ws://192.168.86.158:9090
- JSON protocol: {type, timestamp, data} for gps/imu/heading/baro messages
- Auto-reconnect on disconnect (2s backoff)
- Haptic feedback on incoming "haptic" messages from bot
- Background streaming: UIBackgroundModes location + external-accessory in Info.plist
- SwiftUI status UI: connection banner, sensor rate counters (Hz), start/stop follow-me button
- Dev team Z37N597UWY (vayrette@gmail.com), bundle ID com.saltylab.sultee

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Default URL updated from ws://192.168.86.158:9090 (LAN) to ws://100.64.0.2:9090 (Tailscale)
- URL persisted in UserDefaults under key "orinURL" — survives app restarts
- WebSocketClient.url is now mutable so it can be updated without recreation
- SensorManager.updateURL(_:) applies a new URL when not streaming
- ContentView: editable text field for Orin address with Apply button, disabled while streaming
- Connection banner shows the active URL instead of hardcoded string

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NSAllowsLocalNetworking covers CGNAT 100.64.0.0/10 range used by Tailscale,
fixing ATS blocking plain ws:// connections. Also adds NSExceptionDomains
entry for 100.64.0.2 as explicit fallback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds minimal MQTT 3.1.1 client (MQTTClient.swift) using Network.framework —
no external dependency. Implements CONNECT + PUBLISH (QoS 0) + PINGREQ keepalive.

- Broker: 192.168.87.29:1883 (user: mqtt_seb)
- Topic: saltybot/ios/gps
- Rate: 1 Hz Timer, decoupled from GPS update rate
- Payload matches sensor_dashboard.py format:
  {ts, lat, lon, alt_m, accuracy_m, speed_ms, bearing_deg, provider: "gps"}
- lastKnownLocation cached from CLLocationManagerDelegate, published on timer
- MQTT connect/disconnect tied to startStreaming()/stopStreaming()
- ATS NSExceptionDomains extended to include 192.168.87.29 (MQTT broker LAN IP)
- MQTTClient.swift registered in project.pbxproj Sources build phase

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rename:
- CFBundleDisplayName = "SAUL-T-MOTE" in Info.plist
- navigationTitle updated to "SAUL-T-MOTE" in StatusView
- MQTT clientID prefix changed to "saul-t-mote-"

Map view (MapContentView.swift, MapKit):
- Blue marker + fading breadcrumb trail for user (iPhone GPS)
- Orange car marker + fading breadcrumb trail for robot (Pixel 5)
- Dashed yellow line from robot → user (follow path)
- Bottom overlay: distance between user and robot, robot speed
- Auto-follow camera tracks user; manual drag disables it; re-centre button restores
- MapPolyline for trails, per-point Annotation for fading breadcrumb dots

Robot GPS subscription (saltybot/phone/gps):
- MQTTClient extended with SUBSCRIBE (QoS 0) + incoming PUBLISH parser
  (handles variable-length remaining-length, multi-packet frames)
- Subscriptions persisted and re-sent on reconnect (CONNACK handler)
- SensorManager.handleRobotGPS() updates robotLocation, robotSpeed,
  robotBreadcrumbs, distanceToRobot

iOS GPS publish unchanged (saltybot/ios/gps, 1 Hz) — PR #2 intact.

ContentView restructured as TabView:
- Tab 1: Status (sensor rates, WS URL, follow-me button)
- Tab 2: Map

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This pull request can be merged automatically.
You are not authorized to merge this pull request.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin sl-ios/saul-t-mote-map:sl-ios/saul-t-mote-map
git checkout sl-ios/saul-t-mote-map
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: seb/saltylab-ios#3
No description provided.