[Wearables] Assignment #4 – Connectivity


Storm’s A Comin’ 2.0

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

Materials

  • PN2222A Transistor – NPN bipolar junction transistor, used for general purpose low-power amplifying or switching applications (EBC pinout)
  • 1N4001 Diode – blocking voltage 50 V
  • Code 104 0.1µF Ceramic Capacitor
  • 220 Ohm Resistor (red red brown gold)
  • LiPo 3.7 V battery
  • MKR1010
  • Small Vibration Motor

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:

  • coord
    • coord.lon City geo location, longitude
    • coord.lat City geo location, latitude
  • weather (more info Weather condition codes)
    • weather.id Weather condition id
    • weather.main Group of weather parameters (Rain, Snow, Extreme etc.)
    • weather.description Weather condition within the group
    • weather.icon Weather icon id
  • base Internal parameter
  • main
    • main.temp Temperature. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
    • main.pressure Atmospheric pressure (on the sea level, if there is no sea_level or grnd_level data), hPa
    • main.humidity Humidity, %
    • main.temp_min Minimum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
    • main.temp_max Maximum temperature at the moment. This is deviation from current temp that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
    • main.sea_level Atmospheric pressure on the sea level, hPa
    • main.grnd_level Atmospheric pressure on the ground level, hPa
  • wind
    • wind.speed Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour.
    • wind.deg Wind direction, degrees (meteorological)
  • clouds
    • clouds.all Cloudiness, %
  • rain
    • rain.1h Rain volume for the last 1 hour, mm
    • rain.3h Rain volume for the last 3 hours, mm
  • snow
    • snow.1h Snow volume for the last 1 hour, mm
    • snow.3h Snow volume for the last 3 hours, mm
  • dt Time of data calculation, unix, UTC
  • sys
    • sys.type Internal parameter
    • sys.id Internal parameter
    • sys.message Internal parameter
    • sys.country Country code (GB, JP etc.)
    • sys.sunrise Sunrise time, unix, UTC
    • sys.sunset Sunset time, unix, UTC
  • id City ID
  • name City name
  • cod Internal parameter

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:

  • code Internal parameter
  • message Internal parameter
  • city
    • city.id City ID
    • city.name City name
    • city.coord
      • city.coord.lat City geo location, latitude
      • city.coord.lon City geo location, longitude
    • city.country Country code (GB, JP etc.)
  • cnt Number of lines returned by this API call
  • list
    • list.dt Time of data forecasted, unix, UTC
    • list.main
      • list.main.temp Temperature. Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
      • list.main.temp_min Minimum temperature at the moment of calculation. This is deviation from ‘temp’ that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
      • list.main.temp_max Maximum temperature at the moment of calculation. This is deviation from ‘temp’ that is possible for large cities and megalopolises geographically expanded (use these parameter optionally). Unit Default: Kelvin, Metric: Celsius, Imperial: Fahrenheit.
      • list.main.pressure Atmospheric pressure on the sea level by default, hPa
      • list.main.sea_level Atmospheric pressure on the sea level, hPa
      • list.main.grnd_level Atmospheric pressure on the ground level, hPa
      • list.main.humidity Humidity, %
      • list.main.temp_kf Internal parameter
    • list.weather (more info Weather condition codes)
      • list.weather.id Weather condition id
      • list.weather.main Group of weather parameters (Rain, Snow, Extreme etc.)
      • list.weather.description Weather condition within the group
      • list.weather.icon Weather icon id
    • list.clouds
      • list.clouds.all Cloudiness, %
    • list.wind
      • list.wind.speed Wind speed. Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour.
      • list.wind.deg Wind direction, degrees (meteorological)
    • list.rain
      • list.rain.3h Rain volume for last 3 hours, mm
    • list.snow
      • list.snow.3h Snow volume for last 3 hours
    • list.dt_txt Data/time of calculation, UTC

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);
}