#include <WiFi.h>
#include <time.h>
#include <vector>
#include <algorithm>
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
/* ================= WIFI ================= */
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
/* ================= TIME ================= */
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // adjust for your timezone
const int daylightOffset_sec = 3600;
int lastBrightness = 120; // initial brightness
unsigned long lastBusUpdate = 0; // tracks last bus schedule update
const unsigned long BUS_UPDATE_INTERVAL = 10000;
/* ================= MATRIX ================= */
#define PANEL_WIDTH 64
#define PANEL_HEIGHT 64 // Panel height of 64 will required PIN_E to be defined.
#define PANELS_NUMBER 2
#define PIN_E 21
#define PIN_D 2
#define POT_PIN 32 // POTENTIOMETER PIN
#define PANE_WIDTH PANEL_WIDTH * PANELS_NUMBER
#define PANE_HEIGHT PANEL_HEIGHT
MatrixPanel_I2S_DMA* dma_display;
/* ================= ROUTE DEFINITIONS ================= */
struct BusRoute {
const char* route;
const char* destination;
};
/* PUT IN YOUR BUS ROUTES*/
BusRoute routes[] = {
{"14", "Hubland"},
{"14", "Bahnhof"},
{"114", "UniSport"},
{"114", "Bahnhof"},
{"214", "Bibliotk"},
{"214", "Bahnhof"},
{"29", "TGZ"},
{"29", "Bahnhof"}
};
const int ROUTE_COUNT = sizeof(routes) / sizeof(routes[0]);
/* ================= BUS SCHEDULE TABLES ================= */
/* ---- REPLACE TIMES WITH REAL DATA ---- */
/* 14 → Am Hubland */
const char* bus14_hub_weekday[] = {
"04:43",
"05:12","05:40","05:53"
};
const char* bus14_hub_saturday[] = {
"00:23",
"01:23"
};
const char* bus14_hub_sunday[] = {
"00:23",
"01:23"
};
/* 14 → Hauptbahnhof */
const char* bus14_hbf_weekday[] = {
"05:03","05:33",
"06:07","06:19","06:45"
};
const char* bus14_hbf_saturday[] = {
"05:59",
"06:29","06:59"
};
const char* bus14_hbf_sunday[] = {
"07:29",
"08:29"
};
/* 114 → Am Hubland */
const char* bus114_hub_weekday[] = {
"07:37","07:47","07:57",
"08:07","08:27","08:47",
"09:07","09:27","09:47"
};
const char* bus114_hub_saturday[] = {};
const char* bus114_hub_sunday[] = {};
/* 114 → Hauptbahnhof */
const char* bus114_hbf_weekday[] = {
"07:33",
"08:16","08:36","08:56",
"09:16","09:36","09:56",
"10:16","10:36","10:56"
};
const char* bus114_hbf_saturday[] = {};
const char* bus114_hbf_sunday[] = {};
/* 214 → Am Hubland */
const char* bus214_hub_weekday[] = {
"07:20","07:37"
};
const char* bus214_hub_saturday[] = {};
const char* bus214_hub_sunday[] = {};
/* 214 → Hauptbahnhof */
const char* bus214_hbf_weekday[] = {
"07:17","07:33",
"08:04","08:22"
};
const char* bus214_hbf_saturday[] = {};
const char* bus214_hbf_sunday[] = {};
/* 29 → Am Hubland */
const char* bus29_hub_weekday[] = {
"06:17","06:47",
"07:17","07:32"
};
const char* bus29_hub_saturday[] = {
"06:31",
"07:31",
"08:31",
"09:01"
};
const char* bus29_hub_sunday[] = {
"06:31",
"07:31",
"08:31"
};
/* 29 → Hauptbahnhof */
const char* bus29_hbf_weekday[] = {
"06:12","06:42",
"07:07","07:22","07:37","07:52",
"08:07","08:22","08:52",
"09:22","09:52"
};
const char* bus29_hbf_saturday[] = {};
const char* bus29_hbf_sunday[] = {};
/* ================= SCHEDULE REGISTRY ================= */
struct BusSchedule {
const char** weekday;
int weekdayCount;
const char** saturday;
int saturdayCount;
const char** sunday;
int sundayCount;
};
BusSchedule schedules[] = {
{bus14_hub_weekday, sizeof(bus14_hub_weekday)/sizeof(char*),
bus14_hub_saturday, sizeof(bus14_hub_saturday)/sizeof(char*),
bus14_hub_sunday, sizeof(bus14_hub_sunday)/sizeof(char*)},
{bus14_hbf_weekday, sizeof(bus14_hbf_weekday)/sizeof(char*),
bus14_hbf_saturday, sizeof(bus14_hbf_saturday)/sizeof(char*),
bus14_hbf_sunday, sizeof(bus14_hbf_sunday)/sizeof(char*)},
{bus114_hub_weekday, sizeof(bus114_hub_weekday)/sizeof(char*),
bus114_hub_saturday, sizeof(bus114_hub_saturday)/sizeof(char*),
bus114_hub_sunday, sizeof(bus114_hub_sunday)/sizeof(char*)},
{bus114_hbf_weekday, sizeof(bus114_hbf_weekday)/sizeof(char*),
bus114_hbf_saturday, sizeof(bus114_hbf_saturday)/sizeof(char*),
bus114_hbf_sunday, sizeof(bus114_hbf_sunday)/sizeof(char*)},
{bus214_hub_weekday, sizeof(bus214_hub_weekday)/sizeof(char*),
bus214_hub_saturday, sizeof(bus214_hub_saturday)/sizeof(char*),
bus214_hub_sunday, sizeof(bus214_hub_sunday)/sizeof(char*)},
{bus214_hbf_weekday, sizeof(bus214_hbf_weekday)/sizeof(char*),
bus214_hbf_saturday, sizeof(bus214_hbf_saturday)/sizeof(char*),
bus214_hbf_sunday, sizeof(bus214_hbf_sunday)/sizeof(char*)},
{bus29_hub_weekday, sizeof(bus29_hub_weekday)/sizeof(char*),
bus29_hub_saturday, sizeof(bus29_hub_saturday)/sizeof(char*),
bus29_hub_sunday, sizeof(bus29_hub_sunday)/sizeof(char*)},
{bus29_hbf_weekday, sizeof(bus29_hbf_weekday)/sizeof(char*),
bus29_hbf_saturday, sizeof(bus29_hbf_saturday)/sizeof(char*),
bus29_hbf_sunday, sizeof(bus29_hbf_sunday)/sizeof(char*)}
};
const int SCHEDULE_COUNT = sizeof(schedules) / sizeof(schedules[0]);
/* ================= UPCOMING STRUCT ================= */
struct UpcomingBus {
int minutes;
int index;
};
/* ================= UTILS ================= */
int timeToMinutes(const char* t) {
return (t[0]-'0')*600 + (t[1]-'0')*60 +
(t[3]-'0')*10 + (t[4]-'0');
}
/* ================= DISPLAY ================= */
void drawBuses(const std::vector<UpcomingBus>& list) {
dma_display->clearScreen();
dma_display->setTextSize(1);
const int startX = 6;
const int startY = 5;
const int rowHeight = 12; // 8px font + 4px gap
for (int i = 0; i < list.size() && i < 5; i++) {
const BusRoute& r = routes[list[i].index];
int y = startY + i * rowHeight;
dma_display->setCursor(startX, y);
/* BUS NUMBER — GREEN */
dma_display->setTextColor(dma_display->color565(0, 255, 0));
dma_display->printf("%-3s ", r.route);
/* DESTINATION — WHITE */
dma_display->setTextColor(dma_display->color565(255, 255, 255));
dma_display->printf("%-8s ", r.destination);
/* TIME — RED */
dma_display->setTextColor(dma_display->color565(0, 255, 0));
dma_display->printf("%2d min", list[i].minutes);
}
}
/* ================= SETUP ================= */
void setup() {
Serial.begin(115200);
HUB75_I2S_CFG mxconfig;
mxconfig.mx_height = PANEL_HEIGHT; // we have 64 pix heigh panels
mxconfig.chain_length = PANELS_NUMBER; // we have 2 panels chained
mxconfig.gpio.e = PIN_E;
mxconfig.gpio.d = PIN_D;
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
dma_display->begin();
dma_display->setBrightness8(120);
analogReadResolution(12); // 0–4095
analogSetPinAttenuation(POT_PIN, ADC_11db);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}
/* ================= LOOP ================= */
void loop() {
int raw = analogRead(POT_PIN); // read ADC
int brightness = map(raw, 0, 4095, 120, 0); // map to 120–0
brightness = constrain(brightness, 0, 140);
// only update if the difference is bigger than 200
if (abs(brightness - lastBrightness) > 15) {
dma_display->setBrightness8(brightness);
lastBrightness = brightness;
}
// -----------------------------
// Non-blocking bus update
// -----------------------------
unsigned long now = millis();
if (now - lastBusUpdate >= BUS_UPDATE_INTERVAL) {
lastBusUpdate = now;
// get time
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return;
int nowMin = timeinfo.tm_hour * 60 + timeinfo.tm_min;
int wday = timeinfo.tm_wday; // 0=Sunday
std::vector<UpcomingBus> upcoming;
// iterate schedules
for (int i = 0; i < SCHEDULE_COUNT; i++) {
const char** times;
int count;
if (wday == 0) {
times = schedules[i].sunday;
count = schedules[i].sundayCount;
} else if (wday == 6) {
times = schedules[i].saturday;
count = schedules[i].saturdayCount;
} else {
times = schedules[i].weekday;
count = schedules[i].weekdayCount;
}
for (int t = 0; t < count; t++) {
int busMin = timeToMinutes(times[t]);
if (busMin >= nowMin) {
upcoming.push_back({busMin - nowMin, i});
}
}
}
// sort and draw
std::sort(upcoming.begin(), upcoming.end(),
[](const UpcomingBus& a, const UpcomingBus& b) {
return a.minutes < b.minutes;
});
drawBuses(upcoming);
}
// -----------------------------
// ️Small delay to prevent CPU hogging
// -----------------------------
delay(10); // 10 ms is enough; brightness updates continuously
}
Comments