Skip to content

feat: export whole device configuration (#1924)#1940

Closed
bruschill wants to merge 10 commits into
meshtastic:mainfrom
bruschill:feat/export-device-config
Closed

feat: export whole device configuration (#1924)#1940
bruschill wants to merge 10 commits into
meshtastic:mainfrom
bruschill:feat/export-device-config

Conversation

@bruschill

@bruschill bruschill commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What changed?

Adds an Export Configuration action to Settings → Tools that saves the connected node's full configuration to a binary DeviceProfile (.cfg) file.

  • DeviceProfileExport.swift — entity → protobuf converters for all 8 device configs and 15 module configs (the inverse of the proto → entity mapping in UpdateSwiftData.swift), plus NodeInfoEntity.exportDeviceProfile() which assembles a DeviceProfile: long/short name, LocalConfig, LocalModuleConfig, the channel-set URL, ringtone, canned messages, and the fixed position when one is set.
  • DeviceProfileDocument.swift — a FileDocument wrapping the serialized profile bytes for .fileExporter.
  • Tools.swift — the export button + fileExporter; shown with guidance/disabled when no node is connected.
  • UpdateSwiftData.swift — persists MQTT mapReportingShouldReportLocation in the config-update branch (it was only set on insert), so the exported value isn't a stale default.

Closes #1924.

Why did it change?

The Android app and the meshtastic CLI can export a device's full configuration; iOS/macOS could not. The .cfg binary DeviceProfile format matches Android, so an exported file can be backed up and re-imported across the Meshtastic ecosystem.

How is this tested?

  • New DeviceProfileExportTests (Swift Testing) — 16 tests covering the converters (enum mapping, negated-flag inversion, packed IPv4 bit-pattern, admin-key slot preservation, nested map-report settings, isServer, TAK/traffic/status) and DeviceProfile assembly including a binary serialization round-trip. All pass.
  • Full app build succeeds for the iOS simulator (Debug).
  • The converter set was reviewed field-by-field against the upsert*ConfigPacket functions in UpdateSwiftData.swift (the import mapping) to keep export/import symmetric.

Screenshots/Videos (when applicable)

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/. A short note in the Tools/settings docs may be warranted; happy to add it here or apply the skip-docs-check label per maintainer preference.
  • I have tested the change to ensure that it works as intended.

Notes for reviewers

  • Sensitive material is exported in plaintext. The profile includes the private key, admin keys, WiFi PSK, and MQTT password. This matches the Android .cfg behavior (the format is meant to fully restore a device), but the exported file should be treated as secret. Worth a deliberate decision if iOS wants to diverge (e.g. prompt or redact).
  • Export ↔ import are two hand-maintained mirrors. Each protoConfig converter is the inverse of an upsert*ConfigPacket mapping, and the two can silently drift as config fields are added (the file header comments call this out). A shared single source of truth between import and export would be the deeper fix for a future pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added "Export Device Configuration" to save a connected node's configuration as a local .cfg file with a safe, Android-style filename and correct export type.
    • Shows a confirmation step before exporting sensitive security material.
  • Bug Fixes
    • Improved device/module export fidelity (including channel URL, RTTTL ringtones, canned messages, and fixed-position rules).
    • Fixed persistence during syncs for MQTT location reporting and refreshed store-forward router/server flag.
    • Corrected admin-key slot alignment/trimming and improved optional/empty-field handling in exports.
  • Tests
    • Added thorough device-profile export and export-filename tests, including serialization round-trips.
  • Documentation
    • Updated Settings deep-link documentation (supported paths and query handling).

bruschill and others added 3 commits June 15, 2026 16:25
Adds a "Export Configuration" action to Settings → Tools that saves the
connected node's full configuration to a binary DeviceProfile (.cfg) file,
matching the format the Android app and meshtastic CLI use so it can be
backed up or imported elsewhere.

- DeviceProfileExport.swift: entity → protobuf converters for all 8 device
  configs and 15 module configs (the inverse of the proto → entity mapping
  in UpdateSwiftData.swift), plus NodeInfoEntity.exportDeviceProfile() which
  assembles a DeviceProfile (long/short name, LocalConfig, LocalModuleConfig,
  channel-set URL, ringtone, canned messages, and the fixed position when set).
- DeviceProfileDocument.swift: FileDocument wrapping the serialized profile.
- Tools.swift: export button + fileExporter; disabled with guidance when no
  node is connected.
- Tests covering the converters and DeviceProfile assembly incl. binary
  round-trip.

Fixes found in a code review of this feature:
- Export StoreForward isServer (was dropped) and the TAK, traffic-management,
  and status-message module configs (they ARE part of LocalModuleConfig).
- Preserve admin-key slot alignment instead of compacting empty slots, which
  corrupted keys on round-trip when an earlier slot was empty.
- Persist MQTT mapReportingShouldReportLocation in the upsert update branch
  (pre-existing bug that made the export read a stale default).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the 5 routable settings cases missing from the table
(localMeshDiscovery + its history subpath, trafficManagement,
takConfig, backupManagement, deviceLinks) and correct the tak
label to "TAK Server" to distinguish it from the new takConfig
TAK module config route.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts:
#	Meshtastic.xcodeproj/project.pbxproj

@RCGV1 RCGV1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compatibility/hardening review focused on Android .cfg parity:

  • [P2] Add a confirmation/warning before export because this file can include security/admin material. The export path serializes the full DeviceProfile, including config.security, admin keys/private key when present, and channel PSKs via channelURL. Right now Tools.swift starts export directly from the button. Please add a warning/confirmation or selection step that makes it clear this backup can grant mesh/admin access if shared.

  • [P2] Make the filename/type match Android more closely. Android currently exports names like Meshtastic_${shortName}_${yyyyMMdd}_nodeConfig.cfg; this PR uses the long name, no explicit .cfg suffix in the default filename, and a dynamic UTType(filenameExtension: "cfg"). Please use a sanitized Android-style filename with an explicit .cfg extension, and consider defining a stable exported UTType instead of recreating it inline.

  • [P3] Surface file-export write failures to the user. The .fileExporter completion logs failures, but the visible alert only covers serialization/preparation failures before the exporter opens. If iOS fails to write/save the document, the user should see an alert instead of only a log entry.

The raw file format itself looks compatible with Android: both sides are using raw serialized DeviceProfile protobuf bytes, not JSON or a wrapper container.

@RCGV1

RCGV1 commented Jun 29, 2026

Copy link
Copy Markdown
Member

@bruschill, I think this is a great feature. Can you address the issues I raised above

@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b0cbe7a-4bd2-46bf-ae70-63ea8dbcc7e8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds device configuration export to .cfg, with matching document, UI, persistence, test, project, and deep-link updates.

Changes

Device Profile Export

Layer / File(s) Summary
Export timestamp formatting
Meshtastic/Extensions/Date.swift
Adds cached date formatters and updates export timestamp and date-stamp formatting to use them.
DeviceProfileDocument wrapper
Meshtastic/Export/DeviceProfileDocument.swift
Introduces UTType.meshtasticDeviceProfile, implements DeviceProfileDocument for reading and writing profile bytes, and adds export filename generation.
Entity export mapping
Meshtastic/Export/DeviceProfileExport.swift
Adds protoConfig mappings for device and module config entities, NodeInfoEntity.exportDeviceProfile(), and exportChannelURL() for shareable channel URLs.
Tools export UI
Meshtastic/Views/Settings/Tools.swift
Adds the export section in Tools, prepares DeviceProfileDocument, configures .cfg file export, and presents export failure alerts.
SwiftData persistence updates
Meshtastic/Persistence/UpdateSwiftData.swift
Updates SwiftData upserts for security admin keys, MQTT map reporting, and store-forward router state.
Export tests
MeshtasticTests/DeviceProfileExportTests.swift
Adds tests for entity-to-proto mapping, security admin-key handling, exportDeviceProfile(), ringtone and canned messages, filename generation, and UTType metadata.
Xcode project wiring
Meshtastic.xcodeproj/project.pbxproj
Registers the new export, document, and test sources in the project file, groups, and build phases.
Deep-links docs
docs/developer/deep-links.md
Updates Settings deep-link documentation for localMeshDiscovery/history, trafficManagement, tak, and takConfig entries.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I hop with a cfg in tow,
New profiles packed and ready to go.
Keys and channels lined up just right,
Exported clean in bunny flight.
From settings pane to files so bright,
I leave a trail of config light.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning docs/developer/deep-links.md adds several unrelated deep-link entries and edits that are outside the export feature scope. Move the unrelated deep-link documentation edits into a separate PR, or trim them to only changes needed for the export feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: exporting whole device configuration.
Description check ✅ Passed The description covers what changed, why, how it was tested, and follows the required template structure.
Linked Issues check ✅ Passed The PR implements the requested full configuration export for iOS/macOS and backs it with export support and tests for #1924.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Meshtastic/Export/DeviceProfileExport.swift`:
- Around line 213-223: The store-forward export is reading a stale server flag
because the existing-entity path in upsertStoreForwardModuleConfigPacket updates
only some fields and never refreshes StoreForwardConfigEntity.isRouter, so
protoConfig keeps exporting the old value as isServer. Update the upsert logic
to assign the latest server-mode value to isRouter whenever an existing
StoreForwardConfigEntity is reused, so the protoConfig getter exports the
current state.
- Around line 140-145: The exported admin-key array is preserving stale trailing
slots, so retired `adminKey2`/`adminKey3` values can be written back into
backups. Update the export path in `DeviceProfileExport` to explicitly clear
removed admin-key slots before building `config.adminKey`, and ensure
`upsertSecurityConfigPacket`/the backing model does not leave old values behind
when the protobuf now contains fewer keys. Keep the positional mapping logic,
but only export slots that are still present in the current security config and
avoid carrying forward stale SwiftData values.

In `@Meshtastic/Views/Settings/Tools.swift`:
- Around line 98-104: The `.fileExporter` completion handler in the export flow
only logs `.failure` from the write step, so users don’t get visible feedback
when the save itself fails. Update the export handling around `Tools.swift`’s
`.fileExporter` result switch to surface the error in-app the same way prepare
failures are handled, and keep the existing `Logger.services` entry for
diagnostics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f92db928-0dfd-4019-af58-7b7c8b66dafd

📥 Commits

Reviewing files that changed from the base of the PR and between b9615b1 and ce5fb7c.

📒 Files selected for processing (7)
  • Meshtastic.xcodeproj/project.pbxproj
  • Meshtastic/Export/DeviceProfileDocument.swift
  • Meshtastic/Export/DeviceProfileExport.swift
  • Meshtastic/Persistence/UpdateSwiftData.swift
  • Meshtastic/Views/Settings/Tools.swift
  • MeshtasticTests/DeviceProfileExportTests.swift
  • docs/developer/deep-links.md

Comment on lines +140 to +145
// The proto `adminKey` is a positional repeated field (index 0/1/2 map back to
// adminKey/adminKey2/adminKey3 on import), so preserve slots — nil/empty middle slots stay
// as empty entries and only trailing empties are trimmed.
var adminKeys = [adminKey, adminKey2, adminKey3].map { $0 ?? Data() }
while let last = adminKeys.last, last.isEmpty { adminKeys.removeLast() }
config.adminKey = adminKeys

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Clear removed admin-key slots before exporting.

upsertSecurityConfigPacket only overwrites the slots present in the incoming protobuf, so a node that shrinks from 3 admin keys to 1 or 2 keeps stale adminKey2/adminKey3 values in SwiftData. This exporter then preserves those non-empty trailing slots and writes retired admin keys back into the .cfg backup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Meshtastic/Export/DeviceProfileExport.swift` around lines 140 - 145, The
exported admin-key array is preserving stale trailing slots, so retired
`adminKey2`/`adminKey3` values can be written back into backups. Update the
export path in `DeviceProfileExport` to explicitly clear removed admin-key slots
before building `config.adminKey`, and ensure `upsertSecurityConfigPacket`/the
backing model does not leave old values behind when the protobuf now contains
fewer keys. Keep the positional mapping logic, but only export slots that are
still present in the current security config and avoid carrying forward stale
SwiftData values.

Comment on lines +213 to +223
extension StoreForwardConfigEntity {
var protoConfig: ModuleConfig.StoreForwardConfig {
var config = ModuleConfig.StoreForwardConfig()
config.enabled = enabled
config.isServer = isRouter
config.heartbeat = heartbeat
config.records = UInt32(truncatingIfNeeded: records)
config.historyReturnMax = UInt32(truncatingIfNeeded: historyReturnMax)
config.historyReturnWindow = UInt32(truncatingIfNeeded: historyReturnWindow)
return config
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Refresh the store-forward server flag on updates.

This exports isRouter as isServer, but the existing-entity branch in upsertStoreForwardModuleConfigPacket never updates isRouter. After the first sync, toggling server mode on the device will still export the old value.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Meshtastic/Export/DeviceProfileExport.swift` around lines 213 - 223, The
store-forward export is reading a stale server flag because the existing-entity
path in upsertStoreForwardModuleConfigPacket updates only some fields and never
refreshes StoreForwardConfigEntity.isRouter, so protoConfig keeps exporting the
old value as isServer. Update the upsert logic to assign the latest server-mode
value to isRouter whenever an existing StoreForwardConfigEntity is reused, so
the protoConfig getter exports the current state.

Comment thread Meshtastic/Views/Settings/Tools.swift
CodeRabbit feedback:
- Clear removed positional admin-key slots on security-config sync so a node
  shrinking from 3 admin keys to 1/2 no longer keeps (and exports) retired keys.
  Still gated on a non-empty reported array so a partial/empty packet can't wipe
  stored keys.
- Refresh StoreForwardConfigEntity.isRouter on config update so server-mode
  changes are reflected in the export (the update branch never refreshed it).
- Surface .fileExporter write failures in-app (not just a log), ignoring user
  cancellation.

Also (code-review): drop the removed TrafficManagementConfig bool proto fields
from the export — they were replaced upstream by the non-zero-uint32 convention,
which was breaking the build; sanitize the export filename against path-illegal
characters; update the affected tests.

Addresses CodeRabbit + code-review feedback on meshtastic#1924.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Meshtastic/Persistence/UpdateSwiftData.swift`:
- Around line 1085-1088: In UpdateSwiftData.swift, the admin key update logic in
the security config path only handles the non-empty case, so an empty
config.adminKey leaves old values behind. Update the branch around the existing
adminKey assignments so that when config.adminKey is empty it explicitly clears
newSecurityConfig.adminKey, newSecurityConfig.adminKey2, and
newSecurityConfig.adminKey3, while preserving the current slot-by-slot
assignment when keys are present.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 72aa73fd-c21b-4ba1-a0e5-b50de7a95a2c

📥 Commits

Reviewing files that changed from the base of the PR and between ce5fb7c and 8c99842.

📒 Files selected for processing (4)
  • Meshtastic/Export/DeviceProfileExport.swift
  • Meshtastic/Persistence/UpdateSwiftData.swift
  • Meshtastic/Views/Settings/Tools.swift
  • MeshtasticTests/DeviceProfileExportTests.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • Meshtastic/Views/Settings/Tools.swift
  • MeshtasticTests/DeviceProfileExportTests.swift
  • Meshtastic/Export/DeviceProfileExport.swift

Comment thread Meshtastic/Persistence/UpdateSwiftData.swift Outdated
…Type

Address the compatibility/hardening review on meshtastic#1940:

- Add a confirmation dialog before exporting that warns the .cfg contains
  sensitive security material (private/admin keys, channel PSKs, Wi-Fi/MQTT
  passwords) before the file is written.
- Match Android's filename: Meshtastic_<shortName>_<yyyyMMdd>_nodeConfig.cfg
  via a testable DeviceProfileDocument.exportFilename(...) helper and a new
  Date.exportDateStamp; the .cfg suffix comes from a stable, reused
  UTType.meshtasticDeviceProfile instead of an inline UTType per call site.
- A name made only of path-illegal characters now trims to empty and falls
  back to "Node" instead of collapsing to a string of dashes.
- Re-resolve the connected node at confirm time (not the entity captured at
  button tap) and defer the file exporter past the dialog dismissal.
- Dedup the export DateFormatter boilerplate into cached static formatters.

Tests: add DeviceProfileExportFilenameTests (filename format, fallbacks,
illegal-char stripping, UTType extension); 22 tests pass.
Address CodeRabbit review: upsertSecurityConfigPacket only rewrote admin keys
when the reported array was non-empty, so a node that drops to zero admin keys
kept stale adminKey/adminKey2/adminKey3 values in SwiftData — which the device
profile export then wrote back into the .cfg backup.

Mirror every positional slot unconditionally (an empty array now clears all
three) via a single applyAdminKeys(_:to:) helper shared by the insert and
existing-entity branches, so the two stay in lockstep and slot 0 reads as the
idiomatic `.first`. Security sub-configs arrive as full snapshots, so an empty
admin_key reflects the device's true state.
@tylerpieper

Copy link
Copy Markdown

Seeing this inspired me to have the hallucination machine implement this for CLI and Web as well. Now we will have one import/export format common across all platforms!

@garthvh

garthvh commented Jul 3, 2026

Copy link
Copy Markdown
Member

This looks solid — nice symmetry with the upsert*ConfigPacket import mapping, and good call flagging the plaintext-secrets and hand-maintained-mirror tradeoffs.

Holding off on merging until the import side exists too — export alone isn't very useful without a way to bring a .cfg back in, and I'd rather land both together than ship a half feature. Marking this as a draft for now; I'll flip it back and merge once import is available (or ready to review as a companion PR).

@garthvh
garthvh marked this pull request as draft July 3, 2026 03:29
The committed docs/developer/deep-links.md was updated but the bundled
HTML/markdown under Meshtastic/Resources/docs/ was never regenerated, so
the in-app copy was stale. Rebuild via scripts/build-docs.sh.
@bruschill

Copy link
Copy Markdown
Contributor Author

Superseded by #2023, which contains this same export work plus the inverse import feature so the two ship together. Closing in favor of the combined PR.

@bruschill bruschill closed this Jul 3, 2026
bruschill added a commit to bruschill/Meshtastic-Apple that referenced this pull request Jul 3, 2026
…Type

Address the compatibility/hardening review on meshtastic#1940:

- Add a confirmation dialog before exporting that warns the .cfg contains
  sensitive security material (private/admin keys, channel PSKs, Wi-Fi/MQTT
  passwords) before the file is written.
- Match Android's filename: Meshtastic_<shortName>_<yyyyMMdd>_nodeConfig.cfg
  via a testable DeviceProfileDocument.exportFilename(...) helper and a new
  Date.exportDateStamp; the .cfg suffix comes from a stable, reused
  UTType.meshtasticDeviceProfile instead of an inline UTType per call site.
- A name made only of path-illegal characters now trims to empty and falls
  back to "Node" instead of collapsing to a string of dashes.
- Re-resolve the connected node at confirm time (not the entity captured at
  button tap) and defer the file exporter past the dialog dismissal.
- Dedup the export DateFormatter boilerplate into cached static formatters.

Tests: add DeviceProfileExportFilenameTests (filename format, fallbacks,
illegal-char stripping, UTType extension); 22 tests pass.
bruschill added a commit to bruschill/Meshtastic-Apple that referenced this pull request Jul 3, 2026
Adds an "Import Device Configuration" action to Settings → Tools, the
inverse of the Export Configuration feature (meshtastic#1940). It applies a saved
binary DeviceProfile (.cfg) file to the connected node, matching the
Android app and meshtastic CLI so a backup can be restored across the
ecosystem.

- DeviceProfileImport.swift — pure, device-free core: defensive parse
  (size-cap before decode), and DeviceProfileImportPlan, the has*-gated
  inverse of exportDeviceProfile(). Emits an ordered [ImportItem] plan
  (owner, radio/device, modules, personalization, fixed position,
  network, bluetooth, security, then Channels & LoRa last because it
  reboots) with per-item isSensitive/causesReboot flags and coarse
  ImportSection groups. Dedupes the LoRa config that export writes into
  both config.lora and the channel URL, preferring the URL when it's a
  valid replace-mode set (else the standalone LoRa config).
- DeviceProfileImporter.swift — ProfileApplyGateway seam + apply engine
  (sequential, isConnected pre-checks, abort-on-first-failure). The
  production gateway forwards each item to the existing
  save*Config/saveUser/saveChannelSet/setFixedPosition calls; the
  standalone-LoRa reboot disconnect is swallowed only when the link
  actually drops.
- ImportDeviceProfileView.swift — review sheet with per-section toggles
  (Security & Identity defaults OFF), live sensitive-material + reboot
  banners, a confirmation gate, per-item progress, and an
  applied/failed/skipped result summary.
- Tools.swift — Import section + .fileImporter([.meshtasticDeviceProfile])
  with a capped read, parse, and the review sheet.
- AccessoryManager+ToRadio.swift — new setFixedPosition(_:fromUser:toUser:)
  overload to restore explicit coordinates from a profile (the existing
  overload only uses the phone's GPS).

Tests: DeviceProfileImportTests (Swift Testing) — 22 tests covering
parse/round-trip, coverage vs. export, apply ordering, LoRa/channel
dedupe fallbacks, fixed-position and owner-identity preservation,
sensitivity/reboot flags, and the engine's abort/skip/reboot semantics
via a mock gateway. All pass; full app build succeeds for the iOS
simulator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 [Feature Request]: export whole configuration

4 participants