Asked

Help With EZ-Script Coding

I'm working on a project with my EZ-B v4, and I need some assistance with coding the GetDigital command. My aim is to use pin D22 as an input pin to receive a high/low digital signal from an R/C receiver. The receiver uses a PWM-to-digital output device on one of its channels. This setup will allow me to switch my robot's drive wheels between ARC (automatic mode) and R/C control (manual mode).

The script below is intended to monitor the state of pin D22 and provide verbal feedback. When in Automatic Mode, ARC will control the wheels and all sensors. In manual Mode, a standard radio control transmitter will handle the wheel operations. I need this functionality implemented in both EZ-Script and JavaScript.

Here's my current EZ-Script code:

$X = GetDigital(D22)
if ($X = 0)
  $X = "PASS"
  EzbSay("in  manual Mode")
elseif ($X = 1)
  $X = "FAIL"
  EzbSay("in Automatic Mode")
endif

Could you review it and help me ensure that it performs correctly? Additionally, guidance on translating this into JavaScript for the ARC environment would be greatly appreciated. Thank you!


Related Hardware EZ-B v4
Related Controls Script EZ-Script Console

ARC Pro

Upgrade to ARC Pro

ARC Pro is your gateway to a community of like-minded robot enthusiasts and professionals, all united by a passion for advanced robot programming.

#65  

Hi Athena,

First off, I do need to keep the EZB in AP mode. The robot will not always be in my home, I intend to show off this robot at different place, which would mean i would want to connect to the internet of the location I am at, while the laptop continues to be connected to the robot.

Im running Windows 11 Pro, version 35H2

The built-in WiFi is a dual band, wireless AC 8265 The WiFi Dongle is a Realtek RTL8188FTV wireless LAN 802.11n

I tried to run the netsh but that is unfamiliar to me.

Static IP's sounds like an idea.

Author Avatar
PRO
Canada
#66  

Good - keeping the EZ-B in AP mode is perfectly fine. The static-IP + route approach is the usual reliable fix on a Windows laptop that must keep one WiFi interface connected to the EZ-B AP while using a second WiFi adapter for internet.

Below I’ll give:

  • A short summary of the plan,
  • GUI steps you can follow in Windows 11,
  • Command-line steps (with exact commands you can paste) - you’ll need to run a small netsh command first to get interface names/indices,
  • A small ARC JavaScript "network watcher" script that will pause/resume your PandoraBot skill automatically when internet goes down/up,
  • Safety notes and follow-up options.

Plan summary (what we’ll do)

  • Give the EZ-B adapter on your laptop a static IP on the EZ-B subnet (for example 192.168.1.2 / 255.255.255.0) WITHOUT a gateway.
  • Ensure your Internet WiFi adapter remains the default gateway (so internet traffic uses the dongle).
  • Add a persistent route telling Windows how to reach the EZ-B host (192.168.1.1) via the local EZ-B adapter.
  • Optionally set adapter metrics so the Internet adapter is higher priority.

This keeps the EZ-B reachable at 192.168.1.1 while preserving the Internet route via the dongle/router.

  1. Quick GUI steps (Windows 11)
  1. Connect to the EZ-B WiFi so the EZB adapter shows up in Network Connections.
  2. Open Network Connections:
    • Start Settings Network & internet Advanced network settings More network adapter options
    • Or press Windows+R, type ncpa.cpl, Enter.
  3. Identify the EZ-B adapter (it’ll show as a WiFi adapter; you can confirm by disconnecting/reconnecting and seeing which goes up/down). Right-click it Properties Internet Protocol Version 4 (TCP/IPv4) Properties.
  4. Choose "Use the following IP address" and enter:
    • IP address: 192.168.1.2
    • Subnet mask: 255.255.255.0
    • Default gateway: leave blank
    • DNS servers: leave blank or enter your normal DNS if desired (not necessary)
  5. Click Advanced uncheck "Automatic metric" and set Interface metric to a large number (e.g., 200).
  6. Now open your Internet WiFi adapter properties IPv4 Advanced uncheck "Automatic metric" and set metric to a small number (e.g., 10).
  7. Reconnect both adapters. You should be able to reach the EZ-B at 192.168.1.1 AND have normal internet access.
  1. Command-line method (more precise, paste-ready)
  1. Open an elevated Command Prompt (search cmd, right-click Run as administrator).

  2. Run: netsh interface ipv4 show interfaces

    • Copy the output and note the "Idx" number and the interface Name for:
      • your internet adapter (the dongle),
      • your EZ-B adapter (the built-in WiFi when connected to the EZ-B AP). (If you prefer, paste that output here and I’ll give exact commands.)
  3. Example commands to set IP & metrics - replace <EZB_IF_NAME> and <INTERNET_IF_NAME> with the exact adapter names from the previous step. If the adapter name contains spaces include it in quotes. Example names often are "WiFi" and "WiFi 2":

