-
Notifications
You must be signed in to change notification settings - Fork 0
/
lungs_v03.ino
297 lines (254 loc) · 7.35 KB
/
lungs_v03.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
Created May 2, 2023
by Priyanka Makin
Based on the DweetGet example by Tom Igoe.
This code creates an HTTP client and connected to the OpenWeather Map API.
It gets the current AQI data every few minutes and a watch dog timer is implemented
in the case the requests get hung up on an error.
*/
#include <ArduinoHttpClient.h>
#include <WiFiNINA.h>
#include <wdt_samd21.h>
#include <Adafruit_NeoPixel.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;
char pass[] = SECRET_PASS;
const char serverAddress[] = "api.openweathermap.org"; // server address
int port = 80;
WiFiClient wifi;
HttpClient client = HttpClient(wifi, serverAddress, port);
int status = WL_IDLE_STATUS;
int errCount = 0; // Holds the number of sequential errors
int loopCount = 0; // Counts the number of times we go through the ~10 second loop
int currAqi;
// For the neopixel ring
int LEDpin = 6;
int numPixels = 16;
Adafruit_NeoPixel pixels(numPixels, LEDpin, NEO_GRB + NEO_KHZ800);
uint32_t currColor;
uint32_t white;
uint32_t green;
uint32_t yellow;
uint32_t orange;
uint32_t red;
// assemble the path for the GET message:
String path = "/data/2.5/air_pollution?lat=33.4&lon=111.8&appid=5070c0ca8af79010d5d00b6f33016df8";
void setup() {
Serial.begin(9600);
if (!Serial) delay(3000);
// Initialize the LED ring
pixels.begin();
Serial.println("Clear");
pixels.clear();
pixels.show();
delay(3000);
uint32_t purple = pixels.Color(153, 51, 255);
uint32_t blue = pixels.Color(0, 0, 255);
// For air quality status
white = pixels.Color(255, 255, 255);
green = pixels.Color(0, 204, 0);
yellow = pixels.Color(255, 255, 0);
orange = pixels.Color(255, 102, 0);
red = pixels.Color(255, 0, 0);
// Turn the pixels purple while waiting to connect
pixels.fill(purple);
pixels.show();
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to Network named: ");
Serial.println(ssid); // print the network name (SSID);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
}
// Once Arduino connected to the internet, turn the pixels blue
pixels.fill(blue);
pixels.show();
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// Configure the pins for needed to drive the pumps
pinMode(2, OUTPUT); // pump 1
pinMode(3, OUTPUT);
pinMode(4, OUTPUT); // pump2
pinMode(5, OUTPUT);
wdt_init(WDT_CONFIG_PER_16K); // Define the "timeout" of the watch dog timer. 16K = 16384 clock cycles (16 sec)
}
void loop() {
// We want to update the air quality data every 20 times through this loop
// As of right now, I'm not exactly sure how many seconds that is...
if (loopCount % 20 == 0) {
currAqi = getAQI();
Serial.print("AQI: ");
Serial.println(currAqi);
updateLEDs(currAqi);
breatheLungs(currAqi);
// Reset the loop count so that the variable doesn't overflow
loopCount = 0;
}
// Do one heart beat - takes approx 6 seconds
heartBeat(currColor);
// Reset the watchdog timer
Serial.println("I'm resetting the watchdog");
wdt_reset();
loopCount++;
Serial.println(loopCount);
}
int getAQI() {
// send the GET request
Serial.println("making GET request");
client.get(path);
// read the status code and body of the response
int statusCode = client.responseStatusCode();
String response = client.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
client.stop(); // close the request
// Increment error code if it's appropriate
if (statusCode == -2 | statusCode == -3) {
digitalWrite(LED_BUILTIN, HIGH);
errCount++;
Serial.println(errCount);
} else if (statusCode == 200) {
digitalWrite(LED_BUILTIN, LOW);
errCount = 0;
}
// If an error count more than 3
if (errCount > 2) {
Serial.println("I've had too many errors");
while(1); // Wait so that the watch dog can reset
}
/*
Typical response is:
{"coord":{"lon":111.8,"lat":33.4},
"list":[{"main":{"aqi":3},
"components":{"co":420.57,"no":0,"no2":4.24,"o3":84.4,"so2":9.54,"pm2_5":39.52,"pm10":40.9,"nh3":0.98},
"dt":1683054449}]}
I want "aqi": numberValue
*/
// now parse the response looking for "aqi":
int labelStart = response.indexOf("aqi\":");
// The AQI value is right after the "aqi": substring
// That's 5 characters after the initial "
int contentStart = labelStart + 5;
// find the following } and get what's between the braces:
int contentEnd = response.indexOf("}", labelStart);
String content = response.substring(contentStart, contentEnd);
// now convert it to an int
int aqi = content.toInt();
return aqi;
}
void updateLEDs(int airQuality) {
pixels.clear();
// Dim the brightness to not consume too much power
pixels.setBrightness(75);
switch(airQuality) {
case 1: // Good air quality
currColor = white; // White
break;
case 2: // Fair air quality
currColor = green; // Green
break;
case 3: // Moderate air quality
currColor = yellow; // Yellow
break;
case 4: // Poor air quality
currColor = orange; // Orange
break;
case 5: // Very bad air quality
currColor = red; // Red
break;
default:
// If the value doesn't make sense, turn off the LEDs
pixels.clear();
break;
}
// Update LEDs
for (int i = 0; i < numPixels; i++) {
pixels.setPixelColor(i, currColor);
pixels.show();
delay(100);
}
}
void heartBeat(uint32_t color) {
// Heart beat - dim
Serial.println("I'm dimming");
for (int i = 50; i > 2; i--) {
pixels.setBrightness(i);
pixels.fill(color);
pixels.show();
delay(50);
}
// light up
Serial.println("I'm lighting up");
pixels.fill(currColor);
for (int i = 2; i < 50; i++) {
pixels.setBrightness(i);
pixels.fill(color);
pixels.show();
delay(50);
}
}
void breatheLungs(int airQuality) {
switch(airQuality) {
case 1: // Good air quality
breathePumps(7000, 3000);
break;
case 2: // Fair
breathePumps(5000, 3000);
break;
case 3: // Moderate
breathePumps(3000, 2000);
break;
case 4: // Poor
breathePumps(2000, 1000);
break;
case 5: // Very bad
breathePumps(1000, 500);
break;
default:
// Debug
Serial.println("Weird data, don't know what to do");
break;
}
}
// These are the pump functions
void inflate(int time) {
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, HIGH);
delay(time);
}
void deflate(int time) {
digitalWrite(2, HIGH);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
delay(time);
}
void turnOffPumps() {
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
}
void breathePumps(int inflateTime, int deflateTime) {
// Always start with a big inhale
wdt_reset();
inflate(8000); // Inflate for 10 seconds
for (int i = 0; i < 9; i++) {
wdt_reset();
deflate(deflateTime);
inflate(inflateTime);
}
// Last deflate
deflate(deflateTime);
turnOffPumps();
}