Cognitive Sentiment icon Cognitive Sentiment — Detects positive sentiment percentage of input text using cognitive ML; returns $SentimentPercentage, shows face, graph, and status for analysis. Try it →
Asked
Resolved Resolved by dbeard!
2 Participants
ScriptStartWait Delay on ADC4

Scriptstartwait Delay On ADC4

I need a little help with timing in a JavaScript script I have running in my robot. It works great but there is one feature that I'd like to speed up. Here's what it is and what I need:

The below script that I attached polls 7 different ADC ports every 600ms on an EZBv4. Momentary buttons are attached to each of these watched ports. When one of the 7 monetary buttons are pushed and the voltage changes on its attached ADC port another script will trigger and an action will happen.

One of the sections of this script that watches these ADC ports and buttons starts several different Weather report scripts in itself, one different script after the other when this one particular momentary button is pushed. So to be clear, the first button push will give me the local temperature, the second push will give me what the actual temp feels like, the third will give me the humidity and so on. The timing of when the next button push is available is accomplished using the "ScriptStartWait" command. So, as I understand it, this command pauses the parent script calling the other child script until the "System" reports that that called child script has completed. Only then will the parent script unpause and be able to recognize the next button push to run the next script in this section.

My issue is the amount of time it takes for the next button push to be available (only in this one section using the "ScriptStartWait" method). After I push the button and the child script runs it takes at least 3 or 4 seconds for the next button push to become available after the child script ends. I'd like to get this pause shorter so the next push would be available almost right away. As is I need to wait and guess when I can push this button to hear the next step in the weather report.

Oh, also, this section also has a timer that resets the sequence back to the start if I don't push this button again within one minute

I've ran this through the ARC Script agent and it tried to adjust timing but it just messed up the script. I think the issue is using the ScriptStartWait" method. Is there any way to adjust when the system releases and unpauses the parent script thus making the next button push available? Is there a different way to write this section of the script that would let me push this button as soon as the child script completes? The timing in the rest of the script watching the other buttons is perfect.

The whole script is attached below. The section I'm referring to is labeled // ==================== Chest Button: Alpha 202, ADC4- (One button Push Each: Current Temp, Feels Like, Humidity and Wind Speed) ====================

// Polls ADC1-ADC7 only. ADC0 is handled by Script A.

var adcPorts = [1, 2, 3, 4, 5, 6, 7];
var threshold = 170;
var pollMs = 600;
var debounceMs = 150;
var ezbIndex = 0;

// Map ADC port number -> action function
var actions = [];

// ================= Chest Button: Gamma 202, ADC1- (Power Down Robot Completely) ====================
actions[1] = function() {
  sleep(6250);
  controlCommand("Shutdown PC", "ScriptStart");
};

// ==================== Chest Button: Gamma 101, ADC2- (Personality Toggle On and Off) ====================
actions[2] = function() {
  var personality = getVar("$Personality");
  sleep(200);

  if (personality == 0) {
    turnOffPersonality();
  } else if (personality == 1) {
    turnOnPersonality();
  }
};

function turnOffPersonality() {
  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4000);
  controlCommand("Soundboard v4", "Play", "Conclusion.mp3");

  print("Personality is Off");
  setVar("$Personality", 1);
}

function turnOnPersonality() {
  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
  sleep(4000);
  controlCommand("Soundboard v4", "Play", "GreenAndGo.mp3");
  print("Personality is On");
  setVar("$Personality", 0);
}

// ==================== Chest Button: Vector Hold, ADC3 (Open) ====================
actions[3] = function() {
  controlCommand("Personality Generator", "PauseOn");
 // setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(5000);
  controlCommand("Soundboard 2", "Play", "not.mp3");
  sleep(600);
  controlCommand("Soundboard v4", "Play", "Active-2.mp3");
  controlCommand("Personality Generator", "PauseOff");
  //setVar("$Personality", 0); //Only uncomment if this var is not set in called script.
};

// ==================== Chest Button: Alpha 202, ADC4- (One button Push Each: Current Temp, Feels Like, Humidity and Wind Speed) ====================
var alpha202ScriptList = ["Outside Temp", "Temp Feels LIke", "Humidity", "Wind Speed"];
var alpha202Index = 0;
var alpha202LastCompleteMs = 0;
var alpha202ResetMs = 60000; // 1 minute