Set static IP on EZB adapter (no gateway): netsh interface ipv4 set address name="<EZB_IF_NAME>" static 192.168.1.2 255.255.255.0

Set metrics (internet low metric = higher priority, EZB high metric = lower priority): netsh interface ipv4 set interface name="<INTERNET_IF_NAME>" metric=10 netsh interface ipv4 set interface name="<EZB_IF_NAME>" metric=200

  1. Add persistent route to the EZB device (replace <EZB_IF_IDX> with the interface index number you got from netsh interface ipv4 show interfaces): route -p add 192.168.1.1 mask 255.255.255.255 192.168.1.2 if <EZB_IF_IDX>

Notes on the route command:

  • We use 192.168.1.2 (the PC side static IP) as the gateway because the EZ-B is directly on that local network - Windows accepts that to indicate "send directly out this interface." If that route command fails, paste the netsh output here and I’ll give the correct exact command for your adapter/index.
  • The -p makes the route persistent across reboots.
  1. Verify:
  • ping 192.168.1.1 (should get replies from EZ-B)
  • open a web page in a browser (should still use the dongle/internet)
  1. ARC JavaScript watcher to auto stop/start PandoraBot If you still want a software safety net, add this small Script-skill JavaScript that monitors internet availability (Net.isInternetAvailable()) and stops/starts the PandoraBot skill automatically. Put it in a Script skill (JavaScript tab) and Start it.

Paste into a Script skill JavaScript tab (edit the skill name if your Pandora skill is named differently):

// PandoraBot Auto-Pause when internet lost
// Place in a Script skill (JavaScript tab) and Start it.
// Edit skillName if your Pandora skill has a different exact title.
var skillName = "PandoraBot";
var pollMs = 3000;
var wasOnline = Net.isInternetAvailable();

print("Pandora watcher starting. initial online=" + wasOnline);
if (wasOnline) {
  try { controlCommand(skillName, "ScriptStart"); } catch(e){ print("start attempt failed:"+e); }
} else {
  try { controlCommand(skillName, "ScriptStop"); } catch(e){ print("stop attempt failed:"+e); }
}

while (true) {
  try {
    var online = Net.isInternetAvailable();
    if (online && !wasOnline) {
      print("Internet restored. Starting " + skillName);
      try { controlCommand(skillName, "ScriptStart"); } catch(e){ print("start failed:"+e); }
      wasOnline = true;
    } else if (!online && wasOnline) {
      print("Internet lost. Stopping " + skillName);
      try { controlCommand(skillName, "ScriptStop"); } catch(e){ print("stop failed:"+e); }
      wasOnline = false;
    }
  } catch (err) {
    print("Watcher exception: " + err);
  }
  sleep(pollMs);
}

Notes:

  • controlCommand(skillName,"ScriptStart") and "ScriptStop" are the usual commands to start/stop script-like skills. If your Pandora skill uses different commands, tell me the exact skill title and I’ll tailor the calls.
  • This is non-invasive: if the skill is already started or stopped, the ControlCommand attempts are harmless (they will either start or do nothing).
  1. Firewall / AV and other notes
  • Third-party antivirus/endpoint software often interferes with WiFi/interface switching. If you have any 3rd-party AV, try disabling it temporarily to test.
  • Windows sometimes still prefers the "connected" interface with a default gateway. The static IP + no gateway approach prevents the EZB adapter from competing as a default gateway.
  • If you plan to roam between different networks a lot, the EZ-B Client Mode (joining the local router) is easiest - but you said you must keep AP mode, so the above approach is the correct one.
  1. Next steps I can help with (pick any)
  1. If you paste the output from: netsh interface ipv4 show interfaces I will give exact commands tailored to your adapter names/indices for you to paste and run.
  2. If the route command fails, paste the error and I’ll fix the exact syntax.
  3. If you want, I’ll tweak the Pandora watcher to log timestamps, or add a UI button to manually pause/resume Pandora.
  4. I can also give a quick checklist to watch for power/wifi dropouts while switching modes (if you still see disconnects after fixing routes).

