Storm’s A Comin’ 2.0
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, longitudecoord.lat
City geo location, latitude
weather
(more info Weather condition codes)weather.id
Weather condition idweather.main
Group of weather parameters (Rain, Snow, Extreme etc.)weather.description
Weather condition within the groupweather.icon
Weather icon id
base
Internal parametermain
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), hPamain.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, hPamain.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, mmrain.3h
Rain volume for the last 3 hours, mm
snow
snow.1h
Snow volume for the last 1 hour, mmsnow.3h
Snow volume for the last 3 hours, mm
dt
Time of data calculation, unix, UTCsys
sys.type
Internal parametersys.id
Internal parametersys.message
Internal parametersys.country
Country code (GB, JP etc.)sys.sunrise
Sunrise time, unix, UTCsys.sunset
Sunset time, unix, UTC
id
City IDname
City namecod
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 parametermessage
Internal parametercity
city.id
City IDcity.name
City namecity.coord
city.coord.lat
City geo location, latitudecity.coord.lon
City geo location, longitude
city.country
Country code (GB, JP etc.)
cnt
Number of lines returned by this API calllist
list.dt
Time of data forecasted, unix, UTClist.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, hPalist.main.sea_level
Atmospheric pressure on the sea level, hPalist.main.grnd_level
Atmospheric pressure on the ground level, hPalist.main.humidity
Humidity, %list.main.temp_kf
Internal parameter
list.weather
(more info Weather condition codes)list.weather.id
Weather condition idlist.weather.main
Group of weather parameters (Rain, Snow, Extreme etc.)list.weather.description
Weather condition within the grouplist.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);
}
Leave a Reply
You must be logged in to post a comment.