diff --git a/docs/_javascript/preset_test.js b/docs/_javascript/preset_test.js index 1c759e755..bf5361d13 100644 --- a/docs/_javascript/preset_test.js +++ b/docs/_javascript/preset_test.js @@ -281,6 +281,13 @@ return { available: true, reason: "Ready to queue after the node clock is verified." }; } + function primaryScheduleAvailability(config, nowMs) { + if (nowMs >= config.startMs) { + return { available: false, reason: "The start time has passed; use the immediate option." }; + } + return { available: true, reason: "Ready to queue after the node clock is verified." }; + } + function commandsFor(config, nowMs) { const tuple = [config.freqText, config.bwText, config.sf, config.cr].join(","); const minutes = remainingMinutes(config, nowMs); @@ -288,11 +295,16 @@ stockNow: "tempradio " + tuple + "," + minutes, companionNow: "set radio2.cross on\nset tempradio2 " + tuple + ",rxtx," + minutes, + primaryScheduled: + "set tempradioat " + tuple + "," + config.startEpoch + "," + + config.endEpoch + "\nget tempradioat", companionScheduled: "set radio2.cross on\nset tempradioat2 " + tuple + ",rxtx," + config.startEpoch + "," + config.endEpoch + "\nget tempradioat2", stockCancelDuring: "tempradio " + tuple + ",1", stockLeaveIn30: "tempradio " + tuple + ",30", + primaryCancel: + "get tempradioat\ndel tempradioat all", companionCancelBefore: "get tempradioat2\ndel tempradioat2 all\nset radio2.cross auto", companionCancelDuring: "set tempradio2 off\nset radio2.cross auto", @@ -748,9 +760,11 @@ ); const staticCommands = commandsFor(config, config.startMs); + setCommand(root, "primary-scheduled", staticCommands.primaryScheduled); setCommand(root, "companion-scheduled", staticCommands.companionScheduled); setCommand(root, "stock-cancel-during", staticCommands.stockCancelDuring); setCommand(root, "stock-leave-30", staticCommands.stockLeaveIn30); + setCommand(root, "primary-cancel", staticCommands.primaryCancel); setCommand(root, "companion-cancel-before", staticCommands.companionCancelBefore); setCommand(root, "companion-cancel-during", staticCommands.companionCancelDuring); setCommand(root, "companion-leave-30", staticCommands.companionLeaveIn30); @@ -837,6 +851,7 @@ const phase = phaseAt(config, nowMs); const immediateOpen = immediateAvailable(config, nowMs); const status = root.querySelector('[data-role="status"]'); + const primarySchedule = primaryScheduleAvailability(config, nowMs); const schedule = scheduleAvailability(config, nowMs); const commands = commandsFor(config, nowMs); @@ -903,6 +918,7 @@ : "The test window has ended." ); + setCommandEnabled(root, "primary-scheduled", primarySchedule.available); setCommandEnabled(root, "companion-scheduled", schedule.available); const nowEpoch = Math.floor(nowMs / 1000); @@ -945,6 +961,7 @@ remainingMinutes: remainingMinutes, immediateAvailable: immediateAvailable, scheduleAvailability: scheduleAvailability, + primaryScheduleAvailability: primaryScheduleAvailability, commandsFor: commandsFor, radioEstimates: radioEstimates, formatCountdown: formatCountdown, diff --git a/docs/preset_test.md b/docs/preset_test.md index 9bfe463a3..871054964 100644 --- a/docs/preset_test.md +++ b/docs/preset_test.md @@ -67,10 +67,12 @@ tuple; no source edit is required.

Check the node clock before scheduling

- The Companion tempradioat2 scheduler uses UTC Unix time. - Run clock on every Companion and compare it with the browser - UTC time below. It should agree to within about a minute. A wrong clock - can start late, start immediately, or cause the schedule to be rejected. + The primary tempradioat and Companion + tempradioat2 schedulers use UTC Unix time. Run + clock on every node that will be scheduled and compare it + with the browser UTC time below. It should agree to within about a minute. + A wrong clock can start late, start immediately, or cause the schedule to + be rejected.

@@ -163,24 +165,39 @@ clock
-

Option 2: schedule a Companion in advance

+

Option 2: schedule a supported node in advance

- Stock firmware has no tempradioat command, so a stock node - cannot be queued in advance. Return during the one-hour setup window and - use Option 1. A Companion can use the exact UTC epochs below to switch at - the common start and restore its saved configuration at the common end. + A Simple Repeater build can schedule its primary radio with + tempradioat. A Companion can instead schedule its second + profile with tempradioat2. Both commands use the exact UTC + epochs below, switch at the common start, and restore saved settings at + the common end. Room-server and sensor roles use Option 1 instead.

-

Stock repeater, room server, or sensor

+

Room server or sensor

No advance schedule

- Stock firmware provides tempradio, but not - tempradioat. Use the immediate stock command in Option 1 - after its setup window opens. + Use the immediate tempradio command in Option 1 after + its setup window opens. +