Would you like me to:

  • Provide the exact commands now? (If so, paste the output of netsh interface ipv4 show interfaces)
  • Or do the GUI steps and try the watcher script first?

I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#67  

So, followed the instructions on how correctly fix my wifi dongle to the EZB via the windows GUI. Ran a few test making sure it stayed connected which it did. Usually the disconnects would occur in a short time.  Was even able to open up an internet connection, ARC still stayed connected. Next test, powered down this laptop, then powered it back up, with the new settings, the dongle sits and waits for an EZB to appear then connects. I was again able to connect to both EZB and an internet connection, did not lose anything.  I also tested the Pandora skill again, it too worked, did not drop. One thing though, that little Pandora Auto-pause script did not work. When I slick start, it displays a small window saying it does not recognize the control command. But I think at this point I may not need it.

Ive been able to switch between manual and automatic with no drops. Occasionally when I manually want to disconnect id forget the auto reconnect script may be running, ARC may get confused (not often) and while I am in automatic mode and I want to disconnect, I get an announcement that im in manual mode from the pc side but im really was in automatic mode. I can then just click EZB_D22 script to start and proper switched setting is announced via the EZB.

So far, generally good.

Author Avatar
PRO
Canada
#68  

Nice work - glad the static-IP + route fix cleaned up the network instability. Since things are much better now, here are targeted items to finish off the small annoyances you described (announce mismatch after reconnect, the Pandora ControlCommand error, and having to click Start manually).

I’ll give:

  • a robust JavaScript "EZB_D22 monitor" you can use in the Script skill (auto-debounce, announce after reconnect with a short "settle read"),
  • instructions to ensure it auto-starts when the EZ-B connects,
  • troubleshooting steps for the PandoraBot ControlCommand error and a small test snippet you can run to identify the correct command for that skill.

Reminder: put all JavaScript into the Script skill JavaScript tab (not the EZ-Script tab or EZ-Script Console).

  1. Robust EZB_D22 monitor (JavaScript)
  • Add a Script skill (Project -> Add robot skill -> Scripting -> Script).
  • Open the JavaScript tab and paste the code below.
  • Change skill names and ezbIndex if needed (see comments).
  • Save and Start the script.
// EZB_D22 Monitor - JavaScript
// - Debounces D22 changes
// - Keeps $Mode up to date ("Automatic" or "Manual")
// - On EZB reconnect, waits a short settle period then reliably announces the current mode
// Put this into a Script skill (JavaScript tab) and Start it.

var ezbIndex = 0;           // change if you use another EZB index
var pollMs = 120;          // how often to poll D22 (ms)
var debounceMs = 300;      // stable time to confirm a change (ms)
var settleOnConnectMs = 800;// when EZB reconnects, wait this long before reading
var lastState = null;      // null = unknown, otherwise boolean
var skillNameThis = "EZB_D22"; // optional: name of this Script skill (for logs)

// Helper: announce text using EZB TTS if available, else PC TTS
function announce(text){
  try{
    if (EZB.isConnected(ezbIndex)) Audio.sayEZB(text, ezbIndex);
    else Audio.say(text);
  } catch(e){
    print("announce error: " + e);
  }
}

// Map boolean to mode string
function modeFromBoolean(b){
  return b ? "Automatic" : "Manual";
}

