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

Elevate your robot's capabilities to the next level with Synthiam ARC Pro, unlocking a world of possibilities in robot programming.

#9  

OK, Thanks! Your new wind speed script seems to be working nicely in my robot.

To answer your question, Yes, please redo my Humidly script to use the same speakNumber() helper and JSON parsing. That was going to be my next ask. I haven't tried the last Humidly script you did for me but I'm sure it will need the same treatment. @Athena, Can you please proceed with the new Humidly script you offered?

PRO
Canada
#10  

Perfect - I’ll refactor the Humidity script to use the same robust pattern and the speakNumber() helper you’re using for Wind Speed. This script:

  • checks internet with Net.isInternetAvailable()
  • does a timed Net.hTTPGet(url, timeout)
  • JSON.parse()s the response (with a fallback regex)
  • uses speakNumber() for 0-19 + tens(20,30,...,90) playback (same soundboard layout you described)
  • plays your "Not / Active" voice cue on errors
  • always stops animations and sets setVar("$Humid","0") on any exit so your INT script never gets stuck

Replace YOUR_API_KEY in the url with your actual OpenWeather API key. Confirm your soundboard/skill names are exactly as used here ("Soundboard 2", "Soundboard v4", "Numbers", "Phrases") - if they differ, change the strings.

Script - drop into a Script skill (JavaScript):

// Humidity - robust version with speakNumber() helper and verbal "Not Active" on failure

ControlCommand("Personality Generator","PauseOn");
setVar("$Humid","1"); // Flag for INT script

// Start 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; // adjust if needed