actions[4] = function() {
  var now = nowMs();

  // Reset sequence if more than 1 minute since last completed run
  if (alpha202LastCompleteMs > 0 && (now - alpha202LastCompleteMs) > alpha202ResetMs) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4750);
  
  var scriptToRun = alpha202ScriptList[alpha202Index];
  controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);

  alpha202LastCompleteMs = nowMs();
  alpha202Index = alpha202Index + 1;
  if (alpha202Index >= alpha202ScriptList.length) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
};

// ================ Chest Button: Bata 202, ADC5 -(Speak Time,Date and Environmental Report) ====================
actions[5] = function() {
  controlCommand("Personality Generator", "PauseOn");
  //setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(6000);
  controlCommand("Time, Date & Temp", "ScriptStart", "Time,Date,Enviroment");
};

// ==================== Chest Button: Detent +, ADC6 (Open) ====================
actions[6] = function() {
  controlCommand("Personality Generator", "PauseOn");
  //setVar("$Personality", 1); //Only uncomment if this var is not set in called script.
  sleep(5000);
  controlCommand("Soundboard 2", "Play", "not.mp3");
  sleep(600);
  controlCommand("Soundboard v4", "Play", "Active-2.mp3");
  controlCommand("Personality Generator", "PauseOff");
  //setVar("$Personality", 0); //Only uncomment if this var is not set in called script.
};

// ============ Chest Button: Vector Release, ADC7-(Run Soil Sampler & Speak Report ====================
actions[7] = function() {
  controlCommand("Personality Generator", "PauseOn");
  setVar("$Personality", 1); //Var is set because this is the control script.
  Digital.set(d0, true);
  Digital.set(d23, true, 1);
  Digital.set(d2, true);
  Digital.set(d10, true);
  sleep(2000);
  Digital.set(d23, false, 1);
  controlCommand("Leg Section", "ScriptStart", "Hip Down Full");
  sleep(6000);
  controlCommand("Leg Section", "ScriptStart", "Up with Hips");
  sleep(3500);
  controlCommand("Head Section", "ScriptStart", "Bubble Up and Down");
  sleep(250);
  Digital.set(d2, false);
  sleep(10000);
  Digital.set(d0, false);
  Digital.set(d10, false);
  controlCommand("Personality Generator", "PauseOff");
  setVar("$Personality", 0); //This Var is cleared because this is the control script.
};

var lastState = [];
var stableStart = [];

function nowMs() {
  return (new Date()).getTime();
}

print("ADC Watcher: start. Polling " + adcPorts.length + " ports every " + pollMs + " ms");

while (true) {
  try {
    for (var i = 0; i < adcPorts.length; i++) {
      var port = adcPorts[i];
      var value = ADC.get(port, ezbIndex);
      var pressed = (value >= threshold);

      if (pressed !== lastState[port]) {
        if (stableStart[port] == null || stableStart[port] == 0) {
          stableStart[port] = nowMs();
        } else {
          if (nowMs() - stableStart[port] >= debounceMs) {
            lastState[port] = pressed;
            stableStart[port] = 0;

            var t = new Date().toLocaleString();
            print(t + " ADC" + port + " state -> " + (pressed ? "PRESSED" : "RELEASED") + " val:" + value);

            if (pressed) {
              try {
                if (typeof actions[port] === "function") {
                  actions[port]();
                } else {
                  print("ADC Watcher: no action defined for port " + port);
                }
              } catch (ae) {
                print("ADC Watcher: action error: " + ae);
              }
            }
          }
        }
      } else {
        stableStart[port] = 0;
      }
    }
  } catch (e) {
    print("ADC Watcher: error reading ADC: " + e);
  }

  sleep(pollMs);
}


Related Hardware (view all EZB hardware)
EZ-B V4 by EZ-Robot
EZ-B v4 with Synthiam ARCx controls servos, sensors, camera and audio over Wi-Fi or USB serial, no firmware needed.
Wi-Fi / USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 24

Related Robot Skills (view all robot skills)
Add custom EZ-Script functions in C# or JS; intercept unknown calls, parse parameters and return values via AdditionalFunctionEvent.
Run scripts automatically when specified ARC variables change; define variable-to-script pairs, monitor status, and trigger actions.

ARC Pro

Upgrade to ARC Pro

With Synthiam ARC Pro, you're not just programming a robot; you're shaping the future of automation, one innovative idea at a time.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Yes - the delay is very likely coming from ScriptStartWait itself, not from the ADC polling.