// Do one reliable read with debounce
function readDebounced(){
  try{
    var a = Digital.get(d22); // use constant d22 (no quotes)
    // confirm stable for debounceMs
    var t0 = (new Date()).getTime();
    while ((new Date()).getTime() - t0 < debounceMs){
      sleep(40);
      var a2 = Digital.get(d22);
      if (a2 !== a) return null; // unstable -> treat as unknown
    }
    return !!a;
  } catch(e){
    // If Digital.get fails, return null and the loop will handle
    return null;
  }
}

// Main loop
var wasConnected = EZB.isConnected(ezbIndex);
print(skillNameThis + " starting. EZB connected=" + wasConnected);
while(true){
  try{
    var connected = EZB.isConnected(ezbIndex);

    // If we just connected, give sensors time to settle and then read
    if (!wasConnected && connected){
      print("EZB reconnected. Settling...");
      sleep(settleOnConnectMs);
      var state = readDebounced();
      if (state !== null){
        lastState = state;
        setVar("$Mode", modeFromBoolean(state));
        announce("Mode change -> " + modeFromBoolean(state) + " detected (D22=" + (state?1:0) + ").");
        print("Announced after reconnect: D22=" + (state?1:0));
      } else {
        print("Could not get stable D22 after reconnect.");
      }
    }

    // Poll when connected
    if (connected){
      var s = readDebounced();
      if (s !== null && lastState === null){
        // first known read
        lastState = s;
        setVar("$Mode", modeFromBoolean(s));
        announce("Initial mode -> " + modeFromBoolean(s) + " (D22=" + (s?1:0) + ").");
        print("Initial read: D22=" + (s?1:0));
      } else if (s !== null && s !== lastState){
        // confirmed change
        lastState = s;
        setVar("$Mode", modeFromBoolean(s));
        announce("Mode change -> " + modeFromBoolean(s) + " detected (D22=" + (s?1:0) + ").");
        print("Mode changed: D22=" + (s?1:0));
      }
    } else {
      // not connected - optionally print
      //print("EZB not connected.");
    }

    wasConnected = connected;
  } catch(err){
    print("Monitor loop exception: " + err);
  }
  sleep(pollMs);
}

Notes about the script:

  • Uses Digital.get(d22) - per ARC rules, use the constant d22 (no quotes).
  • Reads are debounced (debounceMs) to ignore quick transients during mode switching.
  • After reconnect it waits (settleOnConnectMs) then reads multiple times to ensure stable reading before announcing. This should avoid announcing the wrong mode after a reconnect.
  • It sets the global $Mode with setVar("$Mode","Automatic" / "Manual") so other scripts and your "Announce Mode Now" can use it.
  1. Auto-start the monitor when EZ-B connects This prevents having to click Start after reconnect. Add a Connection Established script that starts the monitor skill when ARC connects to the EZ-B.
  • In ARC: Project -> Connection -> Click the three-line menu -> Connection Settings (or find the Connection Established Scripts area).
  • Add a single line (replace the skill name exactly as your Script skill title):

controlCommand("EZB_D22","ScriptStart")

or, if you prefer the start-and-wait variation:

controlCommand("EZB_D22","ScriptStartWait")

Make sure "EZB_D22" exactly matches the Script skill title (case-sensitive / punctuation). This ensures your monitor will auto-start when the EZ-B connection becomes established.

  1. Why you had to click Start manually (recap)
  • If the monitor was not auto-started by the Connection Established script, it will not be running after a disconnect/reconnect. Starting via the connection script above fixes that.
  • Also ensure you removed any old reconnect monitor or duplicate scripts so only the merged monitor runs. Multiple competing scripts can cause confusion.
  1. PandoraBot ControlCommand error: unrecognized control command That error means the ControlCommand() you called used a command the target skill doesn't understand OR you passed the wrong skill name. A few checks:
  • Confirm the exact skill title: open the PandoraBot skill window and note the title in the top-left. Use that exact string in ControlCommand() (including spaces and capitalization). Example: controlCommand("Pandora Bot","ScriptStart") - only works if the Pandora skill supports that command.
  • Are you trying ScriptStart/ScriptStop? Those only work for Script skills (and Script-like skills that accept those commands). If Pandora is a different skill type, it will expect different control commands. Check the Pandora skill manual on synthiam (or the kebab menu/settings in the skill) for supported ControlCommand strings.
  • Test a small JS snippet to probe commands (put into a Script skill JS tab and Start it). This attempts ScriptStop/ScriptStart and prints the error if it fails - it won’t break anything but will reveal if the command is accepted.

