-
Notifications
You must be signed in to change notification settings - Fork 0
/
PurpleAir_OLED_display-v1.ino
271 lines (226 loc) · 7.1 KB
/
PurpleAir_OLED_display-v1.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
/* PurpleAir Display: Show current PM2.5 from a local PurpleAir on a 16x2 OLED display.
*
* Connect to wifi, connect to local PurpleAir monitor, get the current PM2.5 values
* from the air monitor's JSON API, print the air quality on attached 16x2 OLED display.
*
* !!--------------------------- HERE BE DRAGONS ---------------------------!!
* !! !!
* !! This program relies on delay() for timing which is bad. !!
* !! Don't use this. Use version 2.0+ !!
* !!=======================================================================!!
*
* The LCD is wired to the top header of the HUZZAH32, sequentially (except for power):
* LCD 5V pin to HUZZAH pin USB
* LCD GND pin to HUZZAH pin GND
* LCD RS pin to HUZZAH pin 13
* LCD R/W pin to HUZZAH pin 12
* LCD Enable pin to HUZZAH pin 27
* LCD D4 pin to HUZZAH pin 33
* LCD D5 pin to HUZZAH pin 15
* LCD D6 pin to HUZZAH pin 32
* LCD D7 pin to HUZZAH pin 14
*/
#include <Adafruit_CharacterOLED.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#define DEBUG_STRINGS 0 // Enabling debug strings over serial increases program size
const char* ssid = "Starbucks Wifi";
const char* password = "psk here";
const char* api_server = "192.168.10.10";
const char* url = "/json";
const char* version = "v1.0";
Adafruit_CharacterOLED lcd(OLED_V2, 13, 12, 27, 33, 15, 32, 14);
WiFiClient client;
void(* resetFunc) (void) = 0;
// Write both lines to the 16x2 display, existing contents cleared
void lcdLines(String l1, String l2)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(l1);
lcd.setCursor(0, 1);
lcd.print(l2);
}
void setup()
{
Serial.begin(115200);
delay(10);
#if DEBUG_STRINGS
Serial.print("[*] PurpleAir Display ");
Serial.println(version);
#endif
lcdLines("PurpleAir", String("Display ") + version);
delay(2500);
// We start by connecting to a WiFi network
#if DEBUG_STRINGS
Serial.println();
Serial.println();
Serial.print("[+] Connecting to ");
Serial.println(ssid);
#endif
lcdLines("Connecting to:", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
#if DEBUG_STRINGS
Serial.print(".");
#endif
}
#if DEBUG_STRINGS
byte macAddr[6];
Serial.println();
Serial.println("[+] WiFi connected");
Serial.print("[.] IP address: ");
Serial.println(WiFi.localIP());
WiFi.macAddress(macAddr);
Serial.print("[.] MAC address: ");
Serial.print(macAddr[5],HEX);
Serial.print(":");
Serial.print(macAddr[4],HEX);
Serial.print(":");
Serial.print(macAddr[3],HEX);
Serial.print(":");
Serial.print(macAddr[2],HEX);
Serial.print(":");
Serial.print(macAddr[1],HEX);
Serial.print(":");
Serial.println(macAddr[0],HEX);
#endif
lcdLines("Connected as:", WiFi.localIP().toString());
}
void loop()
{
const int httpPort = 80;
delay(1000);
#if DEBUG_STRINGS
Serial.print("[+] Connecting to: ");
Serial.println(api_server);
#endif
// Use WiFiClient class to create TCP connections
if (!client.connect(api_server, httpPort)) {
#if DEBUG_STRINGS
Serial.println("[x] Connection failed.");
#endif
lcdLines("Connect failed:", String(api_server)+":"+httpPort);
delay(2500);
if(WiFi.status() != WL_CONNECTED) {
resetFunc();
}
return;
}
#if DEBUG_STRINGS
Serial.print("[+] Requesting URL: ");
Serial.println(url);
#endif
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + api_server + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
#if DEBUG_STRINGS
Serial.println("[x] Client timeout.");
#endif
client.stop();
lcdLines("Client timeout.", "");
delay(2500);
if(WiFi.status() != WL_CONNECTED) {
resetFunc();
}
return;
}
}
// Check HTTP status
char status[32] = {0};
client.readBytesUntil('\r', status, sizeof(status));
if (strcmp(status, "HTTP/1.1 200 OK") != 0) {
#if DEBUG_STRINGS
Serial.print("[x] Unexpected response: ");
Serial.println(status);
#endif
lcdLines("Not an HTTP", "200 response");
delay(2500);
if(WiFi.status() != WL_CONNECTED) {
resetFunc();
}
return;
}
// Skip HTTP headers
char endOfHeaders[] = "\r\n\r\n";
if (!client.find(endOfHeaders)) {
#if DEBUG_STRINGS
Serial.println("[x] Invalid response, couldn't find end of headers.");
#endif
lcdLines("Not an HTTP", "response");
delay(2500);
if(WiFi.status() != WL_CONNECTED) {
resetFunc();
}
return;
}
// Allocate JSON doc, will hold response from API server
DynamicJsonDocument jsonDoc(1700);
// Parse JSON object
DeserializationError jsonError = deserializeJson(jsonDoc, client);
if (jsonError) {
#if DEBUG_STRINGS
Serial.println("[x] JSON parsing failed.");
Serial.println(jsonError.c_str());
#endif
lcdLines("JSON parsing", "failed :(");
delay(2500);
if(WiFi.status() != WL_CONNECTED) {
resetFunc();
}
return;
}
// Extract values
#if DEBUG_STRINGS
String sensor = jsonDoc["Geo"];
int rssi = jsonDoc["rssi"];
#endif
float pm25_a = jsonDoc["pm2_5_atm"];
float pm25_b = jsonDoc["pm2_5_atm_b"];
String pm25 = String((pm25_a + pm25_b) / 2.0);
#if DEBUG_STRINGS
Serial.println("[+] Response:");
Serial.print("Name: ");
Serial.println(sensor);
Serial.print("Sensor RSSI: ");
Serial.println(String(rssi));
Serial.print("PM2.5 Channel A: ");
Serial.println(String(pm25_a));
Serial.print("PM2.5 Channel B: ");
Serial.println(String(pm25_b));
Serial.print("PM2.5 Average: ");
Serial.println(pm25);
#endif
// Disconnect
client.stop();
lcdLines(String("PM2.5 ")+pm25, ""); //, WiFi.localIP());
#if DEBUG_STRINGS
Serial.println();
Serial.println("[.] Done. Waiting 40 seconds to fetch again.");
#endif
// Print a . every 10 seconds on the right edge to indicate it's still working
delay(10000);
lcd.setCursor(13, 0);
lcd.print(".");
#if DEBUG_STRINGS
Serial.print(".");
#endif
delay(10000);
lcd.setCursor(14, 0);
lcd.print(".");
#if DEBUG_STRINGS
Serial.print(".");
#endif
delay(10000);
lcd.setCursor(15, 0);
lcd.print(".");
#if DEBUG_STRINGS
Serial.println(".");
#endif
delay(10000);
}