feat: testowanie nastrojów za pomocą rest api
This commit is contained in:
+112
-22
@@ -99,7 +99,7 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
u8g2.drawFilledEllipse(cx, cy, EYE_RX, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 5) {
|
||||
u8g2.setDrawColor(0);
|
||||
int8_t gx = (int8_t)cx + 3 + pdx / 3;
|
||||
int8_t gx = (int8_t)cx - 3 + pdx / 3;
|
||||
int8_t gy = (int8_t)cy - 3 + pdy / 3;
|
||||
u8g2.drawDisc((uint8_t)gx, (uint8_t)gy, 2);
|
||||
u8g2.setDrawColor(1);
|
||||
@@ -117,20 +117,28 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
u8g2.drawFilledEllipse(cx, cy, r, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 6) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx + 5, cy - 5, 3);
|
||||
u8g2.drawDisc(cx - 5, cy - 5, 3);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOOD_ANGRY: {
|
||||
const uint8_t w = EYE_RX + 3;
|
||||
const uint8_t h = min(effRy, (uint8_t)6);
|
||||
for (int8_t row = 0; row <= (int8_t)(h * 2); row++) {
|
||||
int8_t y = (int8_t)cy - (int8_t)h + row;
|
||||
uint8_t lineW = (row < (int8_t)h) ? w - (uint8_t)((int8_t)h - row) : w;
|
||||
if (lineW < 2) lineW = 2;
|
||||
uint8_t x = isLeft ? cx - w : (uint8_t)(cx + w - lineW);
|
||||
u8g2.drawHLine(x, (uint8_t)y, lineW);
|
||||
// Oko — dolna połowa elipsy (jak sad)
|
||||
uint8_t ry = min(effRy, EYE_RX);
|
||||
u8g2.drawFilledEllipse(cx, cy - 2, EYE_RX, ry,
|
||||
U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_LOWER_RIGHT);
|
||||
// Źrenica
|
||||
if (ry >= 4) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx - 3, cy + 2, 2);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
// Brew ściągnięta do środka (V kształt nad okiem)
|
||||
uint8_t browY = cy - ry - 3;
|
||||
if (isLeft) {
|
||||
u8g2.drawLine(cx - EYE_RX + 2, browY, cx + EYE_RX - 2, browY + 3);
|
||||
} else {
|
||||
u8g2.drawLine(cx - EYE_RX + 2, browY + 3, cx + EYE_RX - 2, browY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -138,6 +146,19 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
uint8_t ry = min(effRy, EYE_RX);
|
||||
u8g2.drawFilledEllipse(cx, cy - 2, EYE_RX, ry,
|
||||
U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_LOWER_RIGHT);
|
||||
// Źrenica
|
||||
if (ry >= 4) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx - 3, cy + 2, 2);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
// Brew opadająca na zewnątrz (smutna — odwrotnie niż angry)
|
||||
uint8_t browY = cy - ry - 3;
|
||||
if (isLeft) {
|
||||
u8g2.drawLine(cx - EYE_RX + 2, browY + 3, cx + EYE_RX - 2, browY);
|
||||
} else {
|
||||
u8g2.drawLine(cx - EYE_RX + 2, browY, cx + EYE_RX - 2, browY + 3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOOD_EXCITED: {
|
||||
@@ -145,10 +166,10 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
u8g2.drawFilledEllipse(cx, cy, EYE_RX, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 5) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawLine(cx - 5, cy - 5, cx + 5, cy + 5);
|
||||
u8g2.drawLine(cx + 5, cy - 5, cx - 5, cy + 5);
|
||||
u8g2.drawLine(cx - 7, cy - 7, cx + 7, cy + 7);
|
||||
u8g2.drawLine(cx + 7, cy - 7, cx - 7, cy + 7);
|
||||
u8g2.setDrawColor(1);
|
||||
u8g2.drawDisc(cx, cy, 2);
|
||||
u8g2.drawDisc(cx, cy, 5);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -167,8 +188,8 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
u8g2.drawFilledEllipse(cx, cy, EYE_RX, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 5) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx + 4, cy - 4, 3);
|
||||
u8g2.drawDisc(cx - 3, cy + 3, 1);
|
||||
u8g2.drawDisc(cx - 4, cy - 4, 3);
|
||||
u8g2.drawDisc(cx + 3, cy + 3, 1);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
break;
|
||||
@@ -178,8 +199,19 @@ static void drawEye(uint8_t cx, uint8_t cy, uint8_t effRy,
|
||||
u8g2.drawFilledEllipse(cx, cy, EYE_RX, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 5) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx - 4, cy - 2, 2);
|
||||
u8g2.drawDisc(cx + 4, cy + 2, 2);
|
||||
u8g2.drawDisc(cx + 4, cy - 2, 2);
|
||||
u8g2.drawDisc(cx - 4, cy + 2, 2);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MOOD_WINK_L:
|
||||
case MOOD_WINK_R: {
|
||||
uint8_t ry = min(effRy, EYE_RX);
|
||||
u8g2.drawFilledEllipse(cx, cy, EYE_RX, ry, U8G2_DRAW_ALL);
|
||||
if (ry >= 5) {
|
||||
u8g2.setDrawColor(0);
|
||||
u8g2.drawDisc(cx - 3, cy - 3, 2);
|
||||
u8g2.setDrawColor(1);
|
||||
}
|
||||
break;
|
||||
@@ -968,10 +1000,41 @@ static String buildHtml()
|
||||
"});"
|
||||
"</script>"
|
||||
|
||||
"<hr style='border-color:#222;margin:16px 0'>"
|
||||
|
||||
// ── Mood test panel ───────────────────────────────────────────────
|
||||
"<h3 style='color:#4f4;margin:0 0 10px'>Test nastroju</h3>"
|
||||
"<div style='margin-bottom:8px;display:flex;flex-wrap:wrap;gap:6px'>"
|
||||
"<button type='button' onclick='tm(0)' style='background:#333'>Normal</button>"
|
||||
"<button type='button' onclick='tm(1)' style='background:#185'>Happy</button>"
|
||||
"<button type='button' onclick='tm(2)' style='background:#226'>Sleepy</button>"
|
||||
"<button type='button' onclick='tm(3)' style='background:#550'>Surprised</button>"
|
||||
"<button type='button' onclick='tm(4)' style='background:#622'>Angry</button>"
|
||||
"<button type='button' onclick='tm(5)' style='background:#246'>Sad</button>"
|
||||
"<button type='button' onclick='tm(6)' style='background:#185'>Excited</button>"
|
||||
"<button type='button' onclick='tm(7)' style='background:#444'>Wink L</button>"
|
||||
"<button type='button' onclick='tm(8)' style='background:#444'>Wink R</button>"
|
||||
"<button type='button' onclick='tm(9)' style='background:#532'>Hungry</button>"
|
||||
"<button type='button' onclick='tm(10)' style='background:#245'>Playful</button>"
|
||||
"<button type='button' onclick='tm(11)' style='background:#432'>Dirty</button>"
|
||||
"</div>"
|
||||
"<div id='mmsg' style='color:#4f4;font-size:12px;height:16px'></div>"
|
||||
"<script>"
|
||||
"function tm(m){"
|
||||
"fetch('/api/mood/test?m='+m,{method:'POST'})"
|
||||
".then(r=>r.json()).then(d=>{"
|
||||
"var el=document.getElementById('mmsg');"
|
||||
"el.textContent=d.msg||'OK';"
|
||||
"setTimeout(function(){el.textContent='';},3000);"
|
||||
"});"
|
||||
"}"
|
||||
"</script>"
|
||||
|
||||
"<hr style='border-color:#222;margin:16px 0'>"
|
||||
"<p style='color:#555;font-size:11px'>GET /api/config POST /api/config (JSON)"
|
||||
" | GET /api/tama POST /api/tama/{feed,play,clean}"
|
||||
" | GET /api/weather POST /weather/save</p>"
|
||||
" | GET /api/weather POST /weather/save"
|
||||
" | POST /api/mood/test?m={0-11}</p>"
|
||||
"</body></html>";
|
||||
return html;
|
||||
}
|
||||
@@ -1104,6 +1167,19 @@ void setupHttpServer()
|
||||
req->send(200, "application/json", buf);
|
||||
});
|
||||
|
||||
// POST /api/mood/test?m=N — ustaw nastoj testowy na 10s
|
||||
httpServer.on("/api/mood/test", HTTP_POST, [](AsyncWebServerRequest *req) {
|
||||
uint32_t now = millis();
|
||||
uint8_t m = 0;
|
||||
if (req->hasParam("m"))
|
||||
m = (uint8_t)constrain(req->getParam("m")->value().toInt(), 0, 11);
|
||||
setBuddyMood(buddy, (Mood)m, now, 10000);
|
||||
Serial.printf("[Web] Mood test: %s (%d)\n", MOOD_LABELS[m], m);
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf), "{\"ok\":true,\"msg\":\"Nastoj: %s (10s)\"}", MOOD_LABELS[m]);
|
||||
req->send(200, "application/json", buf);
|
||||
});
|
||||
|
||||
// GET /api/weather — current weather data + config
|
||||
httpServer.on("/api/weather", HTTP_GET, [](AsyncWebServerRequest *req) {
|
||||
char buf[180];
|
||||
@@ -1271,10 +1347,24 @@ void loop()
|
||||
setDim(night && idle);
|
||||
}
|
||||
|
||||
static uint32_t lastWifi = 0;
|
||||
if (now - lastWifi > 30000) {
|
||||
lastWifi = now;
|
||||
if (WiFi.status() != WL_CONNECTED) WiFi.reconnect();
|
||||
// WiFi watchdog: próba reconnect co 30 s, restart po 5 min bez połączenia
|
||||
static uint32_t lastWifiCheck = 0;
|
||||
static uint32_t wifiDownSince = 0; // 0 = połączony lub nie śledzony
|
||||
if (now - lastWifiCheck > 30000) {
|
||||
lastWifiCheck = now;
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
wifiDownSince = 0;
|
||||
} else {
|
||||
if (wifiDownSince == 0) wifiDownSince = now ? now : 1;
|
||||
uint32_t downMs = now - wifiDownSince;
|
||||
Serial.printf("[WiFi] Brak polaczenia od %lu s, proba reconnect...\n", downMs / 1000);
|
||||
WiFi.reconnect();
|
||||
if (downMs >= 300000UL) {
|
||||
Serial.println("[WiFi] Brak WiFi > 5 min — restart");
|
||||
delay(200);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Weather: show face periodically, re-fetch at most every 60 s
|
||||
|
||||
Reference in New Issue
Block a user