Asked
Resolved Resolved by Athena!

Handling Weather Script Connection Errors

I have a JavaScript in ARC that go onto the Internet and retrieves a full weather report from a Weather service, parses information out of the returned file and has the robot speak the information

For Example: A section of my ARC Setup INT script will set the  variable $OutsideTemp to "1" and then a ControlCommand will start a separate JavaScript that will run the above mentioned procedure. The INT script will then pause. Once the second script receives the weather file from the weather service, it's parsed, the robot recites the temperature along with some movement automations, this script will change the $OutsideTemp variable from "1" to "0". This variable change will signal the waiting INT script that this step is complete and it will proceed to the next step.

OK, my problem is if for some reason the computer isn't connected to the internet or the weather service being called for info does not return the file the second script stalls with an error, will not proceed through the rest of the script and in the end will not change the $OutsideTemp from 1 to 0 signaling the end of the script. This in turn stalls the INT script and the robot will not finish setting up and start running.

OK, how can I add commands to the Weather script that will let this script know that nothing was received from the weather service, then move to the end of the script? I think an even better solution would if the script calling the weather service would know the file was not returned or couldn't connect and end in that spot of the script. It would then set the variable to 0 so the INT script could proceed without this info.

I'll post my scripts below so I can get informed advice. I'm open to all advice, rewrites or constructive criticism. Thanks!

Here's the part of my INT script that calls the temp from the weather service:

//Temp
//---------------
ControlCommand("Head Section", "ScriptStart", "Bubble Full Down");
setVar( "$OutsideTemp", 1 ); //Sets Varaible so Script will run
ControlCommand("Time, Date & Temp", "ScriptStart", "Outside Temp");
while (getVar("$OutsideTemp")== 1) { //Pause script for Temp report
   sleep(100);
}

Here's my script that calls the weather service files, parses it and has the robot speak it:

ControlCommand("Personality Generator", "PauseOn");

//Start anamation //---------------------------- setVar( "$OutsideTemp", 1 ); //Sets Varaible so Script will run PWM.set(D0, 70); //Start Ear Motors PWM.set(D9, 20); //Start Crown Motor ControlCommand("Head Section", "ScriptStart", "Radar 1/4 Sweep"); ControlCommand("Left Arm", "ScriptStart", "Left Claw Open"); ControlCommand("Right Arm", "ScriptStart", "Right Claw Closed");

//Get weather conditions from openweathermao.org var url1 = "https://api.openweathermap.org/you dont need to see this part. HAHA" var content = Net.hTTPGet(url1);

//Read Tempture //--------------- pos = 0; beginPos = pos; pos = content.indexOf("temp", beginPos); endPos = pos; otherend = content.indexOf(",",endPos); var temp = content.substring((endPos+6),(otherend)); //temp = (temp*1.8)-459.67 //Math offset if returned value is returned in Kelvin Units (Defalt) //temp = (temp.toFixed(1)) //Math offset if returned value is returned in Kelvin Units (Defalt)

//Round temp returned to whole number //----------------------------------- var tempRound = Math.round(temp) print("Temperature Rounded: " + tempRound);

controlCommand("Phrases", "Track_17"); //Say "The Temp is at"

sleep(1750)

//**************** //this block extracts numbers out of tempRound Variable where the temp is stored // and places each digit into it's own variable so orbot can speak each digit. //****************

    // Convert the number to a string
    var numberString = tempRound.toString();
    
    // Now, we can access each digit using indexing
    var firstDigit = numberString.charAt(0); // First Digit
    var secondDigit = numberString.charAt(1); // Second Diget
    var thirdDigit = numberString.charAt(2); // Third Digit if needed

// Now we can use firstDigitNumber and secondDigitNumber as needed

Console.log(firstDigit); // Outputs first digit Console.log(secondDigit); // Outputs second digit

//Say first digit in temp, 20 - 90 //-------------------------------- if (firstDigit == 2) { ControlCommand("Numbers", "Track_20"); //Say 20" sleep(1250); } else if (firstDigit == 3) { ControlCommand("Numbers", "Track_21"); //Say 30" sleep(1300); } else if (firstDigit == 4) { ControlCommand("Numbers", "Track_22"); //Say 40" sleep(1350); } else if (firstDigit == 5) { ControlCommand("Numbers", "Track_23"); //Say 50" sleep(1300); } else if (firstDigit == 6) { ControlCommand("Numbers", "Track_24"); //Say 60" sleep(1400); } else if (firstDigit == 7) { ControlCommand("Numbers", "Track_25"); //Say 70" sleep(1400); } else if (firstDigit == 8) { ControlCommand("Numbers", "Track_26"); //Say 80" sleep(1350); } else if (firstDigit == 9) { ControlCommand("Numbers", "Track_27"); //Say 90" sleep(1400); }

