Implement JSON transfer and marquee for long directions

This commit is contained in:
Paul Brinkmeier 2024-07-19 05:25:14 +02:00
parent 8a2eccd9f9
commit 586a77dd2f
2 changed files with 76 additions and 35 deletions

View File

@ -8,5 +8,6 @@
- [x] Create container - [x] Create container
- [x] Write ESP8266 client - [x] Write ESP8266 client
- [ ] Make port configurable - [ ] Make port configurable
- [ ] Transfer using JSON - [x] Transfer using JSON
- [x] Correctly implement basic auth - [x] Correctly implement basic auth
- [ ] Use unidecode to replace non-ascii stuff in the backend

View File

@ -1,4 +1,4 @@
// Screen libraries etc. #include <ArduinoJson.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <SPI.h> #include <SPI.h>
#include <Wire.h> #include <Wire.h>
@ -33,6 +33,7 @@ enum {
} state = CONNECTING; } state = CONNECTING;
int frame = 0; int frame = 0;
int buttonPushed = false; int buttonPushed = false;
JsonDocument departures;
void ICACHE_RAM_ATTR onButtonFalling() { void ICACHE_RAM_ATTR onButtonFalling() {
buttonPushed = true; buttonPushed = true;
@ -54,7 +55,7 @@ void setup() {
pinMode(BUTTON_PIN, INPUT_PULLUP); pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(BUTTON_PIN, onButtonFalling, FALLING); attachInterrupt(BUTTON_PIN, onButtonFalling, FALLING);
display.setTextColor(SSD1306_WHITE); display.setTextColor(SSD1306_INVERSE);
display.setTextSize(1); display.setTextSize(1);
display.setCursor(0, 0); display.setCursor(0, 0);
display.printf("Connecting to\n%s\n", WIFI_SSID); display.printf("Connecting to\n%s\n", WIFI_SSID);
@ -66,11 +67,39 @@ void setup() {
*/ */
} }
void drawSpinner (int frame) { void drawSpinner(int frame) {
display.fillRect(120, 56, spinny_dims[0], spinny_dims[1], SSD1306_BLACK); display.fillRect(120, 56, spinny_dims[0], spinny_dims[1], SSD1306_BLACK);
display.drawBitmap(120, 56, spinny[frame % spinny_dims[2]], spinny_dims[0], spinny_dims[1], SSD1306_WHITE); display.drawBitmap(120, 56, spinny[frame % spinny_dims[2]], spinny_dims[0], spinny_dims[1], SSD1306_WHITE);
} }
// TODO: Error handling
String fetchDepartures() {
std::unique_ptr<BearSSL::WiFiClientSecure> https(new BearSSL::WiFiClientSecure);
https->setInsecure();
HTTPClient client;
if (!client.begin(*https, "vrnp.beany.club", 443, "/departures?stop_id=de:08221:1225&platform=A")) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("begin failed");
display.display();
for (;;);
}
client.addHeader("Authorization", AUTH_TOKEN);
client.addHeader("Accept", "application/json");
int statusCode = client.GET();
if (statusCode != 200) {
display.clearDisplay();
display.setCursor(0, 0);
display.printf("http non-ok: %d\n", statusCode);
display.display();
for (;;);
}
return client.getString();
}
void loop() { void loop() {
switch (state) { switch (state) {
case CONNECTING: { case CONNECTING: {
@ -82,40 +111,16 @@ void loop() {
} }
display.clearDisplay(); display.clearDisplay();
display.setCursor(0, 0); display.fillRect(0, 56, 128, 8, SSD1306_INVERSE);
display.print("Connected!\nRequesting departures"); display.setCursor(0, 56);
display.print("requesting departures");
display.display(); display.display();
std::unique_ptr<BearSSL::WiFiClientSecure> https(new BearSSL::WiFiClientSecure); String departuresRaw = fetchDepartures();
https->setInsecure(); deserializeJson(departures, departuresRaw);
HTTPClient client;
if (!client.begin(*https, "vrnp.beany.club", 443, "/departures?stop_id=de:08221:1225&platform=A")) {
display.clearDisplay();
display.setCursor(0, 0);
display.print("begin failed");
display.display();
for (;;);
return;
}
client.addHeader("Authorization", AUTH_TOKEN);
int statusCode = client.GET();
if (statusCode != 200) {
display.clearDisplay();
display.setCursor(0, 0);
display.printf("http non-ok: %d\n", statusCode);
display.display();
for (;;);
return;
}
display.clearDisplay();
display.setCursor(0, 0);
display.print(client.getString());
display.display();
state = SHOWING_DEPARTURES; state = SHOWING_DEPARTURES;
delay(FRAME_DELAY); frame = 0;
return; return;
} }
@ -125,13 +130,48 @@ void loop() {
return; return;
} }
/*
if (buttonPushed) { if (buttonPushed) {
buttonPushed = false; buttonPushed = false;
delay(FRAME_DELAY); delay(FRAME_DELAY);
return; return;
} }
*/
// Marquee effect for direction strings longer than 11 characters
// Neither particularly efficient nor legible
// (This could use some love)
int availableWidth = 11;
display.clearDisplay();
display.setCursor(0, 0);
for (JsonVariant departure : departures["departures"].as<JsonArray>()) {
const char *directionStr = departure["direction"].as<const char *>();
char buf[128] = {0};
const char *dirStart;
if (strlen(directionStr) <= availableWidth || (strlen(directionStr) + 3 + availableWidth) > 127) {
dirStart = directionStr;
} else {
memcpy(buf, directionStr, strlen(directionStr));
memcpy(buf + strlen(directionStr), " ", 3);
memcpy(buf + strlen(directionStr) + 3, directionStr, availableWidth);
buf[strlen(directionStr) + 3 + availableWidth] = '\0';
dirStart = buf + frame % (strlen(directionStr) + 3);
}
display.printf("%2s %-11.11s %6s\n",
departure["symbol"].as<const char*>(),
dirStart,
departure["leaving"].as<const char*>()
);
}
display.display();
delay(FRAME_DELAY); frame++;
delay(500);
return; return;
} }
} }