Storm’s A Comin’ 2.0

“Aw, there goes mah knee agin.
Storm’s a comin’, Muriel!”

Materials

I ran the following code to check that the MKR1010 could connect to the OpenWeatherMap.org API (Current Weather) and return the JSON via Serial. Note: I used my phone’s WiFi hotspot to avoid NYU’s authentication.

This was the Serial output:

Attempting to connect to SSID: Verizon-SM-G930V-1EF0
Connected to wifi
SSID: Verizon-SM-G930V-1EF0
IP Address: 192.168.43.60
signal strength (RSSI):-18 dBm

Starting connection to server...
connected to server
{"coord":{"lon":-73.99,"lat":40.73},"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"base":"stations","main":{"temp":290.83,"pressure":1022,"humidity":63,"temp_min":288.15,"temp_max":293.15},"visibility":16093,"wind":{"speed":1.5},"clouds":{"all":1},"dt":1555096861,"sys":{"type":1,"id":4610,"message":0.0088,"country":"US","sunrise":1555064518,"sunset":1555111870},"id":5128581,"name":"New York","cod":200}

I ran the JSON through a formatter to make it more readable:

{
   "coord":{
      "lon":-73.99,
      "lat":40.73
   },
   "weather":[
      {
         "id":800,
         "main":"Clear",
         "description":"clear sky",
         "icon":"01d"
      }
   ],
   "base":"stations",
   "main":{
      "temp":290.83,
      "pressure":1022,
      "humidity":63,
      "temp_min":288.15,
      "temp_max":293.15
   },
   "visibility":16093,
   "wind":{
      "speed":1.5
   },
   "clouds":{
      "all":1
   },
   "dt":1555096861,
   "sys":{
      "type":1,
      "id":4610,
      "message":0.0088,
      "country":"US",
      "sunrise":1555064518,
      "sunset":1555111870
   },
   "id":5128581,
   "name":"New York",
   "cod":200
}

Here is OpenWeatherMap’s explanation of the JSON parameters:

I want to be able to read the weather > main field in order to see if a storm is predicted. One option is to set a timer to take a reading of the Current Weather every 10 minutes to see if “Thunderstorm” is in that field.

Another option would be to use the 5-Day Forecast API, the only other API available through the free plan. I changed line 94 to red the following, replacing “/weather?q=” with “/forecast?q=” :

client.println("GET /data/2.5/forecast?q=" + location + "&APPID=" + apiKey); 

It returned an incomplete JSON. I’m not sure why… maybe because it’s only printing on one line and there is a character limit in Serial? I really only need the first day’s worth of data as shown below so I changed the GET line to:

client.println("GET /data/2.5/forecast?q=" + location + "&APPID=" + apiKey + "&cnt=1");

I added the “&cnt=1” so that it would only return the first day:

{  
   "cod":"200",
   "message":0.0096,
   "cnt":1,
   "list":[  
      {  
         "dt":1555124400,
         "main":{  
            "temp":287.11,
            "temp_min":287.11,
            "temp_max":287.337,
            "pressure":1019.88,
            "sea_level":1019.88,
            "grnd_level":1016.68,
            "humidity":90,
            "temp_kf":-0.23
         },
         "weather":[  
            {  
               "id":501,
               "main":"Rain",
               "description":"moderate rain",
               "icon":"10n"
            }
         ],
         "clouds":{  
            "all":92
         },
         "wind":{  
            "speed":6.46,
            "deg":198.501
         },
         "rain":{  
            "3h":4.62
         },
         "sys":{  
            "pod":"n"
         },
         "dt_txt":"2019-04-13 03:00:00"
      }
   ],
   "city":{  
      "id":5128581,
      "name":"New York",
      "coord":{  
         "lat":40.7306,
         "lon":-73.9867
      },
      "country":"US",
      "population":8175133
   }
}

Here are the parameters as explained by OpenWeatherMap:

I would need to isolate list > list.weather > list.weather.main in this case.

Additionally, I would need to decide when to fire the vibration motor. In the API documentation, it says it takes a reading every 3 hours so perhaps if I left the program running, I could set a rule that it makes a new call every 3 hours and if it returns a “Thunderstorm” in the list.weather.main parameter, it vibrates for 5 seconds.

In order to parse the JSON, I used the assistant provided by the makers of the ArduinoJSON library. Here’s what it looked like:

Whew! Luckily, I don’t need all this data. I only need the data in line 27:

const char* list_0_weather_0_main = list_0_weather_0["main"];

Incorporating that into the loop() function in the sketch looks like this:

I prototyped the circuit on a breadboard:

And I tested it first with the following blink program:

void setup() {
  pinMode(3, OUTPUT);
}

void loop() {
  digitalWrite(3, HIGH);
  delay(1000);
  digitalWrite(3, LOW);
  delay(1000);
}

April 15, 2019

Leave a Reply