#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include "DHTesp.h"
#include <WebServer.h>
// ================== TFT ==================
#define PIN_TFT_DC 2
#define PIN_TFT_CS 15
Adafruit_ILI9341 screen(PIN_TFT_CS, PIN_TFT_DC);
// ================== DHT ==================
#define PIN_DHT 16
DHTesp climate;
// ================== WiFi ==================
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASSWORD = "";
// ================== Web ==================
WebServer http(80);
// ================== Data Buffers ==================
const uint8_t HISTORY_LEN = 10;
int speedLog[HISTORY_LEN];
float tempLog[HISTORY_LEN];
int limitLog[HISTORY_LEN];
uint8_t logIndex = 0;
// ================== Position ==================
float latPos = 50.4501; // Київ
float lonPos = 30.5234;
float headingAngle = 0.0; // рад
// ------------------ Random Generators ------------------
int randomSpeed() { return random(0, 181); } // 0–180 км/ч
int randomLimit() { return random(40, 121); } // 40–120 км/ч
void shiftCoordinates(int spd) {
float moveStep = spd * 0.00001f;
headingAngle += random(-5, 6) / 1000.0f;
latPos += moveStep * cos(headingAngle);
lonPos += moveStep * sin(headingAngle);
}
// ------------------ HTML ------------------
void pageRoot() {
String html;
html.reserve(2000);
html += "<!DOCTYPE html><html><head><meta charset='utf-8'><title>Car Stats</title>";
html += "<script src='https://cdn.jsdelivr.net/npm/chart.js'></script></head><body>";
html += "<h2>Car Computer</h2>";
html += "<p>Lat: " + String(latPos,6) + " | Lon: " + String(lonPos,6) + "</p>";
html += "<p>Temp: " + String(tempLog[(logIndex+HISTORY_LEN-1)%HISTORY_LEN],1) + " °C</p>";
html += "<p>Recommended: " + String(limitLog[(logIndex+HISTORY_LEN-1)%HISTORY_LEN]) + " km/h</p>";
html += "<canvas id='chart' width='600' height='300'></canvas><script>";
// labels
html += "const labels=[";
for(uint8_t i=0;i<HISTORY_LEN;i++){
html += "'" + String(i+1) + "'";
if(i<HISTORY_LEN-1) html += ",";
}
html += "];";
// dataset speed
html += "const data={labels:labels,datasets:[";
html += "{label:'Speed',borderColor:'blue',fill:false,data:[";
for(uint8_t i=0;i<HISTORY_LEN;i++){
html += String(speedLog[i]);
if(i<HISTORY_LEN-1) html += ",";
}
html += "]},";
// dataset temp
html += "{label:'Temp',borderColor:'orange',fill:false,data:[";
for(uint8_t i=0;i<HISTORY_LEN;i++){
html += String(tempLog[i],1);
if(i<HISTORY_LEN-1) html += ",";
}
html += "]},";
// dataset recommended
html += "{label:'Limit',borderColor:'green',fill:false,data:[";
for(uint8_t i=0;i<HISTORY_LEN;i++){
html += String(limitLog[i]);
if(i<HISTORY_LEN-1) html += ",";
}
html += "]}]};";
html += "new Chart(document.getElementById('chart'),{type:'line',data:data});";
html += "</script></body></html>";
http.send(200, "text/html", html);
}
// ------------------ Setup ------------------
void setup() {
Serial.begin(115200);
randomSeed(analogRead(0));
screen.begin();
screen.setRotation(1);
screen.fillScreen(ILI9341_BLACK);
screen.setTextColor(ILI9341_WHITE);
screen.setTextSize(2);
screen.setCursor(0,0);
screen.println("WiFi connecting...");
climate.setup(PIN_DHT, DHTesp::DHT22);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
unsigned long t0 = millis();
while(WiFi.status()!=WL_CONNECTED && millis()-t0<20000){
delay(500);
Serial.print(".");
}
screen.setCursor(0,30);
if(WiFi.status()==WL_CONNECTED){
screen.setTextColor(ILI9341_GREEN);
screen.println("WiFi OK");
} else {
screen.setTextColor(ILI9341_RED);
screen.println("WiFi FAIL");
}
http.on("/", pageRoot);
http.begin();
}
// ------------------ Loop ------------------
const int ALERT_DIFF = 15;
void loop() {
int speed = randomSpeed();
int limit = randomLimit();
TempAndHumidity tData = climate.getTempAndHumidity();
float t = isnan(tData.temperature) ? tempLog[(logIndex+HISTORY_LEN-1)%HISTORY_LEN] : tData.temperature;
float h = isnan(tData.humidity) ? 0 : tData.humidity;
shiftCoordinates(speed);
speedLog[logIndex] = speed;
tempLog[logIndex] = t;
limitLog[logIndex] = limit;
logIndex = (logIndex + 1) % HISTORY_LEN;
// ---------- TFT ----------
screen.fillScreen(ILI9341_BLACK);
screen.setCursor(0,0);
screen.setTextColor(ILI9341_CYAN); screen.println("Car Monitor");
screen.setTextColor(ILI9341_GREEN); screen.println("Limit: " + String(limit) + " km/h");
screen.setTextColor(ILI9341_MAGENTA);screen.println("Speed: " + String(speed) + " km/h");
screen.setTextColor(ILI9341_WHITE);
screen.println("Temp: " + String(t,1) + " C");
screen.println("Hum : " + String(h,1) + " %");
screen.println("Lat : " + String(latPos,6));
screen.println("Lon : " + String(lonPos,6));
if(limit > 0 && speed > limit + ALERT_DIFF){
Serial.println("!!! ALERT: Slow Down !!!");
screen.setTextColor(ILI9341_RED);
screen.println("*** SLOW DOWN ***");
}
http.handleClient();
delay(1000);
}