Asked

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

ARC Pro

Upgrade to ARC Pro

Experience the transformation – subscribe to Synthiam ARC Pro and watch your robot evolve into a marvel of innovation and intelligence.

#1  

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

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/data/3.0/onecall?lat=26.661630&lon=-81.970330&units=imperial&appid=ff6d89783614fda740ef15cf81252fba";
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.