+
+ +
+
+

Simple Repeater primary radio

+ Primary schedule +
+
+ +

+ This is available only on a Simple Repeater build with primary + scheduled-radio support. It changes the primary tuple at the start + and restores the saved tuple at the end. If get tempradioat + returns Error: unsupported, use Option 1 instead.

@@ -203,11 +220,11 @@ clock

Cancel or leave the test

- A stock node can leave an active test as shown below. For a Companion - schedule, the all form removes every temporary schedule in - that family. To preserve another schedule, first run the corresponding - get command and replace all with its displayed - entry number. + A stock node can leave an active test as shown below. For a primary or + Companion schedule, the all form removes every temporary + schedule in that family. To preserve another schedule, first run the + corresponding get command and replace all with + its displayed entry number.

@@ -231,6 +248,17 @@ clock

+
+

Simple Repeater · scheduled primary radio

+
+ +

+ Before the start, this removes the queued temporary schedule. While + it is running, it also restores the saved primary tuple after the + command reply drains. +

+
+

Companion · before it starts

@@ -387,9 +415,10 @@ clock
-Stock firmware does not support advance TempRadio scheduling; use its immediate -tempradio command during the setup window. The Companion scheduling -commands require current full-parser firmware, and +Primary tempradioat scheduling is implemented by the Simple Repeater +role; room-server and sensor roles use their immediate tempradio +command during the setup window. The Companion scheduling commands require +current full-parser firmware, and tempradio2 and tempradioat2 require a build with dual-radio-profile support. If a node reports an unknown command, use only a method that its installed firmware documents. diff --git a/mkdocs.yml b/mkdocs.yml index 1065a936e..856447573 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,4 +30,4 @@ extra_javascript: - _javascript/telemetry_decoder.js - _javascript/management_decoder.js - _javascript/filter_tool.js - - _javascript/preset_test.js?v=20260920-1 + - _javascript/preset_test.js?v=20260921-1 diff --git a/test/test_preset_test.js b/test/test_preset_test.js index 2ab1a97b5..e6d7bef4b 100644 --- a/test/test_preset_test.js +++ b/test/test_preset_test.js @@ -16,9 +16,10 @@ assert.doesNotMatch( pageSource, /
tempradioat<\/code> command/); -assert.doesNotMatch(pageSource, /data-command="stock-scheduled"/); -assert.doesNotMatch(pageSource, /Stock · before it starts/); +assert.match(pageSource, /data-command="primary-scheduled"/); +assert.match(pageSource, /data-command="primary-cancel"/); +assert.match(pageSource, /Simple Repeater primary radio/); +assert.doesNotMatch(pageSource, /Stock firmware has no tempradioat<\/code> command/); assert.doesNotMatch(pageSource, /Normal return profile/); const query = @@ -59,6 +60,10 @@ assert.strictEqual(tool.presetPageTitle(requestedLink), "Temporary radio test · assert.match(tool.presetPageSummary(requestedLink), /911\.3 MHz, 500 kHz, SF8, CR7, 22 dBm/); assert.doesNotMatch(tool.presetPageSummary(requestedLink), /910\.1 MHz/); assert.strictEqual(tool.presetEyebrow(requestedLink), "MeshCore · 48-hour temporary preset test"); +assert.strictEqual( + tool.commandsFor(requestedLink, requestedLink.startMs).primaryScheduled, + "set tempradioat 911.3,500,8,7,1790035200,1790208000\nget tempradioat" +); const browserZoneFallback = tool.configFromSearch("", "America/New_York"); assert.strictEqual(browserZoneFallback.tz, "America/New_York"); @@ -98,8 +103,11 @@ assert.strictEqual(tool.remainingMinutes(config, setupOpens), 2940); const commands = tool.commandsFor(config, active); assert.strictEqual(commands.stockNow, "tempradio 910.1,500,8,7,2880"); -assert.strictEqual(commands.stockScheduled, undefined); -assert.strictEqual(commands.stockCancelBefore, undefined); +assert.strictEqual( + commands.primaryScheduled, + "set tempradioat 910.1,500,8,7,1790035200,1790208000\nget tempradioat" +); +assert.strictEqual(commands.primaryCancel, "get tempradioat\ndel tempradioat all"); assert.strictEqual( commands.companionNow, "set radio2.cross on\nset tempradio2 910.1,500,8,7,rxtx,2880" @@ -124,6 +132,8 @@ assert.strictEqual( assert.strictEqual(tool.scheduleAvailability(config, before).available, true); assert.strictEqual(tool.scheduleAvailability(config, active).available, false); +assert.strictEqual(tool.primaryScheduleAvailability(config, before).available, true); +assert.strictEqual(tool.primaryScheduleAvailability(config, active).available, false); assert.strictEqual( tool.scheduleAvailability(config, config.endMs - tool.SCHEDULE_HORIZON_MS - 1).available, false