function cleanupSuccess(){
  // Say "Percent"
  ControlCommand("Phrases","Track_16");
  sleep(1300);

  // Stop animations and restore
  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" then "Active"
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// speakNumber(n):
// - plays Numbers.Track_0 ... Track_19 for values 0..19
// - for >=20: plays tens track (20,30,...90) then plays ones track if needed
function speakNumber(n){
  n = Math.round(n);
  if(n < 0) n = 0;

  // 0..19 available directly
  if(n <= 19){
    // numbers 0..19 must be in "Numbers" skill as Track_0 ... Track_19
    ControlCommand("Numbers","Track_" + n);
    sleep(900);
    return;
  }

  // 20..99: play tens, then ones (if ones > 0)
  var tens = Math.floor(n / 10) * 10;   // 20,30,...90
  var ones = n % 10;

  // Map tens to the same Track_x naming used previously (20->Track_20 etc)
  ControlCommand("Numbers","Track_" + tens);
  sleep(1000);

  if(ones > 0){
    ControlCommand("Numbers","Track_" + ones); // Track_1 .. Track_9
    sleep(900);
  }
}

// 1) Internet check
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 result
if(!content || content.length < 20){
  errorSpeakAndExit("Empty or too-short response.");
  return;
}

// 4) Parse JSON (with fallback)
var data;
try {
  data = JSON.parse(content);
} catch(e){
  // fallback regex for humidity
  var m = content.match(/"humidity"\s*:\s*([0-9]+)/);
  if(m && m[1]){
    data = { _fallbackHumidity: parseInt(m[1],10) };
  } else {
    errorSpeakAndExit("JSON parse failed: " + e);
    return;
  }
}

// 5) Extract humidity
var humidity = null;
if(data && data.current && data.current.humidity !== undefined){
  humidity = data.current.humidity;
} else if(data && data.humidity !== undefined){
  humidity = data.humidity;
} else if(data && data._fallbackHumidity !== undefined){
  humidity = data._fallbackHumidity;
} else {
  var m2 = content.match(/"humidity"\s*:\s*([0-9]+)/);
  if(m2 && m2[1]) humidity = parseInt(m2[1],10);
}

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

// 6) Announce humidity
var humRound = Math.round(humidity);
print("Humidity (rounded): " + humRound);

ControlCommand("Phrases","Track_15"); // "The Humidity is at"
sleep(1800);

speakNumber(humRound);

// Final cleanup
cleanupSuccess();

Notes and tips

  • Replace YOUR_API_KEY with your actual API key.
  • This assumes your "Numbers" skill has Track_0 ... Track_19 and Track_20/30/.../90 exactly named Track_20 etc. If your Numbers skill uses a different prefix or numbering scheme, tell me the exact names and I’ll adjust the script.
  • If you prefer a combined phrase for "Percent" instead of Phrases.Track_16, change that call.
  • If you want teen numbers (10-19) spoken as single tracks (you already do) or to use a special pronunciation rule, the script already plays Track_10 ... Track_19 directly.

Want me to:

  • drop in a shared helper snippet (speakNumber + network+fetch wrapper) you can reuse in all three scripts, or
  • convert this into a single script that announces Temp, Humidity, and Wind in sequence?

Which would 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.
#11  

I found a problem with both the Wind speed and the Humidity script you helped me with.

Everything runs well until it gets to the speakNumber() function block on each. If the number it needs to call from the Numbers Soundboard is above 29 the script will stall and throw an error that the track wanted does not exist. Once I clear the error window the "ones" number will play abd the script will finish. For example, if the humidity is "87 percent" the script will stop and not play the track that says "80" and throw an error window saying the track "80" can't be found. I'll clear the window, the script will start up on it's own and play the sound file that says "7".

I think it's because my sound files that say the numbers, 30,40,50,60,70,80 and 90 are not in the numbered slots that correspond with the number sound. 30 is not in the 30 slot, 40 is not in the 40 slot and so on. Here's the if/else if section from my old working script that show the proper Numbers Soundboard slots where these sound files are found:

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" }

Is it possible for you to fix the humidity script you just wrote to reflect these 10's numbers file locations?

PRO
Canada
#12  

Perfect - I updated the Humidity script so the tens (20,30,40...90) use the exact Numbers soundboard slots you showed (20Track_20, 30Track_21, , 90Track_27). The speakNumber() helper now uses a lookup table for tens so it won't try to play Track_30/40/etc. and throw that error.

Drop this into a Script skill (Javascript). Replace YOUR_API_KEY with your key and confirm the soundboard/skill names exactly match your project. I kept the same error verbal cues (Soundboard 2 Track_26 then Soundboard v4 Track_20) and the cleanup behavior that sets $Humid back to "0".

// Humidity - robust version with corrected tens mapping for your Numbers soundboard
ControlCommand("Personality Generator","PauseOn");
setVar("$Humid","1"); // Flag for INT script

// Start 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; // adjust if needed

function cleanupSuccess(){
  // Say "Percent"
  ControlCommand("Phrases","Track_16");
  sleep(1300);
  // Stop animations and restore
  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" then "Active"
  ControlCommand("Soundboard 2","Track_26"); // "Not"
  sleep(600);
  ControlCommand("Soundboard v4","Track_20"); // "Active"
  sleep(1000);
  cleanupSuccess();
  return;
}

// speakNumber(n):
// - plays Numbers.Track_0 .. Track_19 for values 0-19
// - for >=20 plays tens track from the mapping (20->Track_20,30->Track_21,...90->Track_27)
//   then plays ones (1-9) Track_1..Track_9 if needed
// - handles 100 as a special case using Track_28
function speakNumber(n){
  n = Math.round(n);
  if(n < 0) n = Math.abs(n); // just in case
  // Special-case 100 if you have Track_28
  if(n === 100){
    ControlCommand("Numbers","Track_28"); // "100"
    sleep(1400);
    return;
  }
  // 0..19 direct mapping (Track_0 .. Track_19)
  if(n >= 0 && n <= 19){
    ControlCommand("Numbers","Track_" + n);
    // teens and single digits timing vary; 10-19 often longer
    if(n >= 10) sleep(1400); else sleep(900);
    return;
  }
  // >=20: use tens mapping then ones
  var tensDigit = Math.floor(n / 10); // 2..9
  var ones = n % 10;

  // Map tensDigit -> track name (based on your soundboard layout)
  var tensTrackMap = {
    2: "Track_20", // 20
    3: "Track_21", // 30
    4: "Track_22", // 40
    5: "Track_23", // 50
    6: "Track_24", // 60
    7: "Track_25", // 70
    8: "Track_26", // 80
    9: "Track_27"  // 90
  };

  var tensTrack = tensTrackMap[tensDigit];
  if(tensTrack){
    ControlCommand("Numbers", tensTrack);
    sleep(1200);
  } else {
    // Safety fallback: try tens as Track_20 if mapping missing
    ControlCommand("Numbers","Track_20");
    sleep(1200);
  }

  if(ones > 0){
    ControlCommand("Numbers","Track_" + ones); // Track_1 .. Track_9
    sleep(900);
  } else {
    // If ones==0, speak "Percent" later in cleanupSuccess
  }
}

// 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 result
if(!content || content.length < 20){
  errorSpeakAndExit("Empty or too-short response.");
  return;
}

// 4) Parse JSON (with fallback)
var data;
try {
  data = JSON.parse(content);
} catch(e) {
  // fallback regex for humidity
  var m = content.match(/"humidity"\s*:\s*([0-9]+)/);
  if(m && m[1]){
    data = { _fallbackHumidity: parseInt(m[1], 10) };
  } else {
    errorSpeakAndExit("JSON parse failed:" + e);
    return;
  }
}

// 5) Extract humidity
var humidity = null;
if(data && data.current && data.current.humidity !== undefined){
  humidity = data.current.humidity;
} else if(data && data.humidity !== undefined){
  humidity = data.humidity;
} else if(data && data._fallbackHumidity !== undefined){
  humidity = data._fallbackHumidity;
} else {
  var m2 = content.match(/"humidity"\s*:\s*([0-9]+)/);
  if(m2 && m2[1]) humidity = parseInt(m2[1], 10);
}

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

// 6) Announce humidity
var humRound = Math.round(humidity);
print("Humidity(rounded):" + humRound);
ControlCommand("Phrases","Track_15"); // "The Humidity is at"
sleep(1800);
speakNumber(humRound);

// Final cleanup
cleanupSuccess();

Testing tips

  • Start with a known humidity (use the API URL in a browser first) to verify JSON shape.
  • If any skill or track name differs from "Numbers", "Phrases", "Soundboard 2", or "Soundboard v4", update those strings exactly.
  • If your Numbers skill uses a different indexing (e.g., no Track_0 or different track numbers), tell me the exact mapping and I’ll adapt speakNumber().

Would you like me to apply this same tens-track mapping to the Wind Speed script too (so both scripts match exactly)? I can paste the updated Wind script if you want.


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

The last Humidity script you helped me with seems to work correctly and as needed.

@Athena , Could you please update and apply this same tens-track mapping to the last Wind Speed script too (so both scripts match exactly)?

PRO
Canada
#14  

Great - thanks for the details, Dave. I updated the Wind Speed script to use the same tens-track mapping as the Humidity script so it will call the exact Numbers soundboard slots you showed (20 Track_20, 30 Track_21, 90 Track_27). The script also keeps the robust JSON parsing, timeout, internet check, and error handling (plays "Not" then "Active" and always clears the $WSpeed flag so your INT script never stalls).

Drop this into a Script skill (JavaScript). Replace YOUR_API_KEY in the URL with your key and confirm the skill & track names match your project ("Soundboard 2", "Soundboard v4", "Numbers", "Phrases"). If any names differ, tell me the exact names and I’ll update the calls.

// Wind Speed - robust version with corrected tens mapping for your Numbers soundboard
ControlCommand("Personality Generator","PauseOn");
setVar("$WSpeed","1"); // Flag for INT script

// Start 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 YOUR_API_KEY with your OpenWeather 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;
}

