/**************************************************************************
This is an example for our Monochrome OLEDs based on SSD1306 drivers
Pick one up today in the adafruit shop!
------> http://www.adafruit.com/category/63_98
This example is for a 128x64 pixel display using I2C to communicate
3 pins are required to interface (two I2C and one reset).
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source
hardware by purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries,
with contributions from the open source community.
BSD license, check license.txt for more information
All text above, and the splash screen below must be
included in any redistribution.
**************************************************************************/
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//for RTC
#include "RTClib.h"
//for DHT
#include "DHTesp.h"
//for http
#include <Arduino.h>
#include <WiFi.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#define USE_SERIAL Serial
#define SECRET_SSID "Wokwi-GUEST" // replace MySSID with your WiFi network name
#define SECRET_PASS "" // replace MyPassword with your WiFi password
#define WIFI_CHANNEL 6
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
char ssid[] = SECRET_SSID; // your network SSID (name)
char password[] = SECRET_PASS; // your network password
int a[3] = {17, 18, 19};
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
//time
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
//dht
DHTesp DHT;
//oled
#define LOGO_HEIGHT 30
#define LOGO_WIDTH 26
static const unsigned char PROGMEM a_bmp[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xc0, 0x18, 0x00,
0x01, 0x80, 0x0c, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x71, 0xc6, 0x00,
0x02, 0x00, 0x02, 0x00, 0x02, 0x20, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x06, 0x00,
0x02, 0x0f, 0x04, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0xc0, 0x38, 0x00,
0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char PROGMEM b_bmp[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xc0, 0x18, 0x00,
0x01, 0x80, 0x0c, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x71, 0xc6, 0x00,
0x02, 0x00, 0x02, 0x00, 0x02, 0x20, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x0e, 0x06, 0x00,
0x02, 0x0e, 0x04, 0x00, 0x03, 0x0e, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0xc0, 0x38, 0x00,
0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char PROGMEM c_bmp[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xc0, 0x18, 0x00,
0x01, 0x80, 0x0c, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x71, 0xc6, 0x00,
0x02, 0x00, 0x02, 0x00, 0x02, 0x20, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x06, 0x00,
0x02, 0x0c, 0x04, 0x00, 0x03, 0x12, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0xc0, 0x38, 0x00,
0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const unsigned char PROGMEM d_bmp[] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x78, 0x70, 0x00, 0x00, 0xc0, 0x18, 0x00,
0x01, 0x80, 0x0c, 0x00, 0x03, 0x00, 0x04, 0x00, 0x02, 0xe0, 0xe4, 0x00, 0x02, 0x80, 0x26, 0x00,
0x02, 0x00, 0x02, 0x00, 0x02, 0x20, 0x82, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x06, 0x00,
0x02, 0x13, 0x04, 0x00, 0x03, 0x1e, 0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0xc0, 0x38, 0x00,
0x00, 0x7f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//for the rgb we use
void rgb_checker(int pm25, const int rgb[3]) {
if (0 <= pm25 <= 50) {
digitalWrite(rgb[0], 0);
digitalWrite(rgb[1], 255);
digitalWrite(rgb[2], 0);
display.drawBitmap(70,34,d_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
} else if (51 <= pm25 <= 100) {
digitalWrite(rgb[0], 255);
digitalWrite(rgb[1], 255);
digitalWrite(rgb[2], 0);
display.drawBitmap(70,34,d_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
} else if (101 <= pm25 <= 150) {
digitalWrite(rgb[0], 255);
digitalWrite(rgb[1], 153);
digitalWrite(rgb[2], 51);
display.drawBitmap(70,34,b_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
} else if (151 <= pm25 <= 200) {
digitalWrite(rgb[0], 255);
digitalWrite(rgb[1], 0);
digitalWrite(rgb[2], 0);
display.drawBitmap(70,34,c_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
} else if (201 <= pm25 <= 300) {
digitalWrite(rgb[0], 105);
digitalWrite(rgb[1], 0);
digitalWrite(rgb[2], 204);
display.drawBitmap(70,34,c_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
} else if (301 <= pm25 <= 500) {
digitalWrite(rgb[0], 102);
digitalWrite(rgb[1], 0);
digitalWrite(rgb[2], 0);
display.drawBitmap(70,34,a_bmp,LOGO_WIDTH,LOGO_HEIGHT,1);
}
}
void setup() {
for (int i = 0; i < 3; i++) {
pinMode(a[i], OUTPUT);
}
Serial.begin(9600);
//for Http
while (!Serial) {
delay(100);
}
// We start by connecting to a WiFi network
Serial.println();
Serial.println("******************************************************");
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password, 6);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//for Temp and Hum
DHT.setup(14, DHTesp::DHT22);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
abort();
}
// Show initial display buffer contents on the screen --
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
display.clearDisplay();
// Clear the buffer
display.clearDisplay();
}
void loop() {
display.setTextSize(1);
display.setTextColor(1);
display.setCursor(0, 0);
//http
//display
TempAndHumidity data = DHT.getTempAndHumidity();
DateTime now = rtc.now();
display.print(now.year(), DEC);
display.print('/');
display.print(now.month(), DEC);
display.print('/');
display.print(now.day(), DEC);
display.println(" Tainan");
display.print(now.hour(), DEC);
display.print(':');
display.print(now.minute(), DEC);
display.print(':');
display.print(now.second(), DEC);
display.println();
display.print("hum: ");
display.print(data.humidity);
display.print(" temp: ");
display.println(data.temperature);
// wait for WiFi connection
if ((WiFi.status() == WL_CONNECTED)) {
HTTPClient http;
USE_SERIAL.print("[HTTP] begin...\n");
// configure traged server and url
//http.begin("https://www.howsmyssl.com/a/check", ca); //HTTPS
http.begin("https://data.moenv.gov.tw/api/v2/aqx_p_02?api_key=e8dd42e6-9b8b-43f8-991e-b3dee723a52d&limit=1000&sort=datacreationdate%20desc&format=JSON"); //HTTP
USE_SERIAL.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
USE_SERIAL.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
// String input;
DynamicJsonDocument doc(16384);
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
return;
}
for (JsonObject field : doc["fields"].as<JsonArray>()) {
const char* field_id = field["id"]; // "site", "county", "pm25", "datacreationdate", "itemunit"
const char* field_type = field["type"]; // "text", "text", "text", "text", "text"
const char* field_info_label = field["info"]["label"]; // "測站名稱", "縣市名稱", "細懸浮微粒濃度", "資料建置日期", "測項單位"
}
const char* resource_id = doc["resource_id"]; // "c1f31192-babd-4105-b880-a4c2e23a3276"
const char* extras_api_key = doc["__extras"]["api_key"]; // "e8dd42e6-9b8b-43f8-991e-b3dee723a52d"
bool include_total = doc["include_total"]; // true
const char* total = doc["total"]; // "78"
const char* resource_format = doc["resource_format"]; // "object"
const char* limit = doc["limit"]; // "1000"
const char* offset = doc["offset"]; // "0"
const char* links_start = doc["_links"]["start"];
const char* links_next = doc["_links"]["next"];
for (JsonObject record : doc["records"].as<JsonArray>()) {
const char* record_site = record["site"]; // "大城", "富貴角", "麥寮", "關山", "馬公", "金門", "馬祖", "埔里", "復興", ...
const char* record_county = record["county"]; // "彰化縣", "新北市", "雲林縣", "臺東縣", "澎湖縣", "金門縣", "連江縣", "南投縣", ...
const char* record_pm25 = record["pm25"]; // "22", "22", "29", "8", "19", "34", "27", "2", "38", "16", ...
const char* record_datacreationdate = record["datacreationdate"]; // "2023-11-30 16:00", "2023-11-30 ...
const char* record_itemunit = record["itemunit"]; // "μg/m3", "μg/m3", "μg/m3", "μg/m3", "μg/m3", ...
if (record["site"] == "臺南") {
String site = "Tainan";
int pm25 = record["pm25"];
String creationtime = record["datacreationdate"];
display.print(" pm2.5 : ");
display.print(pm25);
display.println(" ug/m3");
rgb_checker(pm25, a);
}
}
} else {
USE_SERIAL.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}
}
display.display();
delay(1000);
display.clearDisplay();
}