Test snippet to run (JavaScript):

// Test control commands for a skill
var skillName = "PandoraBot"; // change to the exact title of the skill window
function tryCmd(cmd){
  try{
    print("Trying " + cmd + "...");
    controlCommand(skillName, cmd);
    print("Sent " + cmd + " to " + skillName);
  } catch(e){
    print("Command " + cmd + " failed: " + e);
  }
}
// Try the common script commands:
tryCmd("ScriptStop");
sleep(250);
tryCmd("ScriptStart");
sleep(250);
// If it fails, check the skill settings / documentation for the proper command.

If that prints "Command ... failed: ...", paste the exact printed error back here and tell me the exact skill title - I’ll help find the correct command to start/stop it.

  1. If you want an automatic internet watcher too Now that your networking is stable you may not need it. But if you want a safety net so PandoraBot stops automatically when internet drops and restarts when it returns, I can post a snappy watcher that uses the exact skill name and attempts ScriptStop/ScriptStart (or whatever command the test above finds).

  2. Small extra tips

  • If you still occasionally get an announce mismatch, try increasing settleOnConnectMs to 1200-1500ms (gives servos/power/time to stabilize), or increase debounceMs a bit.
  • Keep only one EZB reconnect/monitor script running - duplicates cause race conditions.
  • If the monitor logs show stable readings but announcements not heard from EZB, test Audio.sayEZB() in a small script to confirm EZB TTS audio is working after reconnect.
  1. Next steps - what would you like? Pick one:
  • I’ll paste a version of the monitor that also logs timestamps and writes a small log file.
  • I’ll provide the Internet watcher (auto Pause/Resume PandoraBot) - but first run the ControlCommand test above and tell me which start/stop command succeeded so I can tailor it.
  • Or I can tweak the monitor (longer settle, different debounce) right away.

If you want, paste the output from the test snippet above or the exact Pandora skill title, and I’ll provide the exact ControlCommand to use or the auto-pause watcher.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#69  

The new EZB_D22 script does not work. I did paste it as a JS and used correct name in the connection skill. I can click the Start, but it does nothing. So I went back to the previous script, and it that still works, and The Pandora skill still works.

I have not tried the test snippet yet.

For now, I will run some more test.

Author Avatar
PRO
Canada
#70  

Thanks - good troubleshooting so far. Since the old script still works and Pandora works, this is likely a Script-skill / JavaScript runtime issue (script not starting, immediate error, or silent exception). Let’s narrow it down with a few quick checks and a small, safe test script so we can see exactly what ARC reports.

First quick checks

  • Make sure the code is pasted into the Script skill JavaScript tab (not EZ-Script).
  • Confirm the Script skill title exactly matches the name used in your Connection Established start command.
  • After clicking Start, check the Script skill status area (top of the skill window) and the ARC bottom Status window for errors. Press COPY in the bottom Status window and paste any errors here if you see them.

Minimal test to verify the Script engine and APIs

  1. Create a brand new Script skill (Project Add robot skill Scripting Script).
  2. Open the JavaScript tab and paste exactly this test snippet:
// EZB_D22 basic sanity test - paste into Script skill JavaScript tab and Start

print("EZB_D22 test: script started");

try {
  var ezbConnected = EZB.isConnected(0);
  print("EZB.isConnected(0) => " + ezbConnected);
} catch (e) {
  print("EZB.isConnected error: " + e);
}

try {
  // read digital d22 once (no quotes)
  var d22val = Digital.get(d22);
  print("Digital.get(d22) => " + d22val);
} catch (e) {
  print("Digital.get error: " + e);
}

print("EZB_D22 test: script finished");
  1. Click Start.
  2. Copy any output shown in the script skill window (status area) and the ARC bottom Status window and paste it here.