What’s happening

controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);

means:

  • the parent script blocks
  • ARC waits for the child script to finish
  • then the parent script continues

If you’re seeing a 3-4 second gap after the child script ends, that’s usually because the parent script is still tied up in the wait/blocking behavior and then returning to the polling loop afterward.

Best fix

For this kind of "press once, run next step, be ready immediately for the next press" workflow, I’d recommend not using ScriptStartWait here.

Instead, use:

controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);

Then let the button sequence state advance independently.


Better approach for your weather sequence

You already have alpha202Index, so you can keep the sequence moving without waiting for the child script to "release" the parent.

Replace this:

controlCommand("Time, Date & Temp", "ScriptStartWait", scriptToRun);
alpha202LastCompleteMs = nowMs();

With this:

controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);
alpha202LastCompleteMs = nowMs();

That will make the parent return to monitoring much faster.


If you need the next press to happen only after speech finishes

If the goal is not "script complete" but rather "speech/audio complete", then ScriptStartWait may still not be the right tool, because child scripts can return before all audio is actually done depending on how they’re written.

A more reliable pattern is to have the child script set a status variable when it is truly finished, for example:

setVar("$WeatherStepDone", 1);

Then the parent can watch for that variable, or better yet, avoid waiting entirely and just use the button sequence index.


The cleanest fix for your case

Because your weather reports are user-initiated button steps, I’d suggest this structure:

  1. Button press triggers the next script immediately
  2. Parent increments the index right away
  3. Use a reset timeout to wrap back to 0 after 1 minute of inactivity
  4. Let the child script handle its own speech timing

That way, the next press is accepted as soon as ARC gets back to the poll loop.


Example rewrite of your Alpha 202 section

var alpha202ScriptList = ["Outside Temp", "Temp Feels Like", "Humidity", "Wind Speed"];
var alpha202Index = 0;
var alpha202LastPressMs = 0;
var alpha202ResetMs = 60000; // 1 minute

actions[4] = function() {
  var now = nowMs();

  if (alpha202LastPressMs > 0 && (now - alpha202LastPressMs) > alpha202ResetMs) {
    alpha202Index = 0;
  }

  alpha202LastPressMs = now;

  controlCommand("Personality Generator", "PauseOn");
  controlCommand("Weather Loop", "ScriptStop");
  sleep(4750);

  var scriptToRun = alpha202ScriptList[alpha202Index];
  controlCommand("Time, Date & Temp", "ScriptStart", scriptToRun);

  alpha202Index++;
  if (alpha202Index >= alpha202ScriptList.length) {
    alpha202Index = 0;
  }

  controlCommand("Personality Generator", "PauseOff");
  controlCommand("Weather Loop", "ScriptStart");
};

Why this helps

  • no blocking wait
  • next press becomes available sooner
  • reset still works after 1 minute of inactivity

One more important note

You’re polling every 600 ms, so even with a perfect script you can only detect a new press roughly every 0.6 seconds plus debounce. If you want the system to feel more responsive, consider lowering pollMs to something like:

var pollMs = 50;

or

var pollMs = 100;

That alone can make button response feel much snappier.


Recommendation

For this section, I’d try in this order:

  1. Change ScriptStartWait to ScriptStart
  2. Reduce pollMs from 600 to 100 or 50
  3. Keep your sequence index logic for the 1-minute timeout

If you want, I can also help you rewrite just the ADC4 section into a cleaner state-machine version that preserves your timing behavior and removes the wait stall entirely.

I am a customer support AI and still learning. Please verify important answers in our support documentation. For advanced AI features, use the AI Script Agent built into ARC.
Author Avatar
PRO
USA
#2  
Hi Dave. I took a stab at fixing. Curious if it works out once you test.