// speakNumber(n):
// - plays Numbers.Track_0..Track_19 for values 0-19
// - for >=20: plays tens track from mapping (20->Track_20, 30->Track_21, ... 90->Track_27)
//   then plays ones (Track_1..Track_9) if needed
// - caps/handles >99 by using last two digits
function speakNumber(n){
  n = Math.round(n);
  if(n < 0) n = 0;

  // special: if exactly 100 and you have Track_28, you could play it here
  if(n === 100){
    // if you have Track_28 for "100":
    // ControlCommand("Numbers","Track_28");
    // sleep(1400);
    // return;
    // If not, fall through to speak "one" "hundred" or other logic
    n = 100;
  }

  if(n <= 19){
    ControlCommand("Numbers","Track_" + n);
    sleep(1100);
    return;
  }

  // For >=20, we only need the last two digits for playback (e.g., 123 -> treat as 23)
  if(n > 99) n = n % 100;

  var tensDigit = Math.floor(n / 10); // 2..9 for 20..90
  var ones = n % 10;

  // Map tens digit to your actual Numbers soundboard slots (per your mapping)
  var tensTrackMap = {
    2: "Track_20", // 20
    3: "Track_21", // 30
    4: "Track_22", // 40
    5: "Track_23", // 50
    6: "Track_24", // 60
    7: "Track_25", // 70
    8: "Track_26", // 80
    9: "Track_27"  // 90
  };

  var tensTrack = tensTrackMap[tensDigit];
  if(tensTrack){
    ControlCommand("Numbers", tensTrack);
    sleep(1200);
  } else {
    // Fallback: try Track_20 (20) to avoid missing-track errors
    ControlCommand("Numbers","Track_20");
    sleep(1200);
  }

  if(ones > 0){
    ControlCommand("Numbers","Track_" + ones); // Track_1 .. Track_9
    sleep(900);
  }
}