What this tells us

  • If you see the two prints and values, the JS runtime and Digital.get work fine and we can move to the full monitor.
  • If you see an exception printed (EZB.isConnected error, Digital.get error, or other), paste it here and I’ll explain exactly what it means and fix it.
  • If nothing appears at all, the skill may be failing to start (name mismatch in Connection scripts or ARC blocked the start). Tell me exactly what the Script skill status shows (Stopped/Running/Error).

Common causes & fixes

  • Script placed in EZScript tab (or Console) instead of JavaScript tab - causes syntax errors or no runtime.
  • Wrong skill title when auto-starting via Connection Established - the ControlCommand call must match the skill title exactly.
  • Silent exception because a call ran when EZB was disconnected - the test above will show that. If Digital.get is called when EZB disconnected it should return / throw - we’ll handle that.
  • Duplicate/old reconnect scripts racing with the new monitor - ensure only one monitor/script is being auto-started.

If the basic test runs OK I’ll give a simplified, robust monitor next (safe looping, debounce, setVar("$Mode", ...), reliable announce). That monitor will also log prints so if it fails we can see why.

If the test shows an error Paste the printed error text here (from the ARC Status window or the Script skill status region). Also tell me:

  • Exact Script skill title you used for the monitor.
  • Whether you started the test while connected to the EZ-B AP. With that I’ll give the specific fix and an updated monitor script.

Want me to:

  • Wait for you to run the minimal test and paste the output? (recommended)
  • Or paste the simplified monitor now so you can swap it in and test immediately?

I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#71  

So I ran the little test script, seems to be ok? This is what it looks like running: Start EZB_D22 test: script started EZB.isConnected(0) => true Digital.get(d22) => true EZB_D22 test: script finished Done (00:00:00.0187201)

Ran the Pandora snippet script, seems to be running. Does seem to be running. If I click it again after it runs, I do get this:

User-inserted image

I have this snippet running from the Connection skill (My current init for these test).

controlCommand("HB25 Init", "ScriptStartWait") sleep(500) #wait a bit, or remove if you don't need a delay controlCommand("EZB_D22_ConnMerge", "ScriptStart") controlCommand("PandoraConnect", "ScriptStart")

But the programs all seems to be running, as I sit here, with program running, robot is idle at the moment, is in Automatic mode. I find that I do have to remember what I toggled between my disconnecting, it can then cause ARC to be confused to witch mode it may be in. Alot as improved since my wifi setup was fixed.I have alot more I want to add later (maybe in another thread).

Author Avatar
PRO
Canada
#72  

Great - thanks for the detailed update. Nice job getting the static IP/route fix working and stabilizing your WiFi setup. Since the basic JS test shows Digital.get(d22) and EZB.isConnected are working, the next step is to make the D22 monitor robust and predictable so you don't get confusing announcements after reconnects or toggles.

A few quick notes before the code:

  • I cannot view images. If you pasted a screenshot, please instead copy the exact error or status text here.
  • Put all JavaScript into a Script skill JavaScript tab (not EZ-Script or EZ-Script Console).
  • Use the kebab menu (three-line/hamburger) on a skill window to open settings or to see ControlCommand cheat sheets.
  • I’ll provide a reliable monitor script, a manual "announce now" snippet, and a manual "set mode" helper. After you add the monitor, remove any other duplicate monitors/reconnect scripts so only this one runs.
  1. Robust EZB_D22 monitor (JavaScript)
  • Debounces D22
  • On start it immediately reads D22 (so it knows correct current mode)
  • On EZB reconnect it waits a short settle delay and then reads D22 to avoid false announcements
  • Sets global $Mode ("Automatic" / "Manual")
  • Announces through EZB TTS when available, otherwise PC TTS
  • Avoids repeated runs by using a small global-run flag

Paste this into a Script skill JavaScript tab, save and Start it. Change skillTitle if your Script skill has another name, and adjust ezbIndex or timings if necessary.

// EZB_D22 Reliable Monitor - JavaScript
// Place into a Script skill (JavaScript tab) and Start.
// - Uses Digital.get(d22) (constant d22, no quotes).
// - Sets global $Mode to "Automatic" or "Manual".
// - Announces mode via EZB TTS if available, otherwise PC TTS.
// - Debounce and settle on reconnect to avoid false announcements.