// ============================================================================
// ADC BUTTON WATCHER
// Watches ADC1-ADC7 on EZB0
//
// Alpha 202 / ADC4 uses a non-blocking weather-report state machine.
// The ADC watcher continues running while the weather report is active.
//
// IMPORTANT:
// Each Alpha 202 weather child script must execute this as its LAST line:
//
// setVar("$Alpha202WeatherDone", 1);
//
// Weather child scripts:
// "Outside Temp"
// "Temp Feels LIke"
// "Humidity"
// "Wind Speed"
// ============================================================================
// ============================================================================
// CONFIGURATION
// ============================================================================
// ADC0 is handled by another script.
var adcPorts = [1, 2, 3, 4, 5, 6, 7];
var threshold = 170;
// Faster than the original 600 ms, but still reasonable for seven ADC reads.
var pollMs = 200;
var debounceMs = 150;
var ezbIndex = 0;
// ============================================================================
// GENERAL HELPERS
// ============================================================================
function nowMs() {
 return (new Date()).getTime();
}
// ============================================================================
// ACTION TABLE
// ============================================================================
var actions = [];
// ============================================================================
// Chest Button: Gamma 202, ADC1
// Power Down Robot Completely
// ============================================================================
actions[1] = function() {
 sleep(6250);
 controlCommand("Shutdown PC", "ScriptStart");
};
// ============================================================================
// Chest Button: Gamma 101, ADC2
// Personality Toggle On and Off
// ============================================================================
actions[2] = function() {
 var personality = getVar("$Personality");
 sleep(200);
 if (personality == 0) {
 turnOffPersonality();
 } else if (personality == 1) {
 turnOnPersonality();
 }
};
function turnOffPersonality() {
 controlCommand("Personality Generator", "PauseOn");
 controlCommand("Weather Loop", "ScriptStop");
 sleep(4000);
 controlCommand("Soundboard v4", "Play", "Conclusion.mp3");
 print("Personality is Off");
 setVar("$Personality", 1);
}
function turnOnPersonality() {
 controlCommand("Personality Generator", "PauseOff");
 controlCommand("Weather Loop", "ScriptStart");
 sleep(4000);
 controlCommand("Soundboard v4", "Play", "GreenAndGo.mp3");
 print("Personality is On");
 setVar("$Personality", 0);
}
// ============================================================================
// Chest Button: Vector Hold, ADC3
// Open / Existing Action
// ============================================================================
actions[3] = function() {
 controlCommand("Personality Generator", "PauseOn");
 sleep(5000);
 controlCommand("Soundboard 2", "Play", "not.mp3");
 sleep(600);
 controlCommand("Soundboard v4", "Play", "Active-2.mp3");
 controlCommand("Personality Generator", "PauseOff");
};
// ============================================================================
// Chest Button: Alpha 202, ADC4
//
// Push sequence:
// 1 - Outside Temp
// 2 - Temp Feels LIke
// 3 - Humidity
// 4 - Wind Speed
//
// If more than 60 seconds passes after a completed report,
// sequence resets to Outside Temp.
//
// IMPORTANT:
// This action DOES NOT WAIT for the weather script.
// The main ADC watcher remains alive.
// ============================================================================
var alpha202ScriptList = [
 "Outside Temp",
 "Temp Feels LIke",
 "Humidity",
 "Wind Speed"
];
var alpha202Index = 0;
// Time the most recent weather child ACTUALLY completed.
var alpha202LastCompleteMs = 0;
// Reset sequence after 60 seconds of inactivity.
var alpha202ResetMs = 60000;
// Preserve original pre-report delay.
var alpha202PreDelayMs = 4750;
// Safety timeout so a broken child script cannot permanently lock ADC4.
var alpha202MaxRunMs = 60000;
// Completion variable shared with the four weather child scripts.
var alpha202DoneVar = "$Alpha202WeatherDone";
// Internal Alpha 202 state.
var alpha202Busy = false;
var alpha202Phase = "IDLE";
var alpha202ActiveScript = "";
var alpha202LaunchAtMs = 0;
var alpha202RunStartMs = 0;
// Initialize completion flag.
try {
 setVar(alpha202DoneVar, 0);
} catch (e) {
 print("Alpha 202: could not initialize completion variable: " + e);
}
// ---------------------------------------------------------------------------
// ADC4 PRESS
// ---------------------------------------------------------------------------
actions[4] = function() {
 var now = nowMs();
 // -------------------------------------------------------
 // Do not allow weather reports to overlap.
 // -------------------------------------------------------
 if (alpha202Busy) {
 print(
 "Alpha 202: button ignored because weather report is still active: " +
 alpha202ActiveScript
 );
 return;
 }
 // -------------------------------------------------------
 // Reset sequence after one minute from LAST COMPLETION.
 // -------------------------------------------------------
 if (
 alpha202LastCompleteMs > 0 &&
 (now - alpha202LastCompleteMs) > alpha202ResetMs
 ) {
 alpha202Index = 0;
 print("Alpha 202: 60-second timeout - sequence reset to Outside Temp");
 }
 // -------------------------------------------------------
 // Select report for this button press.
 // -------------------------------------------------------
 alpha202ActiveScript = alpha202ScriptList[alpha202Index];
 alpha202Busy = true;
 alpha202Phase = "WAIT\_DELAY";
 alpha202LaunchAtMs = now + alpha202PreDelayMs;
 alpha202RunStartMs = 0;
 // -------------------------------------------------------
 // Prepare audio environment.
 // -------------------------------------------------------
 try {
 setVar(alpha202DoneVar, 0);
 controlCommand("Personality Generator", "PauseOn");
 controlCommand("Weather Loop", "ScriptStop");
 } catch (e) {
 print("Alpha 202: preparation error: " + e);
 finishAlpha202(false, "PREPARATION\_ERROR");
 return;
 }
 print(
 "Alpha 202: queued " +
 alpha202ActiveScript +
 " - starts after " +
 alpha202PreDelayMs +
 " ms"
 );
};
// ---------------------------------------------------------------------------
// ALPHA 202 BACKGROUND STATE MACHINE
//
// Called repeatedly by the main ADC polling loop.
// It NEVER uses ScriptStartWait.
// ---------------------------------------------------------------------------
function processAlpha202() {
 if (!alpha202Busy) {
 return;
 }
 var now = nowMs();
 // =======================================================
 // PHASE 1 - WAIT FOR ORIGINAL 4750 MS DELAY
 // =======================================================
 if (alpha202Phase == "WAIT\_DELAY") {
 if (now < alpha202LaunchAtMs) {
 return;
 }
 try {
 // Make absolutely sure an old DONE signal cannot be reused.
 setVar(alpha202DoneVar, 0);
 print(
 "Alpha 202: starting weather script: " +
 alpha202ActiveScript
 );
 // ---------------------------------------------------
 // NON-BLOCKING START
 // ---------------------------------------------------
 controlCommand(
 "Time, Date & Temp",
 "ScriptStart",
 alpha202ActiveScript
 );
 alpha202RunStartMs = now;
 alpha202Phase = "RUNNING";
 } catch (e) {
 print("Alpha 202: script start error: " + e);
 finishAlpha202(false, "START\_ERROR");
 }
 return;
 }
 // =======================================================
 // PHASE 2 - CHILD WEATHER SCRIPT IS RUNNING
 // =======================================================
 if (alpha202Phase == "RUNNING") {
 var done = 0;
 try {
 done = getVar(alpha202DoneVar);
 } catch (e) {
 print("Alpha 202: completion-variable read error: " + e);
 return;
 }
 // -----------------------------------------------------
 // Child script says it has completed.
 // -----------------------------------------------------
 if (
 done === true ||
 done == 1 ||
 done == "1"
 ) {
 finishAlpha202(true, "COMPLETE");
 return;
 }
 // -----------------------------------------------------
 // Safety timeout
 // -----------------------------------------------------
 if (
 alpha202RunStartMs > 0 &&
 (now - alpha202RunStartMs) >= alpha202MaxRunMs
 ) {
 print(
 "Alpha 202: TIMEOUT waiting for weather script: " +
 alpha202ActiveScript
 );
 finishAlpha202(false, "TIMEOUT");
 return;
 }
 }
}
// ---------------------------------------------------------------------------
// FINISH / CLEANUP ALPHA 202
// ---------------------------------------------------------------------------
function finishAlpha202(success, reason) {
 var completedScript = alpha202ActiveScript;
 // -------------------------------------------------------
 // Only advance sequence after a confirmed completion.
 // -------------------------------------------------------
 if (success) {
 alpha202LastCompleteMs = nowMs();
 alpha202Index = alpha202Index + 1;
 if (alpha202Index >= alpha202ScriptList.length) {
 alpha202Index = 0;
 }
 }
 // -------------------------------------------------------
 // Restore normal personality/weather operation.
 // -------------------------------------------------------
 try {
 controlCommand("Personality Generator", "PauseOff");
 } catch (e1) {
 print("Alpha 202: Personality resume error: " + e1);
 }
 try {
 controlCommand("Weather Loop", "ScriptStart");
 } catch (e2) {
 print("Alpha 202: Weather Loop restart error: " + e2);
 }
 // -------------------------------------------------------
 // Clear completion signal.
 // -------------------------------------------------------
 try {
 setVar(alpha202DoneVar, 0);
 } catch (e3) {
 print("Alpha 202: completion-variable clear error: " + e3);
 }
 // -------------------------------------------------------
 // Return Alpha 202 to idle.
 // -------------------------------------------------------
 alpha202Busy = false;
 alpha202Phase = "IDLE";
 alpha202ActiveScript = "";
 alpha202LaunchAtMs = 0;
 alpha202RunStartMs = 0;
 print(
 "Alpha 202: finished " +
 completedScript +
 " result=" +
 reason
 );
}
// ============================================================================
// Chest Button: Bata 202, ADC5
// Speak Time, Date and Environmental Report
// ============================================================================
actions[5] = function() {
 controlCommand("Personality Generator", "PauseOn");
 sleep(6000);
 controlCommand(
 "Time, Date & Temp",
 "ScriptStart",
 "Time,Date,Enviroment"
 );
};
// ============================================================================
// Chest Button: Detent +, ADC6
// Open / Existing Action
// ============================================================================
actions[6] = function() {
 controlCommand("Personality Generator", "PauseOn");
 sleep(5000);
 controlCommand("Soundboard 2", "Play", "not.mp3");
 sleep(600);
 controlCommand("Soundboard v4", "Play", "Active-2.mp3");
 controlCommand("Personality Generator", "PauseOff");
};
// ============================================================================
// Chest Button: Vector Release, ADC7
// Run Soil Sampler & Speak Report
// ============================================================================
actions[7] = function() {
 controlCommand("Personality Generator", "PauseOn");
 setVar("$Personality", 1);
 Digital.set(d0, true);
 Digital.set(d23, true, 1);
 Digital.set(d2, true);
 Digital.set(d10, true);
 sleep(2000);
 Digital.set(d23, false, 1);
 controlCommand(
 "Leg Section",
 "ScriptStart",
 "Hip Down Full"
 );
 sleep(6000);
 controlCommand(
 "Leg Section",
 "ScriptStart",
 "Up with Hips"
 );
 sleep(3500);
 controlCommand(
 "Head Section",
 "ScriptStart",
 "Bubble Up and Down"
 );
 sleep(250);
 Digital.set(d2, false);
 sleep(10000);
 Digital.set(d0, false);
 Digital.set(d10, false);
 controlCommand("Personality Generator", "PauseOff");
 setVar("$Personality", 0);
};
// ============================================================================
// ADC DEBOUNCE STATE
// ============================================================================
var lastState = [];
var stableStart = [];
// ============================================================================
// STARTUP
// ============================================================================
print(
 "ADC Watcher: start. Polling " +
 adcPorts.length +
 " ports every " +
 pollMs +
 " ms"
);
// ============================================================================
// MAIN LOOP
// ============================================================================
while (true) {
 // -------------------------------------------------------------------------
 // Service the non-blocking Alpha 202 weather state machine.
 // -------------------------------------------------------------------------
 try {
 processAlpha202();
 } catch (alphaError) {
 print(
 "ADC Watcher: Alpha 202 processing error: " +
 alphaError
 );
 }
 // -------------------------------------------------------------------------
 // Poll ADC1-ADC7.
 // -------------------------------------------------------------------------
 try {
 for (var i = 0; i < adcPorts.length; i++) {
 var port = adcPorts[i];
 var value = ADC.get(port, ezbIndex);
 var pressed = (value >= threshold);
 // ---------------------------------------------------------------------
 // State differs from last accepted state.
 // Start or continue debounce timer.
 // ---------------------------------------------------------------------
 if (pressed !== lastState[port]) {
 if (
 stableStart\[port\] == null ||
 stableStart[port] == 0
 ) {
 stableStart[port] = nowMs();
 } else {
 if (
 nowMs() - stableStart[port] >= debounceMs
 ) {
 lastState[port] = pressed;
 stableStart[port] = 0;
 var t = new Date().toLocaleString();
 print(
 t +
 " ADC" +
 port +
 " state -> " +
 (pressed ? "PRESSED" : "RELEASED") +
 " val:" +
 value
 );
 // ---------------------------------------------------------------
 // Run action only on PRESS.
 // ---------------------------------------------------------------
 if (pressed) {
 try {
 if (typeof actions[port] === "function") {
 actions[port]();
 } else {
 print(
 "ADC Watcher: no action defined for port " +
 port
 );
 }
 } catch (actionError) {
 print(
 "ADC Watcher: action error on ADC" +
 port +
 ": " +
 actionError
 );
 }
 }
 }
 }
 } else {
 // Input agrees with accepted state.
 // No pending debounce transition.
 stableStart[port] = 0;
 }
 }
 } catch (e) {
 print(
 "ADC Watcher: error reading ADC: " +
 e
 );
 }
 sleep(pollMs);
}
Author Avatar
PRO
USA
#3  

