#include "unihiker_k10.h"
#include <WiFi.h>
#include <WiFiManager.h> // WiFiManager
// #include <WebServer.h>
// #include <DNSServer.h> // DNS ->
#include <time.h>
#include <cmath> //
UNIHIKER_K10 k10;
AHT20 aht20;
// WebServer server(80);
// DNSServer dnsServer; // DNS ->
// 3
uint8_t screen_dir = 3;
//
const int SCREEN_W = 320;
const int SCREEN_H = 240;
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
const int ALS_COVER_THRESHOLD = 40;
//
// :
// 4 x 7 x 5 = 140
// 2 x 2 = 4
// : 0-143 (144)
// : 144-163 (20)
// : 164-203 (40)
const int PARTICLE_COUNT = 250;
float partOffX[PARTICLE_COUNT] = {0};
float partOffY[PARTICLE_COUNT] = {0};
//
float partVelX[PARTICLE_COUNT] = {0};
float partVelY[PARTICLE_COUNT] = {0};
// HSV -> RGB helper
void hsv2rgb(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
float hh = fmod(h, 360.0f) / 60.0f;
int i = (int)floor(hh);
float f = hh - i;
float p = v * (1.0f - s);
float q = v * (1.0f - s * f);
float t = v * (1.0f - s * (1.0f - f));
float R=0,G=0,B=0;
switch(i) {
case 0: R=v; G=t; B=p; break;
case 1: R=q; G=v; B=p; break;
case 2: R=p; G=v; B=t; break;
case 3: R=p; G=q; B=v; break;
case 4: R=t; G=p; B=v; break;
case 5:
default: R=v; G=p; B=q; break;
}
r = (uint8_t)round(R * 255.0f);
g = (uint8_t)round(G * 255.0f);
b = (uint8_t)round(B * 255.0f);
}
//
// splits:
// offX, offY:
void drawFragmentedRect(int x, int y, int w, int h, bool isVertical, int splits, uint32_t color, float* offX, float* offY) {
if (isVertical) {
float segH = (float)h / splits;
for(int i=0; i<splits; i++) {
int curY = y + (int)(i * segH);
int curH = (int)((i + 1) * segH) - (int)(i * segH); //
k10.canvas->canvasRectangle(x + (int)offX[i], curY + (int)offY[i], w, curH, color, color, true);
}
} else {
float segW = (float)w / splits;
for(int i=0; i<splits; i++) {
int curX = x + (int)(i * segW);
int curW = (int)((i + 1) * segW) - (int)(i * segW);
k10.canvas->canvasRectangle(curX + (int)offX[i], y + (int)offY[i], curW, h, color, color, true);
}
}
}
// 7 (5)
// offX, offY: 35 (7*5) float
void drawBigDigit(int x, int y, int num, int scale, uint32_t color, float* offX, float* offY) {
// 7: A,B,C,D,E,F,G (0=off, 1=on)
const uint8_t segs[10] = {
0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B
};
uint8_t pattern = segs[num % 10];
int w = 12 * scale; //
int h = 20 * scale; // ()
int t = 2 * scale; //
const int FRAGS = 5; // 5
// Segment A (Top) - Horizontal [Idx 0-4]
if (pattern & 0x40) drawFragmentedRect(x + t, y, w - 2*t, t, false, FRAGS, color, &offX[0], &offY[0]);
// Segment B (Top-Right) - Vertical [Idx 5-9]
if (pattern & 0x20) drawFragmentedRect(x + w - t, y + t, t, h - 2*t, true, FRAGS, color, &offX[5], &offY[5]);
// Segment C (Bottom-Right) - Vertical [Idx 10-14]
if (pattern & 0x10) drawFragmentedRect(x + w - t, y + h + t, t, h - 2*t, true, FRAGS, color, &offX[10], &offY[10]);
// Segment D (Bottom) - Horizontal [Idx 15-19]
if (pattern & 0x08) drawFragmentedRect(x + t, y + 2*h, w - 2*t, t, false, FRAGS, color, &offX[15], &offY[15]);
// Segment E (Bottom-Left) - Vertical [Idx 20-24]
if (pattern & 0x04) drawFragmentedRect(x, y + h + t, t, h - 2*t, true, FRAGS, color, &offX[20], &offY[20]);
// Segment F (Top-Left) - Vertical [Idx 25-29]
if (pattern & 0x02) drawFragmentedRect(x, y + t, t, h - 2*t, true, FRAGS, color, &offX[25], &offY[25]);
// Segment G (Middle) - Horizontal [Idx 30-34]
if (pattern & 0x01) drawFragmentedRect(x + t, y + h, w - 2*t, t, false, FRAGS, color, &offX[30], &offY[30]);
}
// (22)
// offX, offY: 4
void drawBigColon(int x, int y, int scale, uint32_t color, float* offX, float* offY) {
int h = 20 * scale;
// [Idx 0-1]
drawFragmentedRect(x, y + h/2, 2*scale, 2*scale, false, 2, color, &offX[0], &offY[0]);
// [Idx 2-3]
drawFragmentedRect(x, y + h + h/2, 2*scale, 2*scale, false, 2, color, &offX[2], &offY[2]);
}
//
// charW:
void drawTextMosaic(String text, int startX, int startY, uint32_t color, Canvas::eFontSize_t font, int charW, int startIdx) {
int cursorX = startX;
for (int i = 0; i < text.length(); i++) {
String ch = text.substring(i, i+1);
int pIdx = startIdx + i;
if (pIdx >= PARTICLE_COUNT) pIdx = PARTICLE_COUNT - 1; //
// autoClean=false,
k10.canvas->canvasText(ch, cursorX + (int)partOffX[pIdx], startY + (int)partOffY[pIdx], color, font, charW + 5, false);
cursorX += charW;
}
}
void setup() {
Serial.begin(115200);
k10.begin();
k10.initScreen(screen_dir);
k10.creatCanvas();
//
k10.setScreenBackground(0x000000);
delay(200);
// --- WiFi WiFiManager ---
WiFi.mode(WIFI_STA);
//
k10.canvas->canvasText("Connecting WiFi...", 30, SCREEN_H/2 - 20, 0xFFFFFF, k10.canvas->eCNAndENFont24, SCREEN_W, true);
// WiFiManager
{
WiFiManager wm;
// wm.setConfigPortalTimeout(180);
// false
bool ok = wm.autoConnect("K10-Clock-Setup");
if (!ok) {
//
k10.canvas->canvasText("WiFi Setup Failed", 30, SCREEN_H/2 + 10, 0xFF0000, k10.canvas->eCNAndENFont24, SCREEN_W, true);
}
}
// WiFiManager
k10.canvas->canvasRectangle(0, 0, 320, 240, 0x000000, 0x000000, true);
k10.canvas->canvasText("WiFi Connected!", 50, 100, 0x00FF00, k10.canvas->eCNAndENFont24, 300, true);
delay(1000);
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.google.com");
delay(200);
k10.rgb->brightness(9);
k10.rgb->write(-1, 0,0,0);
}
void loop() {
struct tm timeinfo;
bool timeReady = getLocalTime(&timeinfo);
float tempC = aht20.getData(AHT20::eAHT20TempC);
float hum = aht20.getData(AHT20::eAHT20HumiRH);
int als = k10.readALS();
int strength = k10.getStrength(); //
//
int rawX = k10.getAccelerometerX();
int rawY = k10.getAccelerometerY();
// 3()YXXY
// (+/-)/
float shakeDirX = rawY / 20.0f;
float shakeDirY = -rawX / 20.0f;
//
k10.canvas->canvasRectangle(0, 0, 320, 320, 0x000000, 0x000000, true);
// --- ---
// 1000 (1g)
//
// 1. < 50:
// 2. 50 <= < 800:
// 3. >= 800:
int diff = abs(strength - 1000);
// ()
for(int i=0; i<PARTICLE_COUNT; i++) {
if (diff >= 800) {
//
float accX = random(-150, 151) / 2.0f;
float accY = random(-150, 151) / 2.0f;
//
partVelX[i] += accX + shakeDirX;
partVelY[i] += accY + shakeDirY;
//
partVelX[i] *= 0.995f;
partVelY[i] *= 0.995f;
}
else if (diff >= 50) {
//
float accX = random(-60, 61) / 4.0f;
float accY = random(-60, 61) / 4.0f;
//
partVelX[i] += accX + (shakeDirX * 0.3f);
partVelY[i] += accY + (shakeDirY * 0.3f);
//
float k = 0.015f;
partVelX[i] += -k * partOffX[i];
partVelY[i] += -k * partOffY[i];
//
partVelX[i] *= 0.96f;
partVelY[i] *= 0.96f;
}
else {
//
float k = 0.35f; //
float forceX = -k * partOffX[i];
float forceY = -k * partOffY[i];
partVelX[i] += forceX;
partVelY[i] += forceY;
// ()
partVelX[i] *= 0.60f;
partVelY[i] *= 0.60f;
//
if (abs(partOffX[i]) < 1.0f && abs(partVelX[i]) < 0.5f) {
partOffX[i] = 0;
partVelX[i] = 0;
}
if (abs(partOffY[i]) < 1.0f && abs(partVelY[i]) < 0.5f) {
partOffY[i] = 0;
partVelY[i] = 0;
}
}
// +=
partOffX[i] += partVelX[i];
partOffY[i] += partVelY[i];
}
if (timeReady) {
// --- 1. (Offset Index 144+) ---
char dateBuf[32];
const char* wds[] = {"SUN","MON","TUE","WED","THU","FRI","SAT"};
snprintf(dateBuf, sizeof(dateBuf), "%04d-%02d-%02d %s",
timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday, wds[timeinfo.tm_wday]);
// Font24 14px
// Offset start: 144
drawTextMosaic(String(dateBuf), 55, 20, 0xAAAAAA, k10.canvas->eCNAndENFont24, 14, 144);
// --- 2. (Offset Index 0..143) ---
// : Digit(35) | Digit(35) | Colon(4) | Digit(35) | Digit(35)
int scale = 3;
int digitW = 12 * scale + 6;
int colonW = 4 * scale + 6;
int totalW = (4 * digitW) + colonW;
int startX = (SCREEN_W - totalW) / 2;
int startY = (SCREEN_H - (40 * scale)) / 2; //
int h1 = timeinfo.tm_hour / 10;
int h2 = timeinfo.tm_hour % 10;
int m1 = timeinfo.tm_min / 10;
int m2 = timeinfo.tm_min % 10;
uint32_t tColor = 0xFFFFFF; //
// Offset 0
drawBigDigit(startX, startY, h1, scale, tColor, &partOffX[0], &partOffY[0]);
// Offset 35
drawBigDigit(startX + digitW, startY, h2, scale, tColor, &partOffX[35], &partOffY[35]);
// Offset 70
drawBigColon(startX + digitW * 2, startY, scale, tColor, &partOffX[70], &partOffY[70]);
// Offset 74
drawBigDigit(startX + digitW * 2 + colonW, startY, m1, scale, tColor, &partOffX[74], &partOffY[74]);
// Offset 109
drawBigDigit(startX + digitW * 3 + colonW, startY, m2, scale, tColor, &partOffX[109], &partOffY[109]);
// --- 3. (Offset Index 164+) ---
int lblY = SCREEN_H - 55;
int valY = SCREEN_H - 35;
// : Label(50), Value(60)
int tempX = 50;
drawTextMosaic("TEMP", tempX, lblY, 0x888888, k10.canvas->eCNAndENFont16, 9, 164);
drawTextMosaic(String(tempC, 1) + "C", tempX - 10, valY, 0xFFB36B, k10.canvas->eCNAndENFont24, 14, 174);
// : Label(70), Value(80)
int humX = 220;
drawTextMosaic("HUM", humX, lblY, 0x888888, k10.canvas->eCNAndENFont16, 9, 184);
drawTextMosaic(String(hum, 0) + "%", humX, valY, 0x66CCFF, k10.canvas->eCNAndENFont24, 14, 194);
} else {
k10.canvas->canvasText("WIFI CONNECTING...", 60, SCREEN_H/2, 0xFFFFFF, k10.canvas->eCNAndENFont24, SCREEN_W, true);
}
//
if (als >= 0 && als < ALS_COVER_THRESHOLD) {
unsigned long ms = millis();
float phase = (ms % 1000) / 1000.0f;
float breath = 0.6f * (0.5f * (1.0f + sinf(2.0f * 3.1415926f * phase - 3.1415926f/2.0f))) + 0.2f;
float hue = fmod(ms / 10.0f, 360.0f);
uint8_t r,g,b;
hsv2rgb(hue, 1.0f, breath, r, g, b);
k10.rgb->brightness(9);
k10.rgb->write(-1, r, g, b);
} else {
k10.rgb->write(-1, 0, 0, 0);
}
k10.canvas->updateCanvas();
delay(30);
}
Comments