//Say second digit in temp, 1 - 9 //--------------------------------
if (secondDigit == 0) { ControlCommand("Phrases", "Track_3"); //Say "Degrees Fahrenheait" sleep(1900); //controlCommand("Phrases", "Track_12"); //Say "On this Alien Planet" //sleep(2000); PWM.set(D0, 0); //Start Ear Motors PWM.set(D9, 0); //Start Crown Motor setVar( "$OutsideTemp", 0 ); //Clears Varaible so next Script will run halt(); } else if (secondDigit == 1) { ControlCommand("Numbers", "Track_1"); //Say "1" sleep(1350); } else if (secondDigit == 2) { ControlCommand("Numbers", "Track_2"); //Say "2" sleep(1250); } else if (secondDigit == 3) { ControlCommand("Numbers", "Track_3"); //Say "3" sleep(1400); } else if (secondDigit == 4) { ControlCommand("Numbers", "Track_4"); //Say "4" sleep(1450); } else if (secondDigit == 5) { ControlCommand("Numbers", "Track_5"); //Say "5" sleep(1450); } else if (secondDigit == 6) { ControlCommand("Numbers", "Track_6"); //Say "6" sleep(1450); } else if (secondDigit == 7) { ControlCommand("Numbers", "Track_7"); //Say "7" sleep(1400); } else if (secondDigit == 8) { ControlCommand("Numbers", "Track_8"); //Say "8" sleep(1400); } else if (secondDigit == 9) { ControlCommand("Numbers", "Track_9"); //Say "9" sleep(1450); }

//Shut down anamations //--------------------------------------------------------------- ControlCommand("Phrases", "Track_3"); //Say "Degrees Fahrenheait" sleep(1900) //controlCommand("Phrases", "Track_12"); //Say "On this Alien Planet" PWM.set(D0, 0); //Start Ear Motors PWM.set(D9, 0); //Start Crown Motor setVar( "$OutsideTemp", 0 ); //Clears Varaible so next Script will run

ControlCommand("Personality Generator", "PauseOff"); ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");


Related Hardware EZ-B v4
Related Controls Script On Variable Changed

ARC Pro

Upgrade to ARC Pro

ARC Pro is your passport to a world of endless possibilities in robot programming, waiting for you to explore.

#1   — Edited

Here's the second script again that calls the weather service. The above code I posted looks messy. Edited. thanks.

ControlCommand("Personality Generator", "PauseOn");

//Start anamation
//----------------------------
setVar( "$OutsideTemp", 1 ); //Sets Varaible so Script will run
PWM.set(D0, 70); //Start Ear Motors
PWM.set(D9, 20); //Start Crown Motor
ControlCommand("Head Section", "ScriptStart", "Radar 1/4 Sweep");
ControlCommand("Left Arm", "ScriptStart", "Left Claw Open");
ControlCommand("Right Arm", "ScriptStart", "Right Claw Closed");

//Get weather conditions from openweathermao.org
var url1 = "https://api.openweathermap.org/*******************************************";
var content = Net.hTTPGet(url1);

//Read Tempture
//---------------
pos = 0;
beginPos = pos;
pos = content.indexOf("temp", beginPos);
endPos = pos;
otherend = content.indexOf(",",endPos);
var temp = content.substring((endPos+6),(otherend));
//temp = (temp*1.8)-459.67  //Math offset if returned value is returned in Kelvin Units (Defalt) 
//temp = (temp.toFixed(1))  //Math offset if returned value is returned in Kelvin Units (Defalt) 

//Round temp returned to whole number
//-----------------------------------
var tempRound = Math.round(temp)
print("Temperature Rounded: " + tempRound); 

controlCommand("Phrases", "Track_17"); //Say "The Temp is at"
      
sleep(1750)
        
//****************
//this block extracts numbers out of tempRound Variable where the temp is stored
// and places each digit into it's own variable so orbot can speak each digit.
//****************
       
        // Convert the number to a string
        var numberString = tempRound.toString();
        
        // Now, we can access each digit using indexing
        var firstDigit = numberString.charAt(0); // First Digit
        var secondDigit = numberString.charAt(1); // Second Diget
        var thirdDigit = numberString.charAt(2); // Third Digit if needed
// Now we can use firstDigitNumber and secondDigitNumber as needed

Console.log(firstDigit); // Outputs first digit
Console.log(secondDigit); // Outputs second digit 

//Say first digit in temp, 20 - 90
//--------------------------------
if (firstDigit == 2) {
  ControlCommand("Numbers", "Track_20"); //Say 20"
  sleep(1250);
} else if (firstDigit == 3) {
  ControlCommand("Numbers", "Track_21"); //Say 30"
  sleep(1300);
} else if (firstDigit == 4) {
  ControlCommand("Numbers", "Track_22"); //Say 40"
  sleep(1350);
} else if (firstDigit == 5) {
  ControlCommand("Numbers", "Track_23"); //Say 50"
  sleep(1300);
} else if (firstDigit == 6) {
  ControlCommand("Numbers", "Track_24"); //Say 60"
  sleep(1400);
} else if (firstDigit == 7) {
  ControlCommand("Numbers", "Track_25"); //Say 70"
  sleep(1400);
} else if (firstDigit == 8) {
  ControlCommand("Numbers", "Track_26"); //Say 80"
  sleep(1350);
} else if (firstDigit == 9) {
  ControlCommand("Numbers", "Track_27"); //Say 90"
  sleep(1400);
} 
  
//Say second digit in temp, 1 - 9
//--------------------------------  
if (secondDigit == 0) {
  ControlCommand("Phrases", "Track_3"); //Say "Degrees Fahrenheait"
  sleep(1900);
  //controlCommand("Phrases", "Track_12"); //Say "On this Alien Planet"
  //sleep(2000);
  PWM.set(D0, 0); //Start Ear Motors
  PWM.set(D9, 0); //Start Crown Motor
  setVar( "$OutsideTemp", 0 ); //Clears  Varaible so next Script will run
  halt();
}  else if (secondDigit == 1) {
  ControlCommand("Numbers", "Track_1"); //Say "1"
  sleep(1350);
}  else if (secondDigit == 2) {
  ControlCommand("Numbers", "Track_2"); //Say "2"
  sleep(1250);
} else if (secondDigit == 3) {
  ControlCommand("Numbers", "Track_3"); //Say "3"
  sleep(1400);
} else if (secondDigit == 4) {
  ControlCommand("Numbers", "Track_4"); //Say "4"
  sleep(1450);
} else if (secondDigit == 5) {
  ControlCommand("Numbers", "Track_5"); //Say "5"
  sleep(1450);
} else if (secondDigit == 6) {
  ControlCommand("Numbers", "Track_6"); //Say "6"
  sleep(1450);
} else if (secondDigit == 7) {
  ControlCommand("Numbers", "Track_7"); //Say "7"
  sleep(1400);
} else if (secondDigit == 8) {
  ControlCommand("Numbers", "Track_8"); //Say "8"
  sleep(1400);
} else if (secondDigit == 9) {
  ControlCommand("Numbers", "Track_9"); //Say "9"
  sleep(1450);
}

//Shut down anamations
//---------------------------------------------------------------
ControlCommand("Phrases", "Track_3"); //Say "Degrees Fahrenheait"
sleep(1900)
//controlCommand("Phrases", "Track_12"); //Say "On this Alien Planet"
PWM.set(D0, 0); //Start Ear Motors
PWM.set(D9, 0); //Start Crown Motor
setVar( "$OutsideTemp", 0 ); //Clears Varaible so next Script will run

ControlCommand("Personality Generator", "PauseOff");
ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");
PRO
Canada
#2  

Hi Dave - I’m Athena. Nice work describing the problem and posting your code. The root cause is that when the weather fetch or parsing fails, your weather script never reaches the cleanup code that sets $OutsideTemp back to 0. That blocks the INT script which is waiting for that variable.

Below are concise fixes and a safe, refactored JavaScript you can drop into ARC. The key ideas:

  • Check Internet first with Net.isInternetAvailable()
  • Use Net.hTTPGet(url, timeout) so the request won’t hang indefinitely
  • Validate the returned content and use JSON.parse() for robust parsing (instead of indexOf substring hacks)
  • Always setVar("$OutsideTemp","0") and stop animations on every exit path (success or any error)
  • Use return to end the script cleanly (instead of letting an error leave you stuck)

Useful references:

Example robust weather script (replace YOUR_API_KEY and adjust Track/ControlCommand names to your project):

// Robust Weather Script for ARC (JavaScript)
ControlCommand(Personality Generator,PauseOn);

// Signal start to the INT script
setVar("$OutsideTemp","1");

// Start animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand(Head Section,ScriptStart,Radar 1/4 Sweep);
ControlCommand(Left Arm,ScriptStart,Left Claw Open);
ControlCommand(Right Arm,ScriptStart,Right Claw Closed);

// Build your OpenWeather URL (replace API key and ensure proper & separators)
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid=YOUR_API_KEY";;

// Helper cleanup function to always restore state and set the flag back to 0
function cleanupAndExit(message) {
  if (message) print(message);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand(Personality Generator,PauseOff);
  setVar("$OutsideTemp","0");
  // If you want the script to stop now:
  return;
}

// 1) Check Internet first
if (!Net.isInternetAvailable()) {
  cleanupAndExit("No internet available.");
  return;
}

// 2) Fetch with timeout (ms)
var timeoutMs = 7000; // adjust as you like
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch (e) {
  cleanupAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate response
if (!content || content.length < 5) {
  cleanupAndExit("Empty or invalid response from weather service.");
  return;
}

// 4) Parse JSON and extract temperature
var temp;
try {
  var data = JSON.parse(content);
  // OneCall v3 returns current.temp for current conditions
  temp = (data && data.current && data.current.temp) ? data.current.temp : undefined;
  if (temp === undefined) {
    cleanupAndExit("Temperature not found in response.");
    return;
  }
} catch (e) {
  cleanupAndExit("Failed to parse weather response: " + e);
  return;
}

// 5) We have a valid temperature - proceed to speak it
var tempRound = Math.round(temp);
print("Temperature Rounded: " + tempRound);

// Example: say the lead text, then digits (replace Track_ names with yours)
ControlCommand(Phrases,Track_17); // "The temperature is"
sleep(1500);

// Convert to string and speak tens and ones (adapt to your audio clips / tracks)
var s = tempRound.toString();
var firstDigit = s.charAt(0);
var secondDigit = s.length > 1 ? s.charAt(1) : null;

// Function to say tens (20,30,...)
function sayTens(d) {
  if (d == "2") ControlCommand(Numbers,Track_20);
  else if (d == "3") ControlCommand(Numbers,Track_21);
  else if (d == "4") ControlCommand(Numbers,Track_22);
  else if (d == "5") ControlCommand(Numbers,Track_23);
  else if (d == "6") ControlCommand(Numbers,Track_24);
  else if (d == "7") ControlCommand(Numbers,Track_25);
  else if (d == "8") ControlCommand(Numbers,Track_26);
  else if (d == "9") ControlCommand(Numbers,Track_27);
  sleep(1300);
}

function sayOnes(d) {
  if (d == "0") { ControlCommand(Phrases,Track_3); sleep(1800); return; } // Degrees Fahrenheit or "zero"
  if (d == "1") ControlCommand(Numbers,Track_1);
  else if (d == "2") ControlCommand(Numbers,Track_2);
  else if (d == "3") ControlCommand(Numbers,Track_3);
  else if (d == "4") ControlCommand(Numbers,Track_4);
  else if (d == "5") ControlCommand(Numbers,Track_5);
  else if (d == "6") ControlCommand(Numbers,Track_6);
  else if (d == "7") ControlCommand(Numbers,Track_7);
  else if (d == "8") ControlCommand(Numbers,Track_8);
  else if (d == "9") ControlCommand(Numbers,Track_9);
  sleep(1400);
}

// If 2-digit (20-99) speak tens first, else for single-digit just speak the ones
if (s.length >= 2) {
  sayTens(firstDigit);
  if (secondDigit !== null) sayOnes(secondDigit);
} else {
  sayOnes(firstDigit);
}

// Finalize
PWM.set(d0,0);
PWM.set(d9,0);
ControlCommand(Personality Generator,PauseOff);
ControlCommand(Script Manager,ScriptStart,Both Claws Rest Closed);
setVar("$OutsideTemp","0"); // Important: always clear the flag so the INT script continues

How to update your INT script (make it robust and responsive):

  • Use string values consistently for global variables and a shorter sleep so it doesn’t block too long.

Example INT snippet:

setVar("$OutsideTemp","1");
ControlCommand(Time,Date Temp,ScriptStart,Outside Temp);
// wait until weather script clears the flag
while (getVar("$OutsideTemp","0") == "1") {
  sleep(100); // check frequently but not constantly
}

Notes and tips:

  • Replace YOUR_API_KEY with your actual OpenWeather API key. Ensure the URL uses & between parameters and proper lat/lon formatting.
  • Net.hTTPGet(url, timeout) will return nothing after timeout; you must handle that case (the example does).
  • Use JSON.parse(content) rather than substring/indexOf; it’s far more reliable with the OpenWeather JSON.
  • If you want automatic reaction to network status (e.g., change behavior when WiFi goes down), consider configuring the Network Change skill to set a global variable that your scripts monitor. See: https://synthiam.com/Support/Skills/Communication/Network-Change?id=20489
  • If you’d like, I can refactor the entire speak-digit section into a more compact function that handles negatives, 3-digit temps, and units.

Would you like me to:

  • (A) Paste a fully refactored script that speaks negative temps and handles single / three-digit numbers, or
  • (B) Help fix your exact original script line-by-line (keeping your ControlCommand track names)?

Tell me which and paste your exact working OpenWeather URL (with key omitted) if you want me to test the parsing logic for that JSON shape.


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.
#3  

@Athena

The temperature script you rewrote for me seems to be working nicely. I did have to make a few adjustments to get it to run. Mainly I needed to Define the script names and voice file tracks in the ComandControl commands with parentheses (" ") like this:  ControlCommand("Soundboard 2", "Track_26");

I see there are (I think) four different places in this script where a check is made to see if the internet is disconnected or the proper information was returned. If not the script will return to end the script cleanly (instead of letting an error leave you stuck).

I'd like to have a verbal response from the robot if this ever happens.   Could you add the following ControlCommands that trigger voice files to this script in the proper places of each case if the above happens?"

ControlCommand("Soundboard 2", "Track_26"); //Say "Not"
  sleep(600);
  ControlCommand("Soundboard v4", "Track_20"); //Say "Active"
  sleep(1000);
PRO
Canada
#4  

Great - glad the script is working well. I added the requested voice response (Soundboard 2 Track_26 "Not", then Soundboard v4 Track_20 "Active") into each error/early-exit path so the robot will speak when the internet or weather data is not available.

Below is the updated JavaScript you can drop into ARC. It:

  • checks internet first,
  • uses Net.hTTPGet(url, timeout) with try/catch,
  • verifies returned content and JSON parsing,
  • checks for the temp field in common OpenWeather response shapes,
  • in every error path plays your two soundboard tracks, then performs cleanup and sets $OutsideTemp back to "0" so the INT script can continue.

Note: I used quoted ControlCommand strings (as you found necessary). If your soundboard or track names differ, replace the names exactly.

// Robust Weather Script with verbal "Not Active" on failure
ControlCommand("Personality Generator","PauseOn");
setVar("$OutsideTemp","1");

// Start animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Left Arm","ScriptStart","Left Claw Open");
ControlCommand("Right Arm","ScriptStart","Right Claw Closed");

// Replace with your actual OpenWeather URL (units & API key)
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.66163&lon=-81.97033&units=imperial&appid=YOUR_API_KEY";;
var timeoutMs = 7000; // HTTP timeout in ms

function cleanupSuccess(){
  // stop animations and restore state
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$OutsideTemp","0");
  return;
}

function errorSpeakAndExit(msg){
  if(msg) print(msg);
  // Play the requested voice lines before exiting
  ControlCommand("Soundboard 2","Track_26"); // Say "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // Say "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// 1) Internet available?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET with timeout + error handling
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 10){
  errorSpeakAndExit("Empty or invalid response.");
  return;
}

// 4) Parse JSON safely
var data = null;
try {
  data = JSON.parse(content);
} catch(e) {
  errorSpeakAndExit("JSON parse failed: " + e);
  return;
}

// 5) Extract temperature (support common OpenWeather shapes)
var tempVal = null;
if(data.current && data.current.temp !== undefined) tempVal = data.current.temp;
else if(data.main && data.main.temp !== undefined) tempVal = data.main.temp;
else if(data.temp !== undefined) tempVal = data.temp;

if(tempVal === null){
  errorSpeakAndExit("Temperature value not found in response.");
  return;
}

// Continue normal processing: round, speak digits, etc.
var tempRound = Math.round(Number(tempVal));
print("Temperature Rounded: " + tempRound);

ControlCommand("Phrases","Track_17"); // "The Temp is at"
sleep(1750);

// Convert number to string and speak tens/ones as your previous logic
var numberString = tempRound.toString();
var firstDigit = numberString.charAt(0);
var secondDigit = (numberString.length > 1) ? numberString.charAt(1) : null;

// small helper functions for speaking
function sayTens(d){
  if(d == "2") ControlCommand("Numbers","Track_20");
  else if(d == "3") ControlCommand("Numbers","Track_21");
  else if(d == "4") ControlCommand("Numbers","Track_22");
  else if(d == "5") ControlCommand("Numbers","Track_23");
  else if(d == "6") ControlCommand("Numbers","Track_24");
  else if(d == "7") ControlCommand("Numbers","Track_25");
  else if(d == "8") ControlCommand("Numbers","Track_26");
  else if(d == "9") ControlCommand("Numbers","Track_27");
  sleep(1300);
}
function sayOnes(d){
  if(d == "0"){ ControlCommand("Phrases","Track_3"); sleep(1800); return; }
  if(d == "1") ControlCommand("Numbers","Track_1");
  else if(d == "2") ControlCommand("Numbers","Track_2");
  else if(d == "3") ControlCommand("Numbers","Track_3");
  else if(d == "4") ControlCommand("Numbers","Track_4");
  else if(d == "5") ControlCommand("Numbers","Track_5");
  else if(d == "6") ControlCommand("Numbers","Track_6");
  else if(d == "7") ControlCommand("Numbers","Track_7");
  else if(d == "8") ControlCommand("Numbers","Track_8");
  else if(d == "9") ControlCommand("Numbers","Track_9");
  sleep(1400);
}

// Speak digits
if(numberString.length >= 2){
  sayTens(firstDigit);
  if(secondDigit !== null) sayOnes(secondDigit);
} else {
  sayOnes(firstDigit);
}

// Finish normal cleanup
cleanupSuccess();

Notes and tips

  • Confirm your Soundboard names/tracks: are the exact control names "Soundboard 2" and "Soundboard v4"? If they differ, update those strings.
  • If you want the robot to speak a different phrase than "Not Active", change the tracks used or add a custom combined phrase track.
  • Timeout can be increased if you want slower networks to succeed (timeoutMs).
  • If you want me to also insert a spoken message for success (e.g., "Weather ready"), tell me which soundboard/track to use and I can add it.

Would you like me to:

  1. Adjust timing between the two soundboard tracks, or
  2. Add a single combined "Not Active" sound file instead of two separate tracks?

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.
#5   — Edited

@Athena ,  Thank you. With a couple minor adjustments my Temperature script you rewrote for me works as needed. When it sees a disconnected internet to the computer or there is no response or a response not understood from the weather website it will stop, print a message, give me a verbal notice, move on and finish the remaining script. Here is my final script that works as needed. Thnaks:

// Robust Weather Script with verbal "Not Active" on failure
ControlCommand("Personality Generator","PauseOn");
setVar("$OutsideTemp","1");

// Start animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Left Arm","ScriptStart","Left Claw Open");
ControlCommand("Right Arm","ScriptStart","Right Claw Closed");

// Replace with your actual OpenWeather URL (units & API key)
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&; Your Key Goes Here"
var timeoutMs = 7000; // HTTP timeout in ms

function cleanupSuccess(){
  // stop animations and restore state
  ControlCommand("Phrases", "Track_3"); //Say "Degrees Fahrenheait"
sleep(2300);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$OutsideTemp","0");
  return;
}

function errorSpeakAndExit(msg){
  if(msg) print(msg);
  // Play the requested voice lines before exiting
  ControlCommand("Soundboard 2","Track_26"); // Say "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // Say "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// 1) Internet available?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET with timeout + error handling
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 10){
  errorSpeakAndExit("Empty or invalid response.");
  return;
}

// 4) Parse JSON safely
var data = null;
try {
  data = JSON.parse(content);
} catch(e) {
  errorSpeakAndExit("JSON parse failed: " + e);
  return;
}

// 5) Extract temperature (support common OpenWeather shapes)
var tempVal = null;
if(data.current && data.current.temp !== undefined) tempVal = data.current.temp;
else if(data.main && data.main.temp !== undefined) tempVal = data.main.temp;
else if(data.temp !== undefined) tempVal = data.temp;

if(tempVal === null){
  errorSpeakAndExit("Temperature value not found in response.");
  return;
}

// Continue normal processing: round, speak digits, etc.
var tempRound = Math.round(Number(tempVal));
print("Temperature Rounded: " + tempRound);

ControlCommand("Phrases","Track_17"); // "The Temp is at"
sleep(1750);

// Convert number to string and speak tens/ones as your previous logic
var numberString = tempRound.toString();
var firstDigit = numberString.charAt(0);
var secondDigit = (numberString.length > 1) ? numberString.charAt(1) : null;

// small helper functions for speaking
function sayTens(d){
  if(d == "2") ControlCommand("Numbers","Track_20");
  else if(d == "3") ControlCommand("Numbers","Track_21");
  else if(d == "4") ControlCommand("Numbers","Track_22");
  else if(d == "5") ControlCommand("Numbers","Track_23");
  else if(d == "6") ControlCommand("Numbers","Track_24");
  else if(d == "7") ControlCommand("Numbers","Track_25");
  else if(d == "8") ControlCommand("Numbers","Track_26");
  else if(d == "9") ControlCommand("Numbers","Track_27");
  sleep(1300);
}
function sayOnes(d){
  if(d == "0"){ ControlCommand("Phrases","Track_3"); sleep(1800); return; }
  if(d == "1") ControlCommand("Numbers","Track_1");
  else if(d == "2") ControlCommand("Numbers","Track_2");
  else if(d == "3") ControlCommand("Numbers","Track_3");
  else if(d == "4") ControlCommand("Numbers","Track_4");
  else if(d == "5") ControlCommand("Numbers","Track_5");
  else if(d == "6") ControlCommand("Numbers","Track_6");
  else if(d == "7") ControlCommand("Numbers","Track_7");
  else if(d == "8") ControlCommand("Numbers","Track_8");
  else if(d == "9") ControlCommand("Numbers","Track_9");
  sleep(1400);
}

// Speak digits
if(numberString.length >= 2){
  sayTens(firstDigit);
  if(secondDigit !== null) sayOnes(secondDigit);
} else {
  sayOnes(firstDigit);
}

// Finish normal cleanup
cleanupSuccess();

I also have two other weather scripts that need to be rewritten with the same changes as my Temperature script. One is a call for the local Humidly and the other is for local Wind Speed. Can you please rewrite each of the following script with the same considerations and changes that you did for the Temp script? Here they are:

Wind Speed:

ControlCommand("Personality Generator", "PauseOn");

//Start up robot anamations
 //--------------------------------------
setVar( "$WSpeed", 1 ); //Sets Varaible so Script will run
PWM.set(D0, 70); //Start Ear Motors
PWM.set(D9, 20); //Start Crown Motor
ControlCommand("Head Section", "ScriptStart", "Radar 1/4 Sweep");
ControlCommand("Script Manager", "ScriptStart", "Both Claws Closed");

//Get cuttent weather conditions from openweathermap.org
var url1 = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&; Key goes here"
var content = Net.hTTPGet(url1);

//Read Wind Speed & set variables
//-----------------------------------------
pos = 0;
beginPos = pos;
pos = content.indexOf("speed", beginPos);
endPos = pos;
otherend = content.indexOf(",",endPos);
var wspeed = content.substring((endPos+7),(otherend));
print("Wind Speed: " + wspeed);

//Round returned windspeed to get rid of decimal point
var wSpeedRound = Math.round(wspeed)
print("Wind Speed Rounded: " + wSpeedRound); 

//Change to string so we can read the numbers as a group
var wSpeedRound= wSpeedRound.toString();
    
ControlCommand("Phrases", "Track_13"); //Say "The Wind Volisity is at"
        sleep(2100)

//Say Windspeed if 19 MPH or below
//--------------------------------
if (wSpeedRound <= 19) {
  if (wSpeedRound == 0) {
    ControlCommand("Numbers", "Track_0"); //Say "0"
}    else if (wSpeedRound == 1) {
    ControlCommand("Numbers", "Track_1"); //Say "1"
}    else if (wSpeedRound == 2) {
    ControlCommand("Numbers", "Track_2"); //Say "2"
}   else if (wSpeedRound == 3) {
    ControlCommand("Numbers", "Track_3"); //Say "3"
}   else if (wSpeedRound == 4) {
    ControlCommand("Numbers", "Track_4"); //Say "4"
}   else if (wSpeedRound == 5) {
    ControlCommand("Numbers", "Track_5"); //Say "5"
}   else if (wSpeedRound == 6) {
    ControlCommand("Numbers", "Track_6"); //Say "6"
}   else if (wSpeedRound == 7) {
    ControlCommand("Numbers", "Track_7"); //Say "7"
}   else if (wSpeedRound == 8) {
    ControlCommand("Numbers", "Track_8"); //Say "8"
}   else if (wSpeedRound == 9) {
    ControlCommand("Numbers", "Track_9"); //Say "9"
}    else if (wSpeedRound == 10) {
    ControlCommand("Numbers", "Track_10"); //Say "10"
}    else if (wSpeedRound == 11) {
    ControlCommand("Numbers", "Track_11"); //Say "11"
}   else if (wSpeedRound == 12) {
    ControlCommand("Numbers", "Track_12"); //Say "12"
}   else if (wSpeedRound == 13) {
    ControlCommand("Numbers", "Track_13"); //Say "13"
}   else if (wSpeedRound == 14) {
    ControlCommand("Numbers", "Track_14"); //Say "14"
}   else if (wSpeedRound == 15) {
    ControlCommand("Numbers", "Track_15"); //Say "15"
}   else if (wSpeedRound == 16) {
    ControlCommand("Numbers", "Track_16"); //Say "16"
}   else if (wSpeedRound == 17) {
    ControlCommand("Numbers", "Track_17"); //Say "17"
}   else if (wSpeedRound == 18) {
    ControlCommand("Numbers", "Track_18"); //Say "18"
}   else if (wSpeedRound == 19) {
    ControlCommand("Numbers", "Track_19"); //Say "19"
} 
}

//Say windspeed if 20 MPH or above
//--------------------------------
if  (wSpeedRound >= 20) {
 //****************
 //this block extracts numbers out of tempRound Variable where the temp is stored
 // and places each digit into it's own variable so orbot can speak each digit.
 //****************
        // Now, we can access each digit using indexing
        var firstDigit = wSpeedRound.charAt(0); // First Digit
        var secondDigit = wSpeedRound.charAt(1); // Second Diget
        var thirdDigit = wSpeedRound.charAt(2); // Third Digit if needed
        
// Now you can use firstDigitNumber and secondDigitNumber as needed
Console.log(firstDigit); // Outputs first digit
Console.log(secondDigit); // Outputs second digit     
if (firstDigit == 2) {
  ControlCommand("Numbers", "Track_20"); //Say "20"
  } else if (firstDigit == 3) {
  ControlCommand("Numbers", "Track_21"); //Say "30"
} else if (firstDigit == 4) {
  ControlCommand("Numbers", "Track_22"); //Say "40"
} else if (firstDigit == 5) {
  ControlCommand("Numbers", "Track_23"); //Say "50"
} else if (firstDigit == 6) {
  ControlCommand("Numbers", "Track_24"); //Say "60"
} else if (firstDigit == 7) {
  ControlCommand("Numbers", "Track_25"); //Say "70"
} else if (firstDigit == 8) {
  ControlCommand("Numbers", "Track_26"); //Say "80"
} else if (firstDigit == 9) {
  ControlCommand("Numbers", "Track_27"); //Say "90"
} 
  
sleep (1200);

//Say Second Digit of Windspeed
//------------------------------
if (secondDigit == 0) {
  ControlCommand("Phrases", "Track_14"); //Say "Miles Per Hour"
  sleep(1500);
  PWM.set(D0, 0); //Stop Ear Motors
  PWM.set(D9, 0); //Stop Crown Motor
  setVar( "$WSpeed", 0 ); //Sets Varaible so next Script will run
  ControlCommand("Personality Generator", "PauseOff");
  ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");
  halt();
} else if (secondDigit == 1) {
  ControlCommand("Numbers", "Track_1"); //Say "1"  
} else if (secondDigit == 2) {
  ControlCommand("Numbers", "Track_2"); //Say "2"
} else if (secondDigit == 3) {
  ControlCommand("Numbers", "Track_3"); //Say "3"
} else if (secondDigit == 4) {
  ControlCommand("Numbers", "Track_4"); //Say "4"
} else if (secondDigit == 5) {
  ControlCommand("Numbers", "Track_5"); //Say "5"
} else if (secondDigit == 6) {
  ControlCommand("Numbers", "Track_6"); //Say "6"
} else if (secondDigit == 7) {
  ControlCommand("Numbers", "Track_7"); //Say "7"
} else if (secondDigit == 8) {
  ControlCommand("Numbers", "Track_8"); //Say "8"
} else if (secondDigit == 9) {
  ControlCommand("Numbers", "Track_9"); //Say "9"
}
}

sleep(1500);

//Shutdown anamations
//---------------------------
ControlCommand("Phrases", "Track_14"); //Say "Miles Per Hour"
sleep(2500);
PWM.set(D0, 0); //Stop Ear Motors
PWM.set(D9, 0); //Stop Crown Motor
setVar( "$WSpeed", 0 ); //Sets Varaible so next Script will run

ControlCommand("Personality Generator", "PauseOff");
ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");

Humidity: 

ControlCommand("Personality Generator", "PauseOn");

//StartUp anamations
//-------------------
setVar( "$Humid", 1 ); //Sets Varaible so Script will run
PWM.set(D0, 70); //Start Ear Motors
PWM.set(D9, 20); //Start Crown Motor
ControlCommand("Head Section", "ScriptStart", "Radar 1/4 Sweep");
ControlCommand("Left Arm", "ScriptStart", "Left Claw Closed");
ControlCommand("Right Arm", "ScriptStart", "Right Claw Open");

//Get current weather conditions from openweathermap.org
var url1 = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&; Key goes here"
var content = Net.hTTPGet(url1);

//Read Humidity and set variables
//-------------------------------
pos = 0;
beginPos = pos;
pos = content.indexOf("humidity", beginPos);
endPos = pos;
otherend = content.indexOf("}",endPos);
var hum = content.substring((endPos+10),(endPos+12))
print("Humidity: " + hum);

var HumRound = Math.round(hum) //Round read humitity to get read of decimal point
print("Humidity Rounded: " + HumRound);
 
ControlCommand("Phrases", "Track_15"); //Say "The Humidity is at"
sleep(2000); 

//----------------------------------------------------------------
//this block extracts numbers out of tempRound Variable where the temp is stored
// and places each digit into it's own variable so orbot can speak each digit.
 //--------------------------------------------------------------
       
        // Convert the number to a string
        var numberString = HumRound.toString();
        
        // Now, we can access each digit using indexing
        var firstDigit = numberString.charAt(0); // First Digit
        var secondDigit = numberString.charAt(1); // Second Diget
        var thirdDigit = numberString.charAt(2); // Third Digit if needed
        
// Now you can use firstDigitNumber and secondDigitNumber as needed
Console.log(firstDigit); // Outputs first digit
Console.log(secondDigit); // Outputs second digit 
Console.log(thirdDigit); // Outputs second digit

//Say first digit of hudimity
//---------------------------
if (firstDigit == 2) {
  ControlCommand("Numbers", "Track_20"); //Say "20"
  sleep(1250);
} else if (firstDigit == 3 ) {
  ControlCommand("Numbers", "Track_21"); //Say "30"
  sleep(1300);
} else if (firstDigit == 4 ) {
  ControlCommand("Numbers", "Track_22"); //Say "40"
  sleep(1350);
} else if (firstDigit == 5 ) {
  ControlCommand("Numbers", "Track_23"); //Say "50"
  sleep(1300);
} else if (firstDigit == 6  ) {
  ControlCommand("Numbers", "Track_24"); //Say "60"
  sleep(1400);
} else if (firstDigit == 7  ) {
  ControlCommand("Numbers", "Track_25"); //Say "70"
  sleep(1400);
} else if (firstDigit == 8  ) {
  ControlCommand("Numbers", "Track_26"); //Say "80"
  sleep(1350);
} else if (firstDigit == 9 ) {
  ControlCommand("Numbers", "Track_27"); //Say "90"
  sleep(1400);
} 
  
//Say Second digit of hudimity
//-----------------------------
if (secondDigit == 1) {
  ControlCommand("Numbers", "Track_1"); //Say "1"
  sleep(1350);
}  else if (secondDigit == 2) {
  ControlCommand("Numbers", "Track_2"); //Say "2"
  sleep(1350);
} else if (secondDigit == 3) {
  ControlCommand("Numbers", "Track_3"); //Say "3"
  sleep(1400);
} else if (secondDigit == 4) {
  ControlCommand("Numbers", "Track_4"); //Say "4"
  sleep(1450);
} else if (secondDigit == 5) {
  ControlCommand("Numbers", "Track_5"); //Say "5"
  sleep(1450);
} else if (secondDigit == 6) {
  ControlCommand("Numbers", "Track_6"); //Say "6"
  sleep(1450);
} else if (secondDigit == 7) {
  ControlCommand("Numbers", "Track_7"); //Say "7"
  sleep(1400);
} else if (secondDigit == 8) {
  ControlCommand("Numbers", "Track_8"); //Say "8"
  sleep(1400);
} else if (secondDigit == 9) {
  ControlCommand("Numbers", "Track_9"); //Say "9"
  sleep(1450);
}

if (firstDigit == 1 && thirdDigit == 0 ) {
ControlCommand("Numbers", "Track_28"); //Say "100"
sleep(1400)
}

//Shutdown anamations
//------------------
ControlCommand("Phrases", "Track_16"); //Say "Percent"
sleep(1300);
//controlCommand("Phrases", "Track_12"); //Say "On this Alien Planet"
PWM.set(D0, 0); //Start Ear Motors
PWM.set(D9, 0); //Start Crown Motor
setVar( "$Humid", 0 ); //Sets Varaible so next Script will run

ControlCommand("Personality Generator", "PauseOff");
ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");
PRO
Canada
#6  

Nice work, Dave - glad the temp script is working the way you want. Below are two refactored scripts for Wind Speed and Humidity that follow the same robust pattern as your Temperature script:

  • Check internet first (Net.isInternetAvailable())
  • Use Net.hTTPGet(url, timeout) with try/catch to avoid hanging
  • Parse JSON with JSON.parse() instead of substring/indexOf
  • Play your "Not Active" voice lines and print a message on every error path
  • Always stop animations and set the global flag ($WSpeed or $Humid) back to "0" so the INT script continues

Important: Replace YOUR_API_KEY in each URL with your actual OpenWeather API key. Confirm the soundboard and track names match your project (I used the same track IDs you used earlier).

Wind Speed (drop into a Script skill as JavaScript)

// Wind Speed - robust version with verbal "Not Active" on failure
ControlCommand("Personality Generator","PauseOn");
setVar("$WSpeed","1"); // Flag for INT script

// Animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Script Manager","ScriptStart","Both Claws Closed");

// Replace with your API key
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid=YOUR_API_KEY";;
var timeoutMs = 7000;

function cleanupSuccess(){
  // Say "Miles Per Hour"
  ControlCommand("Phrases","Track_14"); // Say "Miles Per Hour"
  sleep(1500);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$WSpeed","0");
  return;
}

function errorSpeakAndExit(msg){
  if(msg) print(msg);
  // Play "Not Active"
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// 1) Internet?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 10){
  errorSpeakAndExit("Empty or invalid HTTP response.");
  return;
}

// 4) Parse JSON
var data;
try {
  data = JSON.parse(content);
} catch(e) {
  errorSpeakAndExit("JSON parse failed: " + e);
  return;
}

// 5) Extract wind speed (robust checks for common structures)
var ws = null;
if (data.current && data.current.wind_speed !== undefined) ws = data.current.wind_speed;
else if (data.current && data.current.wind && data.current.wind.speed !== undefined) ws = data.current.wind.speed;
else if (data.wind_speed !== undefined) ws = data.wind_speed;

if(ws === null){
  errorSpeakAndExit("Wind speed not found in response.");
  return;
}

print("Wind Speed (raw): " + ws);
var wSpeedRound = Math.round(ws);
print("Wind Speed Rounded: " + wSpeedRound);

// Speak intro
ControlCommand("Phrases","Track_13"); // "The Wind Velocity is at"
sleep(2100);

// Convert to string and speak digits using your existing tracks
var numberString = wSpeedRound.toString();
var firstDigit = numberString.charAt(0);
var secondDigit = (numberString.length > 1) ? numberString.charAt(1) : null;
var thirdDigit = (numberString.length > 2) ? numberString.charAt(2) : null;

// helper speak functions
function sayTens(d){
  if(d == "2") ControlCommand("Numbers","Track_20"); // 20
  else if(d == "3") ControlCommand("Numbers","Track_21");
  else if(d == "4") ControlCommand("Numbers","Track_22");
  else if(d == "5") ControlCommand("Numbers","Track_23");
  else if(d == "6") ControlCommand("Numbers","Track_24");
  else if(d == "7") ControlCommand("Numbers","Track_25");
  else if(d == "8") ControlCommand("Numbers","Track_26");
  else if(d == "9") ControlCommand("Numbers","Track_27");
  sleep(1200);
}
function sayOnes(d){
  if(d == "0"){
    ControlCommand("Phrases","Track_14"); // "Miles Per Hour"
    sleep(1500);
    PWM.set(d0,0);
    PWM.set(d9,0);
    setVar("$WSpeed","0");
    ControlCommand("Personality Generator","PauseOff");
    ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
    return;
  }
  if(d == "1") ControlCommand("Numbers","Track_1");
  else if(d == "2") ControlCommand("Numbers","Track_2");
  else if(d == "3") ControlCommand("Numbers","Track_3");
  else if(d == "4") ControlCommand("Numbers","Track_4");
  else if(d == "5") ControlCommand("Numbers","Track_5");
  else if(d == "6") ControlCommand("Numbers","Track_6");
  else if(d == "7") ControlCommand("Numbers","Track_7");
  else if(d == "8") ControlCommand("Numbers","Track_8");
  else if(d == "9") ControlCommand("Numbers","Track_9");
  sleep(1300);
}

// Speak digits (follows same pattern you used for Temperature)
if(numberString.length >= 2){
  sayTens(firstDigit);
  if(secondDigit !== null) sayOnes(secondDigit);
} else {
  sayOnes(firstDigit);
}

// Final cleanup
cleanupSuccess();

Humidity (drop into a Script skill as JavaScript)

// Humidity - robust version with verbal "Not Active" on failure
ControlCommand("Personality Generator","PauseOn");
setVar("$Humid","1"); // Flag for INT script

// Animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Left Arm","ScriptStart","Left Claw Closed");
ControlCommand("Right Arm","ScriptStart","Right Claw Open");

// Replace with your API key
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid=YOUR_API_KEY";;
var timeoutMs = 7000;

function cleanupSuccess(){
  ControlCommand("Phrases","Track_16"); // Say "Percent"
  sleep(1300);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$Humid","0");
  return;
}

function errorSpeakAndExit(msg){
  if(msg) print(msg);
  // Play "Not Active"
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// 1) Internet?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 10){
  errorSpeakAndExit("Empty or invalid HTTP response.");
  return;
}

// 4) Parse JSON
var data;
try {
  data = JSON.parse(content);
} catch(e) {
  errorSpeakAndExit("JSON parse failed: " + e);
  return;
}

// 5) Extract humidity
var hum = null;
if (data.current && data.current.humidity !== undefined) hum = data.current.humidity;
else if (data.humidity !== undefined) hum = data.humidity;

if(hum === null){
  errorSpeakAndExit("Humidity not found in response.");
  return;
}

print("Humidity (raw): " + hum);
var HumRound = Math.round(hum);
print("Humidity Rounded: " + HumRound);

// Speak intro
ControlCommand("Phrases","Track_15"); // "The Humidity is at"
sleep(2000);

// Convert to string and speak digits
var numberString = HumRound.toString();
var firstDigit = numberString.charAt(0);
var secondDigit = (numberString.length > 1) ? numberString.charAt(1) : null;
var thirdDigit = (numberString.length > 2) ? numberString.charAt(2) : null;

// helper speak functions
function sayTens(d){
  if(d == "2") ControlCommand("Numbers","Track_20");
  else if(d == "3") ControlCommand("Numbers","Track_21");
  else if(d == "4") ControlCommand("Numbers","Track_22");
  else if(d == "5") ControlCommand("Numbers","Track_23");
  else if(d == "6") ControlCommand("Numbers","Track_24");
  else if(d == "7") ControlCommand("Numbers","Track_25");
  else if(d == "8") ControlCommand("Numbers","Track_26");
  else if(d == "9") ControlCommand("Numbers","Track_27");
  sleep(1350);
}
function sayOnes(d){
  if(d == "1") ControlCommand("Numbers","Track_1");
  else if(d == "2") ControlCommand("Numbers","Track_2");
  else if(d == "3") ControlCommand("Numbers","Track_3");
  else if(d == "4") ControlCommand("Numbers","Track_4");
  else if(d == "5") ControlCommand("Numbers","Track_5");
  else if(d == "6") ControlCommand("Numbers","Track_6");
  else if(d == "7") ControlCommand("Numbers","Track_7");
  else if(d == "8") ControlCommand("Numbers","Track_8");
  else if(d == "9") ControlCommand("Numbers","Track_9");
  sleep(1400);
}

// Special case: 100%
if(firstDigit == "1" && secondDigit == "0" && thirdDigit == "0"){
  ControlCommand("Numbers","Track_28"); // "100"
  sleep(1400);
  cleanupSuccess();
  return;
}

// Speak digits (same pattern used for Temperature)
if(numberString.length >= 2){
  sayTens(firstDigit);
  if(secondDigit !== null) sayOnes(secondDigit);
} else {
  sayOnes(firstDigit);
}

// Final cleanup
cleanupSuccess();

Notes & tips

  • Replace YOUR_API_KEY in both scripts.
  • Confirm the soundboard names/track IDs exactly match those in your project; change strings if needed.
  • If you want the robot to say a success phrase (e.g., "Weather ready") at the end, tell me which soundboard and track and I’ll add it to cleanupSuccess().
  • If you want better wording for numbers below 20 (e.g., "thirteen" instead of "one three") I can update the digit-speaking logic to handle 10-19 and negative numbers and three-digit cases (humidity already has a 100 special case).

Would you like me to:

  1. Implement natural-language number speaking for 0-19 and negatives, or
  2. Keep the existing digits-as-tracks pattern you already use?

If A, tell me which soundboard/tracks you have for teen numbers (10-19) or I can create a sequence from existing tracks if available.


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.
#7   — Edited

@Athena,

I'm currently trying the Wind Speed script you rewrote for me and having problems. It's reporting the proper info sent back from the service but not saying the proper numbers. For example if the wind speed it actually 13 the script is reporting 3. It's probably because the soundboard names and tracks don't fit the format you wrote.

Basically in my soundboard I have sound files of the robot saying the numbers 0 through 19, then the whole numbers of 20 through 90 (20,30,40,50 and so on).. To get the robot to say numbers like 21 or 23 I need to have the script replete one of the single numbers1 through 9 afterward the whole number when needed.  For example 20 (then) 1 or 40 (then) 3.

I did some editing and got the script to say the proper wind speed that is reported back. However I'm not sure it's written in the beat and most efficient way. Here's my working script. Can it be improved on? :

// Wind Speed - robust version with verbal "Not Active" on failure
ControlCommand("Personality Generator","PauseOn");
setVar("$WSpeed","1"); // Flag for INT script

// Animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Script Manager","ScriptStart","Both Claws Closed");

// Replace with your API key
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid= KEY"
var timeoutMs =4000;

function cleanupSuccess(){
  // Say "Miles Per Hour"
  ControlCommand("Phrases","Track_14"); // Say "Miles Per Hour"
  sleep(1500);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$WSpeed","0");
  return;
}

function errorSpeakAndExit(msg){
  if(msg) print(msg);
  // Play "Not Active"
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// 1) Internet?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 10){
  errorSpeakAndExit("Empty or invalid HTTP response.");
  return;
}

// 4) Parse JSON
var data;
try {
  data = JSON.parse(content);
} catch(e) {
  errorSpeakAndExit("JSON parse failed: " + e);
  return;
}

// 5) Extract wind speed (robust checks for common structures)
var ws = null;
if (data.current && data.current.wind_speed !== undefined) ws = data.current.wind_speed;
else if (data.current && data.current.wind && data.current.wind.speed !== undefined) ws = data.current.wind.speed;
else if (data.wind_speed !== undefined) ws = data.wind_speed;

if(ws === null){
  errorSpeakAndExit("Wind speed not found in response.");
  return;
}

print("Wind Speed (raw): " + ws);
var wSpeedRound = Math.round(ws);
print("Wind Speed Rounded: " + wSpeedRound);

// Speak intro
ControlCommand("Phrases","Track_13"); // "The Wind Velocity is at"
sleep(2100);

//Say Windspeed if 19 MPH or below
//--------------------------------
if (wSpeedRound <= 19) {
  if (wSpeedRound == 0) {
    ControlCommand("Numbers", "Track_0"); //Say "0"
}    else if (wSpeedRound == 1) {
    ControlCommand("Numbers", "Track_1"); //Say "1"
}    else if (wSpeedRound == 2) {
    ControlCommand("Numbers", "Track_2"); //Say "2"
}   else if (wSpeedRound == 3) {
    ControlCommand("Numbers", "Track_3"); //Say "3"
}   else if (wSpeedRound == 4) {
    ControlCommand("Numbers", "Track_4"); //Say "4"
}   else if (wSpeedRound == 5) {
    ControlCommand("Numbers", "Track_5"); //Say "5"
}   else if (wSpeedRound == 6) {
    ControlCommand("Numbers", "Track_6"); //Say "6"
}   else if (wSpeedRound == 7) {
    ControlCommand("Numbers", "Track_7"); //Say "7"
}   else if (wSpeedRound == 8) {
    ControlCommand("Numbers", "Track_8"); //Say "8"
}   else if (wSpeedRound == 9) {
    ControlCommand("Numbers", "Track_9"); //Say "9"
}    else if (wSpeedRound == 10) {
    ControlCommand("Numbers", "Track_10"); //Say "10"
}    else if (wSpeedRound == 11) {
    ControlCommand("Numbers", "Track_11"); //Say "11"
}   else if (wSpeedRound == 12) {
    ControlCommand("Numbers", "Track_12"); //Say "12"
}   else if (wSpeedRound == 13) {
    ControlCommand("Numbers", "Track_13"); //Say "13"
}   else if (wSpeedRound == 14) {
    ControlCommand("Numbers", "Track_14"); //Say "14"
}   else if (wSpeedRound == 15) {
    ControlCommand("Numbers", "Track_15"); //Say "15"
}   else if (wSpeedRound == 16) {
    ControlCommand("Numbers", "Track_16"); //Say "16"
}   else if (wSpeedRound == 17) {
    ControlCommand("Numbers", "Track_17"); //Say "17"
}   else if (wSpeedRound == 18) {
    ControlCommand("Numbers", "Track_18"); //Say "18"
}   else if (wSpeedRound == 19) {
    ControlCommand("Numbers", "Track_19"); //Say "19"
} 
}

//Say windspeed if 20 MPH or above
//--------------------------------
if  (wSpeedRound >= 20) {
 //****************
 //this block extracts numbers out of tempRound Variable where the temp is stored
 // and places each digit into it's own variable so orbot can speak each digit.
 //****************
        // Now, we can access each digit using indexing
        var firstDigit = wSpeedRound.charAt(0); // First Digit
        var secondDigit = wSpeedRound.charAt(1); // Second Diget
        var thirdDigit = wSpeedRound.charAt(2); // Third Digit if needed
        
// Now you can use firstDigitNumber and secondDigitNumber as needed
Console.log(firstDigit); // Outputs first digit
Console.log(secondDigit); // Outputs second digit     
if (firstDigit == 2) {
  ControlCommand("Numbers", "Track_20"); //Say "20"
  } else if (firstDigit == 3) {
  ControlCommand("Numbers", "Track_21"); //Say "30"
} else if (firstDigit == 4) {
  ControlCommand("Numbers", "Track_22"); //Say "40"
} else if (firstDigit == 5) {
  ControlCommand("Numbers", "Track_23"); //Say "50"
} else if (firstDigit == 6) {
  ControlCommand("Numbers", "Track_24"); //Say "60"
} else if (firstDigit == 7) {
  ControlCommand("Numbers", "Track_25"); //Say "70"
} else if (firstDigit == 8) {
  ControlCommand("Numbers", "Track_26"); //Say "80"
} else if (firstDigit == 9) {
  ControlCommand("Numbers", "Track_27"); //Say "90"
} 
  
sleep (1200);

//Say Second Digit of Windspeed
//------------------------------
if (secondDigit == 0) {
  ControlCommand("Phrases", "Track_14"); //Say "Miles Per Hour"
  sleep(1500);
  PWM.set(D0, 0); //Stop Ear Motors
  PWM.set(D9, 0); //Stop Crown Motor
  setVar( "$WSpeed", 0 ); //Sets Varaible so next Script will run
  ControlCommand("Personality Generator", "PauseOff");
  ControlCommand("Script Manager", "ScriptStart", "Both Claws Rest Closed");
  halt();
  
} else if (secondDigit == 1) {
  ControlCommand("Numbers", "Track_1"); //Say "1"  
} else if (secondDigit == 2) {
  ControlCommand("Numbers", "Track_2"); //Say "2"
} else if (secondDigit == 3) {
  ControlCommand("Numbers", "Track_3"); //Say "3"
} else if (secondDigit == 4) {
  ControlCommand("Numbers", "Track_4"); //Say "4"
} else if (secondDigit == 5) {
  ControlCommand("Numbers", "Track_5"); //Say "5"
} else if (secondDigit == 6) {
  ControlCommand("Numbers", "Track_6"); //Say "6"
} else if (secondDigit == 7) {
  ControlCommand("Numbers", "Track_7"); //Say "7"
} else if (secondDigit == 8) {
  ControlCommand("Numbers", "Track_8"); //Say "8"
} else if (secondDigit == 9) {
  ControlCommand("Numbers", "Track_9"); //Say "9"
}
}

sleep(1500);

// Final cleanup
cleanupSuccess();

Thanks

PRO
Canada
#8  

Great job debugging this, Dave - thanks for the clear explanation of your soundboard layout. Your solution was on the right track; the script can be cleaned up and made more robust and readable by:

  • Parsing the JSON response (instead of string-indexing) so it won’t break if the response changes order.
  • Using a single reusable speakNumber(n) helper that understands you have tracks 0-19 and tens (20,30,...90) - it will play a tens file and then (if needed) a ones file for values like 21, 23, etc.
  • Fixing the content-length check bug (you had an assignment by accident).
  • Keeping the same error verbal cue ("Not" then "Active") and consistent cleanup paths.

Below is a cleaned-up Wind Speed script that you can drop into ARC. Replace YOUR_API_KEY with your key and confirm the skill & track names match your project (I used the same names you provided).

// Wind Speed - improved, robust, and uses 0-19 + tens sound files
ControlCommand("Personality Generator","PauseOn");
setVar("$WSpeed","1"); // Flag for INT script

// Animations
PWM.set(d0,70);
PWM.set(d9,20);
ControlCommand("Head Section","ScriptStart","Radar 1/4 Sweep");
ControlCommand("Script Manager","ScriptStart","Both Claws Closed");

// OpenWeather OneCall (replace YOUR_API_KEY)
var url = "https://api.openweathermap.org/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid=YOUR_API_KEY";;
var timeoutMs = 7000;

// Cleanup on success
function cleanupSuccess(){
  ControlCommand("Phrases","Track_14"); // "Miles Per Hour"
  sleep(1500);
  PWM.set(d0,0);
  PWM.set(d9,0);
  ControlCommand("Personality Generator","PauseOff");
  ControlCommand("Script Manager","ScriptStart","Both Claws Rest Closed");
  setVar("$WSpeed","0");
  return;
}

// Error path: speak "Not" then "Active" then cleanup
function errorSpeakAndExit(msg){
  if(msg) print(msg);
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// Speak a number using your sound files:
// - 0..19 => "Numbers" Track_0..Track_19
// - >=20 => play tens (20,30,...90) track, then ones (1..9) if needed
function speakNumber(n){
  n = Math.round(n);
  if(n < 0) {
    // If you have a negative sound, play it. Otherwise just speak the absolute value.
    // ControlCommand("Numbers","Track_minus");
    n = Math.abs(n);
  }
  if(n <= 19){
    ControlCommand("Numbers","Track_" + n); // Tracks 0..19
    sleep(900);
    return;
  }
  // For 20..99
  var tens = Math.floor(n/10) * 10; // 20,30,...
  ControlCommand("Numbers","Track_" + tens); // e.g. Track_20
  sleep(800);
  var ones = n % 10;
  if(ones > 0){
    ControlCommand("Numbers","Track_" + ones); // Track_1..Track_9
    sleep(900);
  }
}

// 1) Internet?
if(!Net.isInternetAvailable()){
  errorSpeakAndExit("No internet available.");
  return;
}

// 2) HTTP GET with timeout
var content = "";
try {
  content = Net.hTTPGet(url, timeoutMs);
} catch(e) {
  errorSpeakAndExit("HTTP request failed: " + e);
  return;
}

// 3) Validate content
if(!content || content.length < 20){
  errorSpeakAndExit("Empty or too-short response.");
  return;
}

// 4) Parse JSON robustly and extract wind speed
var data;
try {
  data = JSON.parse(content);
} catch(e){
  // fallback: try to extract numeric "wind_speed" from text if JSON.parse failed
  var m = content.match(/"wind_speed"\s*:\s*([0-9.]+)/);
  if(m && m[1]) {
    data = { _fallbackWind: parseFloat(m[1]) };
  } else {
    errorSpeakAndExit("JSON parse failed: " + e);
    return;
  }
}

var ws = null;
if(data && data.current && data.current.wind_speed !== undefined){
  ws = data.current.wind_speed;
} else if(data && data.wind_speed !== undefined){
  ws = data.wind_speed;
} else if(data && data._fallbackWind !== undefined){
  ws = data._fallbackWind;
} else {
  // last-resort regex search
  var m2 = content.match(/"wind_speed"\s*:\s*([0-9.]+)/);
  if(m2 && m2[1]) ws = parseFloat(m2[1]);
}

if(ws === null || isNaN(ws)){
  errorSpeakAndExit("No wind speed found in response.");
  return;
}

// 5) Speak the wind speed using your soundboard structure
var wSpeedRound = Math.round(ws);
print("Wind Speed (rounded): " + wSpeedRound);
ControlCommand("Phrases","Track_13"); // "The Wind Velocity is at"
sleep(1800);

speakNumber(wSpeedRound);

// Final cleanup
cleanupSuccess();

Notes and tips

  • I set timeouts and robust parsing. This prevents your script from stalling.
  • The function speakNumber() uses the exact layout you described (tracks 0-19, and tens 20-90). If your Numbers skill uses a different prefix (for example, "Num" instead of "Numbers" or different Track names), change the skill name or track prefix accordingly.
  • If you don’t have a Track_0 in the Numbers skill and instead use a phrase skill for "zero," change the speakNumber() path for n == 0 to call that phrase.
  • I removed halt() and used return consistently to end the script cleanly.

Would you like me to:

  • Update your Humidity script to use the same speakNumber() helper and JSON parsing (I can paste the refactor), or
  • Provide a single shared JS function (as a plugin-style snippet) you can reuse across all three scripts (Temp, Humidity, Windspeed)?

Which do you prefer?


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.