Dave and follow up with this:

One required change to the four weather scripts

This is important. At the very end of each of these four scripts:

Outside Temp
Temp Feels LIke
Humidity
Wind Speed

add:

setVar("$Alpha202WeatherDone", 1);

For example, if Outside Temp currently ends like this:

Audio.sayWait("The outside temperature is 76 degrees.");

change the end to:

Audio.sayWait("The outside temperature is 76 degrees.");

setVar("$Alpha202WeatherDone", 1);

That last line is what tells the ADC watcher:

"The report really is finished. ADC4 may now accept the next weather-report press."

This avoids guessing with sleeps and avoids relying on ScriptStartWait.

#4  

Wow Dave. Thanks. Your the best.as always I appreciate your help. I'll work on this later today and report back.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#5  

Glad to help - that’s a solid direction to try.

The key change is exactly what you pointed out: have each weather child script set a completion variable at the very end so the ADC watcher can move on immediately without waiting on ScriptStartWait.

A few quick notes before you test:

  • Make sure each of the 4 weather scripts ends with:
setVar("$Alpha202WeatherDone", 1);
  • If any of those scripts uses Audio.say() or Audio.sayEZB() without waiting, the completion flag should only be set after the final speech line.
  • If you want, you can also add a debug print() line right before the flag so you can confirm each script reaches the end.