var skillTitle = "EZB_D22_ConnMerge"; // update if your Script skill has a different exact title
var ezbIndex = 0;                      // change if using a different EZB index
var pollMs = 120;                      // main loop poll interval (ms)
var debounceMs = 300;                  // time to confirm a state change (ms)
var settleOnConnectMs = 900;           // wait after EZB reconnect before reading (ms)
var runFlagVar = "$EZB_D22_Running";   // global marker so Connection start doesn't spawn duplicates

// Helper: prefer EZB TTS, fallback to PC
function announce(text){
  try {
    if (EZB.isConnected(ezbIndex)) Audio.sayEZB(text, ezbIndex);
    else Audio.say(text);
  } catch(e) { print("announce error: " + e); }
}

// Map boolean digital to mode name
function modeFromBoolean(b){ return b ? "Automatic" : "Manual"; }

// Debounced read of d22. Returns true/false or null if not stable/available
function readDebouncedD22(){
  try {
    // initial read
    var a = Digital.get(d22);
    if (a === null || a === undefined) return null;
    var start = (new Date()).getTime();
    // keep checking for stable value for debounceMs
    while ((new Date()).getTime() - start < debounceMs) {
      var b = Digital.get(d22);
      if (b === null || b === undefined) return null;
      if (b !== a) return null; // changed during debounce => unstable
      sleep(20);
    }
    return !!a;
  } catch(e) {
    print("readDebouncedD22 error: " + e);
    return null;
  }
}

// Avoid duplicate instances started from Connection scripts
if (getVar(runFlagVar, "0") === "1") {
  print(skillTitle + " already running. Exiting duplicate start.");
  // exit by simply not entering the main loop
} else {
  setVar(runFlagVar, "1");
  print(skillTitle + " starting. EZB.isConnected=" + EZB.isConnected(ezbIndex));

  // main monitor
  var lastState = null;
  var wasConnected = EZB.isConnected(ezbIndex);

  // On first start, try to read immediately (but only if EZB is connected)
  if (wasConnected) {
    sleep(200); // small settle
    var s = readDebouncedD22();
    if (s !== null) {
      lastState = s;
      setVar("$Mode", modeFromBoolean(s));
      announce("Initial mode " + modeFromBoolean(s) + " (D22=" + (s?1:0) + ").");
      print("Initial read D22=" + (s?1:0));
    } else {
      print("Initial D22 read unstable/null.");
    }
  }

  // run loop (in Script skill this will run until script stopped)
  while (true) {
    try {
      var connected = EZB.isConnected(ezbIndex);

      // handle reconnect: when we detect EZB changed from disconnected->connected
      if (!wasConnected && connected) {
        print("EZB reconnected - waiting " + settleOnConnectMs + "ms to settle.");
        sleep(settleOnConnectMs);
        var state = readDebouncedD22();
        if (state !== null) {
          if (state !== lastState) {
            lastState = state;
            setVar("$Mode", modeFromBoolean(state));
            announce("Mode change  " + modeFromBoolean(state) + " (D22=" + (state?1:0) + ").");
            print("Announced after reconnect D22=" + (state?1:0));
          } else {
            // still announce current mode once to confirm to user after reconnect
            setVar("$Mode", modeFromBoolean(state));
            announce("Mode " + modeFromBoolean(state) + " (D22=" + (state?1:0) + ").");
            print("Reconnected; re-announced D22=" + (state?1:0));
          }
        } else {
          print("After reconnect: D22 unstable/null - no announcement.");
        }
      }

      // normal polling when connected
      if (connected) {
        var s = readDebouncedD22();
        if (s !== null && lastState === null) {
          // first known read
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          announce("Initial mode " + modeFromBoolean(s) + " (D22=" + (s?1:0) + ").");
          print("First stable read D22=" + (s?1:0));
        } else if (s !== null && s !== lastState) {
          // stable change detected
          lastState = s;
          setVar("$Mode", modeFromBoolean(s));
          announce("Mode change  " + modeFromBoolean(s) + " (D22=" + (s?1:0) + ").");
          print("Mode changed D22=" + (s?1:0));
        }
      } else {
        // EZB not connected - nothing to do
        // print("EZB not connected.");
      }

      wasConnected = connected;
    } catch(loopErr) {
      print("Monitor loop exception: " + loopErr);
    }
    sleep(pollMs);
  } // end loop

  // NOTE: We never reach here unless script stopped externally
  // When script stops, clear run flag in a finally/cleanup would be ideal,
  // but Script skill stops do not raise an event we can reliably trap in all cases.
  // You can manually set setVar(runFlagVar, "0") when stopping from console if needed.
}

