#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <RTClib.h>
// OLED 設定
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
RTC_DS3231 rtc;
// RGB LED 腳位定義
const int redPin = 15;
const int greenPin = 16;
const int bluePin = 17;
// DHT22 感測器設定
#define DHTPIN 18 // DHT22 資料腳位
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);
//時鐘設定
#define C_X 84
#define C_Y 32
// 按鈕設定
int Location = 127;
const int buttonPin = 19;
int displayMode = 0;
bool showPowerOn = true; // 控制顯示模式,默認顯示開機動畫
unsigned long lastButtonPress = 0; // 防止按鈕抖動的時間記錄
// 模擬 AQI 輸入
const int sensorPin = 34;
static const unsigned char warning_logo[]={
// 'warning', 30x30px
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x80, 0x00,
0x00, 0x0c, 0xc0, 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x10, 0x20, 0x00,
0x00, 0x23, 0x10, 0x00, 0x00, 0x27, 0x90, 0x00, 0x00, 0x47, 0x88, 0x00, 0x00, 0xc7, 0x8c, 0x00,
0x00, 0x87, 0x84, 0x00, 0x01, 0x07, 0x82, 0x00, 0x01, 0x07, 0x82, 0x00, 0x02, 0x07, 0x81, 0x00,
0x06, 0x07, 0x81, 0x80, 0x04, 0x03, 0x00, 0x80, 0x08, 0x00, 0x00, 0x40, 0x08, 0x03, 0x00, 0x40,
0x10, 0x07, 0x80, 0x20, 0x10, 0x07, 0x80, 0x20, 0x20, 0x07, 0x80, 0x10, 0x60, 0x03, 0x00, 0x18,
0x40, 0x00, 0x00, 0x08, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char water_logo[]={
// 'water', 30x30px
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00,
0x00, 0x06, 0xc0, 0x00, 0x00, 0x0c, 0xc0, 0x00, 0x00, 0x1c, 0x60, 0x00, 0x00, 0x18, 0x30, 0x00,
0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x18, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x60, 0x0c, 0x00,
0x00, 0xc0, 0x0c, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x01, 0x80, 0x06, 0x00, 0x01, 0x80, 0x03, 0x00,
0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x80, 0x03, 0x00, 0x01, 0x80, 0x02, 0x00, 0x01, 0x80,
0x02, 0x40, 0x01, 0x80, 0x03, 0x60, 0x01, 0x80, 0x03, 0x60, 0x01, 0x00, 0x03, 0x30, 0x03, 0x00,
0x01, 0x9c, 0x07, 0x00, 0x00, 0xce, 0x0e, 0x00, 0x00, 0x60, 0x1c, 0x00, 0x00, 0x3e, 0xf8, 0x00,
0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char power_logo[]={
// 'power', 203x64px
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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0x30, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x3f, 0xff, 0x81, 0x80, 0x30, 0x00, 0x30, 0x07, 0x00, 0x10, 0x00, 0x01, 0x80, 0x00, 0x80, 0x00,
0x00, 0x00, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xb3, 0x11, 0x81, 0x80, 0x18, 0x00,
0x30, 0x0f, 0x80, 0x0c, 0xff, 0x81, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff, 0xfc, 0x0c, 0x00, 0x06,
0x00, 0x00, 0x00, 0x04, 0x33, 0x11, 0x81, 0x8f, 0xff, 0xf0, 0x30, 0x1c, 0xc0, 0x06, 0xc1, 0x91,
0x80, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x33, 0x11,
0x81, 0x81, 0x81, 0x80, 0x30, 0x38, 0x60, 0x03, 0xc1, 0x91, 0x80, 0x00, 0x80, 0x00, 0x00, 0x30,
0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x3f, 0xff, 0x81, 0x80, 0x83, 0x01, 0xfc, 0x60,
0x30, 0x00, 0xc1, 0x91, 0x80, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x01, 0x80, 0xc3, 0x00, 0x31, 0xdf, 0xec, 0x00, 0xc1, 0x91, 0x80, 0x60,
0x83, 0x00, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x8f,
0xff, 0xf0, 0x33, 0x00, 0x06, 0x30, 0xff, 0x91, 0x80, 0x40, 0x83, 0x00, 0x00, 0x30, 0x00, 0x0c,
0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x7f, 0xff, 0x8f, 0xe0, 0x00, 0x00, 0x38, 0x00, 0x00, 0x18,
0xc1, 0x91, 0x80, 0xc0, 0x81, 0x80, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x0c, 0xc1, 0x91, 0x80, 0xc0, 0x81, 0x80,
0x00, 0x30, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x01, 0x87, 0xff, 0xe0,
0x7c, 0xfd, 0xfc, 0x06, 0xc1, 0x91, 0x80, 0xc0, 0x81, 0x80, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06,
0x00, 0x00, 0x00, 0x04, 0x3f, 0xff, 0x01, 0x86, 0x00, 0x60, 0x76, 0xcd, 0x8c, 0x00, 0xc1, 0x91,
0x81, 0x80, 0x80, 0xc0, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x30, 0x03,
0x01, 0x86, 0x00, 0x60, 0xf2, 0xcd, 0x8c, 0x00, 0xff, 0x91, 0x81, 0x80, 0x80, 0xc0, 0x00, 0x30,
0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x30, 0x03, 0x01, 0x87, 0xff, 0xe0, 0xf0, 0xcd,
0x8c, 0x00, 0xc1, 0x91, 0x81, 0x80, 0x80, 0x60, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00,
0x00, 0x04, 0x30, 0x03, 0x01, 0x86, 0x00, 0x60, 0xb0, 0xcd, 0x8c, 0x00, 0xc1, 0x91, 0x83, 0x00,
0x80, 0x60, 0x00, 0x30, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x04, 0x3f, 0xff, 0x01, 0x86,
0x00, 0x61, 0xb0, 0xfd, 0xfc, 0x06, 0xc1, 0x91, 0x83, 0x00, 0x80, 0x60, 0x00, 0x30, 0x00, 0x0c,
0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0xc3, 0x00, 0x01, 0x86, 0x00, 0x61, 0x30, 0x00, 0x00, 0x06,
0xc1, 0x91, 0x86, 0x00, 0x80, 0x30, 0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05,
0x86, 0x21, 0x01, 0x87, 0xff, 0xe0, 0x30, 0x30, 0x30, 0x04, 0xff, 0x91, 0x86, 0x00, 0x80, 0x30,
0x00, 0x30, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x00, 0x00, 0x07, 0x0c, 0x33, 0x01, 0xb0, 0x66, 0x00,
0x30, 0x30, 0x60, 0x0c, 0x36, 0x11, 0x8c, 0x00, 0x80, 0x30, 0x00, 0x30, 0x00, 0x3f, 0xff, 0xff,
0xc0, 0x00, 0x00, 0x0c, 0x3c, 0x1e, 0x01, 0xe0, 0xc6, 0x00, 0x30, 0x70, 0x60, 0x08, 0x66, 0x01,
0x80, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0xec, 0x0c,
0x03, 0x80, 0xc6, 0x10, 0x30, 0xf8, 0xf0, 0x18, 0x63, 0x01, 0x80, 0x00, 0x80, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0xc4, 0x0c, 0x01, 0x86, 0x10, 0x31, 0xcd,
0xd8, 0x10, 0xc1, 0x01, 0x80, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x83, 0x00, 0x0f, 0x06, 0x30, 0x33, 0x85, 0x8c, 0x31, 0x81, 0x81, 0x80, 0x00,
0x80, 0x00, 0x00, 0x30, 0x00, 0x01, 0xc0, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x80, 0x38,
0x03, 0xe0, 0x32, 0x03, 0x06, 0x21, 0x00, 0x9f, 0x00, 0x1f, 0x80, 0x01, 0xff, 0xff, 0xfe, 0x0e,
0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0xc0, 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, 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, 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, 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, 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, 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, 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,
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, 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, 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, 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, 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, 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, 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, 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
};
static const unsigned char snowflake_logo[]={
// 'snowflake', 30x30px
0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x07, 0x80, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x1b, 0x60, 0x00, 0x08, 0x0f, 0xc0, 0x00, 0x2d, 0x87, 0x82, 0xd0,
0x3d, 0xb3, 0x36, 0xf0, 0x1f, 0xbb, 0x77, 0xe0, 0x3f, 0x9f, 0xe7, 0xf0, 0x03, 0xdf, 0xff, 0x00,
0x0f, 0xfb, 0x7f, 0xc0, 0x00, 0x7f, 0xf8, 0x00, 0x03, 0xff, 0xff, 0x00, 0x03, 0xe7, 0x9f, 0x00,
0x00, 0x7f, 0xf8, 0x00, 0x0f, 0x7b, 0x7b, 0xc0, 0x03, 0xff, 0xef, 0x00, 0x3f, 0x9f, 0xe7, 0xf0,
0x1f, 0x9f, 0x77, 0xe0, 0x3d, 0xbb, 0x36, 0xf0, 0x2d, 0x97, 0x96, 0xd0, 0x00, 0x0f, 0xc0, 0x40,
0x00, 0x1f, 0x60, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x0f, 0xc0, 0x00,
0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00
};
static const unsigned char sun_logo[]={
// 'sun', 30x30px
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x83, 0x04, 0x00,
0x00, 0xc3, 0x0c, 0x00, 0x00, 0xe0, 0x1c, 0x00, 0x00, 0x43, 0x08, 0x00, 0x00, 0x1f, 0xe0, 0x00,
0x1c, 0x7f, 0xf8, 0xe0, 0x0e, 0xff, 0xfd, 0xc0, 0x04, 0xff, 0xfc, 0x80, 0x01, 0xff, 0xfe, 0x00,
0x01, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x00, 0x3b, 0xff, 0xff, 0x70, 0x3b, 0xff, 0xff, 0x78,
0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x04, 0xff, 0xfe, 0x80,
0x0e, 0xff, 0xfd, 0xc0, 0x1c, 0x7f, 0xf8, 0xe0, 0x00, 0x1f, 0xf0, 0x00, 0x00, 0x47, 0x88, 0x00,
0x00, 0x60, 0x1c, 0x00, 0x00, 0xc3, 0x0c, 0x00, 0x00, 0x83, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char moon_logo[]={
// 'moon', 30x30px
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x1f, 0x00,
0x00, 0x3e, 0x0f, 0x00, 0x00, 0xfc, 0x04, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00,
0x07, 0xf0, 0x08, 0x00, 0x0f, 0xe0, 0x0c, 0x00, 0x1f, 0xe0, 0x0f, 0xe0, 0x1f, 0xe0, 0x0f, 0xe0,
0x3f, 0xc0, 0x3f, 0xc0, 0x3f, 0xc0, 0x7f, 0xc0, 0x3f, 0xc0, 0x7f, 0xc0, 0x3f, 0xe0, 0x0f, 0xe0,
0x3f, 0xe0, 0x07, 0x70, 0x3f, 0xe0, 0x06, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00,
0x1f, 0xf8, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x30, 0x1f, 0xff, 0x01, 0xf0, 0x0f, 0xff, 0xff, 0xf0,
0x07, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0xff, 0xfe, 0x00,
0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char good_logo[]={
// 'good', 14x14px
0x00, 0x00, 0x10, 0x00, 0x19, 0xf0, 0x18, 0x20, 0x14, 0x40, 0x1c, 0x78, 0xf7, 0xfc, 0x1c, 0x60,
0x1c, 0x60, 0x1c, 0x60, 0x36, 0x60, 0x00, 0xc0, 0x00, 0x40, 0x00, 0x00
};
static const unsigned char notgood_logo[]={
// 'notgood', 28x14px
0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xc0, 0x00, 0x7f, 0x80, 0x47, 0xc0, 0x01, 0x80, 0x41, 0x80,
0x03, 0x00, 0xc3, 0x00, 0x03, 0x00, 0xf3, 0x60, 0x06, 0x47, 0xbf, 0xf0, 0x0a, 0x30, 0xb1, 0x00,
0x12, 0x18, 0xe1, 0x00, 0x62, 0x08, 0x61, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x02, 0x01, 0x17, 0x00,
0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00
};
void setup() {
Serial.begin(115200);
// 設置 RGB LED 腳位為輸出
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
// 設置按鈕腳位
pinMode(buttonPin, INPUT_PULLUP); // 使用內建上拉電阻
// 初始化 DHT22
dht.begin();
if (!rtc.begin()) {
Serial.println("Couldn't find RTC");
while (1);
}
if (rtc.lostPower()) {
Serial.println("RTC 停止運行,設定為當前時間!");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // 設定為編譯時的時間
}
// 初始化 OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
Serial.println("OLED 初始化失敗");
while (true);
}
display.clearDisplay();
}
float a = 45;
float theta_r, x, y;
int i = 360, t, hour, minute, second, year, month, day;
const int timeset = 8;
void loop() {
if (showPowerOn) {
Power_on();
return; // 停止後續邏輯執行
}
// 檢查按鈕狀態
if (digitalRead(buttonPin) == LOW && millis() - lastButtonPress > 300) {
displayMode = (displayMode + 1) % 3; // 切換模式,三種模式循環
lastButtonPress = millis();
}
//Serial.println(displayMode);
if (displayMode == 0) {
// AQI 模式
updateOLED_AQI();
} else if (displayMode == 1){
// 溫濕度模式
float temperature = dht.readTemperature();
float humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity)) {
updateOLED_TempHum("Error", "Error");
} else {
updateOLED_TempHum(String(temperature, 1), String(humidity, 1));
}
} else if (displayMode == 2){
updateOLED_Time();
}
//delay(50); // 每秒更新一次
}
//設置開機跑馬燈
void Power_on(){
// 如果處於開機畫面狀態
if (digitalRead(buttonPin) == LOW && millis() - lastButtonPress > 300) {
showPowerOn = false; // 按下按鈕後退出開機畫面
lastButtonPress = millis();
display.clearDisplay(); // 清除開機畫面
return;
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.drawBitmap(Location,0, power_logo, 203, 64, SSD1306_WHITE);
display.display();
if(Location<=-203){
Location = 127;
}
Location-=3;
delay(1);
}
// 設置 RGB 顏色函數
void setColor(int red, int green, int blue) {
analogWrite(redPin, red ); // RGB 範圍 0~255,但 ESP32 PWM 是 0~1023
analogWrite(greenPin, green );
analogWrite(bluePin, blue );
}
// 更新 OLED 顯示 AQI 模式
void updateOLED_AQI() {
display.setCursor(0, 0);
int sensorValue = analogRead(sensorPin);
int airQuality = map(sensorValue, 0, 4095, 0, 500); // AQI 範圍 0~500
// 更新 RGB LED 顏色
if (airQuality >= 0 && airQuality <= 50) {
setColor(0, 255, 0); // 綠色
display.clearDisplay();
display.fillRect(0, 47, 19, 15, SSD1306_WHITE);
} else if (airQuality > 50 && airQuality <= 100) {
setColor(255, 255, 0); // 黃色
display.clearDisplay();
display.fillRect(0, 47, 20, 15, SSD1306_WHITE);
display.fillRect(22, 47, 20, 15, SSD1306_WHITE);
} else if (airQuality > 100 && airQuality <= 150) {
setColor(255, 80, 0); // 橘色
display.clearDisplay();
display.fillRect(0, 47, 20, 15, SSD1306_WHITE);
display.fillRect(22, 47, 20, 15, SSD1306_WHITE);
display.fillRect(44, 47, 20, 15, SSD1306_WHITE);
} else if (airQuality > 150 && airQuality <= 200) {
setColor(255, 0, 0); // 紅色
display.clearDisplay();
display.fillRect(0, 47, 20, 15, SSD1306_WHITE);
display.fillRect(22, 47, 20, 15, SSD1306_WHITE);
display.fillRect(44, 47, 20, 15, SSD1306_WHITE);
display.fillRect(66, 47, 20, 15, SSD1306_WHITE);
} else if (airQuality > 200 && airQuality <= 300) {
setColor(128, 0, 128); // 紫色
display.clearDisplay();
display.fillRect(0, 47, 20, 15, SSD1306_WHITE);
display.fillRect(22, 47, 20, 15, SSD1306_WHITE);
display.fillRect(44, 47, 20, 15, SSD1306_WHITE);
display.fillRect(66, 47, 20, 15, SSD1306_WHITE);
display.fillRect(88, 47, 20, 15, SSD1306_WHITE);
} else if (airQuality > 300) {
setColor(185, 70, 87); // 咖啡色
display.clearDisplay();
display.fillRect(0, 47, 20, 14, SSD1306_WHITE);
display.fillRect(22, 47, 20, 14, SSD1306_WHITE);
display.fillRect(44, 47, 20, 14, SSD1306_WHITE);
display.fillRect(66, 47, 20, 14, SSD1306_WHITE);
display.fillRect(88, 47, 20, 14, SSD1306_WHITE);
display.fillRect(110, 47, 20, 14, SSD1306_WHITE);
}
display.println("Air Quality Monitor");
display.setCursor(47, 15);
display.print("AQI:");
display.println(airQuality);
display.drawBitmap(0,31, good_logo, 14, 14, SSD1306_WHITE);
display.drawBitmap(100,31, notgood_logo, 28, 14, SSD1306_WHITE);
display.drawLine(0, 45, 128, 45, SSD1306_WHITE);
display.drawLine(0, 63, 128, 63, SSD1306_WHITE);
display.display();
}
// 更新 OLED 顯示溫濕度模式
void updateOLED_TempHum(String temp, String hum) {
display.clearDisplay();
float tempfloat = temp.toFloat();
float humfloat = hum.toFloat();
if (tempfloat > 30){
display.drawBitmap(95,34, warning_logo, 30, 30, SSD1306_WHITE);
}
else if (tempfloat < 15){
display.drawBitmap(95,34, snowflake_logo, 30, 30, SSD1306_WHITE);
}
if (humfloat > 80){
display.drawBitmap(95,0, water_logo, 30, 30, SSD1306_WHITE);
}
display.setCursor(0, 0);
display.println("Temp & Humidity");
display.setCursor(0, 15);
display.print("Temp: ");
display.print(temp);
display.println(" C");
display.setCursor(0, 30);
display.print("Humidity: ");
display.print(hum);
display.println(" %");
display.display();
}
// 更新 OLED 顯示時間模式
void updateOLED_Time() {
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
DateTime now = rtc.now();
hour = now.hour();
minute = now.minute();
second = now.second();
year = now.year();
month = now.month();
day = now.day();
display.clearDisplay();
display.drawCircle(C_X, C_Y, 31, WHITE);
if (hour>=18 && hour<=23){
display.drawBitmap(0,17, moon_logo, 30, 30, SSD1306_WHITE);
}
else if (hour>=0 && hour<=5){
display.drawBitmap(0,17, moon_logo, 30, 30, SSD1306_WHITE);
}
else if (hour>=6 && hour<=17){
display.drawBitmap(0,17, sun_logo, 30, 30, SSD1306_WHITE);
}
for (int i = 0; i < 12; i++) {
float angle = i * 30;
float rd = angle * (PI/180.0);
int x_1 = C_X+29*cos(rd);
int y_1 = C_Y+29*sin(rd);
int x_2 = C_X+(50-25)*cos(rd);
int y_2 = C_Y+(50-25)*sin(rd);
display.drawLine(x_1, y_1, x_2, y_2, WHITE);
}
if (hour >= 24) {
hour -= 24; // 24小時制循環
day++;
}
display.setCursor(0, 1);
display.print(year);
display.print("/");
display.print(month);
display.print("/");
display.print(day);
display.setCursor(0, 55);
if(hour<10){
display.print("0");
}
display.print(hour);
display.print(":");
if(minute<10){
display.print("0");
}
display.print(minute);
display.print(":");
if(second<10){
display.print("0");
}
display.print(second);
t = 90-hour*30-minute*0.5;
theta_r = t*(PI/180.0);
x = C_X+15*cos(theta_r);
y = C_Y-15*sin(theta_r);
display.drawLine(C_X, C_Y, x, y, SSD1306_WHITE);
t = 90-minute*6;
theta_r = t*(PI/180.0);
x = C_X+25*cos(theta_r);
y = C_Y-25*sin(theta_r);
display.drawLine(C_X, C_Y, x, y, SSD1306_WHITE);
t = 90-second*6;
theta_r = t*(PI/180.0);
x = C_X+28*cos(theta_r);
y = C_Y-28*sin(theta_r);
display.drawLine(C_X, C_Y, x, y, SSD1306_WHITE);
display.display();
}