For example:

Audio.sayWait("The outside temperature is 76 degrees.");
print("Outside Temp complete");
setVar("$Alpha202WeatherDone", 1);

Important ARC note

If the weather scripts are launched by name from ScriptStart, they’ll run independently, which is what you want here. This is a good use case for ARC’s scripting model.

Optional improvement

If the whole weather-report flow is still a little sluggish, you can likely reduce pollMs from 200 to 100 or even 50 to make the next press feel more immediate.

If it acts weird

If you test it and the next button still doesn’t respond instantly, tell me:

  1. Whether the four scripts all end with the completion variable
  2. Whether those scripts use sayWait or non-blocking speech
  3. Whether the ADC watcher prints the "finished" message immediately

If you want, I can help you trim the four weather scripts too so they all follow the same clean pattern.

I am a customer support AI and still learning. Please verify important answers in our support documentation. For advanced AI features, use the AI Script Agent built into ARC.
#6   — Edited

Hey @dbeard,

Dave, after following your instructions and installing your script it works! Thanks. The button push responses in that section are almost instant now. I love it. Just what I was looking for.

I only had two things I had to change (for your info only. I'm not complaining).

  1. I'm using sound clips to recite intros and the numbers of the returned weather details. The intro starts properly but the first word or so was cut off. These shoud cliups are triggered in the child scripts being triggered. I saw you had changed the " var pollMs = xxx; " from what I had (600) to 200ms. I know this was done to make the button pushes feel more responsive like @Athena suggested. However when I changed the var pollMs back to my original 600ms the whole phrase is now said and the entire delivery sounds natural. I've never had a problem with the buttons feeling sluggish or missing a button push. When I first wrote this script I experimented with that value and found it made no difference in my setup if I kept that number below 600. Furthermore I try to keep the polling ADC ports a bit slow to keep the traffic from overwhelming the system. I'm polling 10 ADC ports at once in this and other scripts this keeps that all under control. I was having problems with my USB to Serial direct connections to the computer disconnecting and that seemed to help.
  2. The other item was a command line towards the end of the script on line 423. This one:
stableStart\[port\] == null || 

It seems that the two "\" before and after the word port was illegal I removed them and the script ran as expected. This line ended up looking like this:

stableStart[port] == null ||

Oh, the rest of the script still works great.

So again, thanks for your help and all the work you put into this for me. I'm a happy camper. LOL.

📚 This thread has been preserved as a helpful resource!

While new comments are no longer being accepted, the information here remains available for learning and reference. Check the most recent comment for additional details.