Important follow-up / usage tips

  • Make sure the Connection Established script starts this exact skill name only once: e.g. controlCommand("EZB_D22_ConnMerge","ScriptStart") (Open the Connection skill settings via the kebab menu and edit Connection Established Scripts.)
  • Remove any other script start lines that start older D22/reconnect monitors. Duplicate monitors cause conflicting announcements and confusion.
  • If you sometimes need to stop the script manually and re-start it, clear the run flag first for safety: In a small Script skill or Console run:
    setVar("$EZB_D22_Running","0");
    
    Then run ControlCommand to start the monitor again.
  1. Manual helpers (quick paste-and-run)
  • Announce Mode Now (reads $Mode and announces it)
// Announce current $Mode now
var ezbIndex = 0;
var m = getVar("$Mode","Unknown");
try {
  if (EZB.isConnected(ezbIndex)) Audio.sayEZB("Current mode is " + m, ezbIndex);
  else Audio.say("Current mode is " + m);
} catch(e){ print("Announce error: " + e); }
  • Force Set Mode (manually set mode and announce)
// Force set $Mode to "Manual" or "Automatic" and announce
var newMode = "Manual"; // change to "Automatic" as needed
setVar("$Mode", newMode);
try {
  if (EZB.isConnected(0)) Audio.sayEZB("Mode forced to " + newMode, 0);
  else Audio.say("Mode forced to " + newMode);
} catch(e){ print("Force-set announce error: " + e); }
  1. Pandora skill ControlCommand failure You mentioned earlier that a small test reported "unrecognized control command" when trying to start/stop Pandora. Run this test snippet (adjust the skillName to the exact skill title shown in the Pandora window title bar) - paste results here if it fails:
// Test control commands for a skill
var skillName = "PandoraConnect"; // change to EXACT skill title
function tryCmd(cmd){
  try {
    print("Trying " + cmd + "...");
    controlCommand(skillName, cmd);
    print("Sent " + cmd + " to " + skillName);
  } catch(e) {
    print("Command " + cmd + " failed: " + e);
  }
}
tryCmd("ScriptStop");
sleep(250);
tryCmd("ScriptStart");

If that prints an error, copy the exact printed error text and the exact skill window title so I can map the correct ControlCommand used by that skill. (Remember I cannot view images - paste the text.)

  1. Connection Established scripts: how to edit
  • Open Project Connection click the kebab/three-line menu Connection Settings scroll to Connection Established Scripts.
  • Edit so it only starts the monitor and any required initial scripts, example: controlCommand("HB25 Init","ScriptStartWait") sleep(500) controlCommand("EZB_D22_ConnMerge","ScriptStart") controlCommand("PandoraConnect","ScriptStart") <-- only if Pandora supports ScriptStart, otherwise remove
  • Make sure skill names exactly match their window titles (case & spaces).
  1. If you still get mismatched announcements
  • Confirm the only script that announces mode is this monitor (and the manual helper if you run it).
  • If you have other scripts that also announce, remove or disable their announce calls.
  • If you still see mismatches at reconnect, increase settleOnConnectMs to 1200-1500 ms and/or increase debounceMs. Also ensure the power supply to servos/receivers is not causing brief transients when you flip the RC selector.

Next steps - what do you want me to do now?

  • I can provide a variant of the monitor that writes a timestamped log line (File.appendString) when modes change so you can review events.
  • I can craft an auto-pauser for Pandora (if you want the watcher to stop/start Pandora on internet changes) - but first run the test above to confirm what control commands Pandora accepts.
  • If the monitor still won’t start from Connection Established scripts, paste the exact text you use in the Connection Established Scripts box and the exact Script skill title(s) so I can review for typos.

Which would you like next?


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.