Get with File on P-ION: connect and transfer the way Ontrol's Niagara driver does

A real P-ION (fw 1.32) restarted on every Sox file get. Ontrol's Niagara 4
driver gets app.sab from the same device, so its settings are copied:
- DASP hello asks for 256-byte packets (idealMax/absMax), so file chunks
  are 238 bytes
- the message-length header (0x81) goes to Orion only, decided once the
  platform id is read
- the app is saved on the device before app.sab is read, the save resent
  every 5 s rather than 1 s (a P-ION save takes 2-3+ s)
- the file open is resent every 15 s; DASP gains a per-packet resend
  interval for this

Tested on a P-ION at 192.168.1.252: save 3.2 s, app.sab + kits.scode +
app.sax in 15.8 s, no resends, device stayed up. The unsaved-changes
question became a notice, since the app is now always saved first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 08:15:12 +03:00
co-authored by Claude Opus 5.5
parent 6b23bafffc
commit 2880c2a6f2
6 changed files with 80 additions and 37 deletions
+7 -16
View File
@@ -619,9 +619,9 @@ _APP_ACTIONS = ["save", "hibernate", "quit", "restart", "reboot"]
def do_get_with_file():
"""App > Get with File: backs the device's app up to a zip in <Sedona home>/store/apps.
The zip carries the device's app.sab, so changes not yet saved on the device are
offered a save first. The transfer runs off the main thread behind a small progress
window.
The app is saved on the device before its app.sab is read, as Ontrol's Niagara
driver does, so unsaved changes are announced first and the backup can be called
off. The transfer runs off the main thread behind a small progress window.
"""
ds = app_state.device_session
if not app_state.live_mode or ds is None or not ds.is_connected:
@@ -631,21 +631,11 @@ def do_get_with_file():
messagebox.showerror("Get with File", "The Sedona home folder is not set (Preferences).")
return
if app_state.is_dirty:
answer = messagebox.askyesnocancel(
if app_state.is_dirty and not messagebox.askokcancel(
"Unsaved Changes",
"The app has changes that are not saved on the device yet." + NL + NL +
"Save the app on the device before getting it?" + NL +
"(No gets the app as it was last saved.)",
)
if answer is None:
return
if answer and not _invoke_app_action("save"):
messagebox.showerror(
"Get with File",
"The device did not save the app, so nothing was fetched. "
"The status bar says why.")
return
"Get with File saves the app on the device first, so they will be saved."):
return
path = _ask_backup_path(ds)
if not path:
@@ -683,6 +673,7 @@ def do_get_with_file():
app_state.set_status(f"Get with File failed: {error}", warn=True)
messagebox.showerror("Get with File", f"The backup failed:{NL}{NL}{error}")
return
app_state.mark_clean() # the app was saved on the device first
_report_backup(result)
def work():