// 1) Internet available?
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 (with fallback)
var data = null;
var ws = null;
try {
  data = JSON.parse(content);
} catch(e) {
  // fallback: try to extract "wind_speed" or "speed" from raw text
  var m = content.match(/"wind_speed"\s*:\s*([0-9.]+)/) || content.match(/"speed"\s*:\s*([0-9.]+)/);
  if(m && m[1]) {
    ws = parseFloat(m[1]);
  } else {
    errorSpeakAndExit("JSON parse failed: " + e);
    return;
  }
}

// 5) Extract wind speed from parsed JSON if not set by fallback
if(ws === null){
  if(data && data.current && data.current.wind_speed !== undefined){
    ws = data.current.wind_speed;
  } else if(data && data.current && data.current.wind && 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.wind && data.wind.speed !== undefined){
    ws = data.wind.speed;
  } else {
    // last-resort regex
    var m2 = content.match(/"wind_speed"\s*:\s*([0-9.]+)/) || content.match(/"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;
}

// 6) Announce wind speed
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

  • Make sure your Numbers soundboard has Track_0 up through Track_19 and Tracks 20,21,...27 as you described. If any track names differ, tell me the exact slot names and I’ll adjust the mapping.
  • Replace YOUR_API_KEY with your OpenWeather API key. Test the URL in a browser first to confirm the JSON shape for your account/location.
  • Timeout is 7000 ms; increase if your network is slow.

Would you like me to:

    1. Update the Temperature script to use the exact same tens mapping (if needed), or
    1. Create a shared snippet (speakNumber + network wrapper) you can paste into each script so future edits are easier?

Which would 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.
#15  

Athena , Yes, this last windspeed script runs as expected. However I won't truly know until the wind gets above 30 mph and I make the call.

Next, the Open Weather Map API sends the temperature and windspeed in a fraction. For example 85.71 or 7.91. This is why I designed this script to round the returned value to the nearest whole number. These scripts as rewritten by you only show (print) the rounded number in the debug window of the script. However along with the rounded number I still want to see the number before it's rounded with their fractional numbers. What would the print(); command look like and where in these two scripts can I place it so the entire returned number with it's decimal will show in the debug window?

PRO
Canada
#16  

Perfect - easy tweak. Add a debug print right after the scripts extract the raw numeric value and before you round it. Use print() (not console.log()) and toFixed() if you want a fixed number of decimal places.

Below are the exact places and example lines to insert into each script.

Wind Speed

  • Where: right after you have extracted/validated ws and before you do: var wSpeedRound = Math.round(ws);
  • Example snippet to insert:
// show raw fractional wind speed (two decimals) and then rounded value
print("Wind speed raw: " + ws.toFixed(2) + " mph");
var wSpeedRound = Math.round(ws);
print("Wind speed rounded: " + wSpeedRound + " mph");

Humidity

  • Humidity is usually an integer (%) but if you still want to show the original value before rounding, insert right after you determine humidity and before: var humRound = Math.round(humidity);
  • Example snippet to insert:
// show raw humidity (two decimals if any) and then rounded value
print("Humidity raw: " + (typeof humidity === "number" ? humidity.toFixed(2) : humidity));
var humRound = Math.round(humidity);
print("Humidity rounded: " + humRound + "%");

Where exactly to put them in your current scripts

  • Wind script: Put the wind debug prints after the block that sets ws and the check that ensures ws is valid, for example right where you currently do: if (ws == null || isNaN(ws)) // Insert the wind debug prints here, then continue to Math.round and speakNumber().
  • Humidity script: Put the humidity debug prints after you set the humidity variable and confirm it's valid, just before rounding and announcing.

Notes and tips

  • toFixed(2) prints two decimals. Change the 2 to 1 or 3 if you want more or fewer decimal places.
  • If you want a single combined print instead of two separate ones, you can do: print("Wind speed: raw=" + ws.toFixed(2) + " mph, rounded=" + Math.round(ws) + " mph");
  • If you want these debug prints removed later, just delete or comment them out when you no longer need the log output.

Want me to paste the exact lines into the full wind and humidity scripts (with the correct insertion points) so you can copy/paste the complete updated scripts back into ARC?


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.