Coronameter
As Michigan gets it's first cases of COVID-19 and events, schools, and businesses close up, this global pandemic starts to feel a lot more real. To stay properly panicked, I decided to re-purpose my old temperature display from college as a dedicated screen showing what the score is.
Screen
Hardware
The hardware is nothing more than a ST7920 LCD wired to an ESP8266. The screen runs at 5V, so there is a logic level converter thrown in, too. This screen used to be a display for my indoor outdoor temperature thingy, is crudely soldered, and had no case. First order of business was to design and 3D print a small plastic enclosure for it. After wiring up a 5V wall adapter, the hardware is done.
Software
When it was a temperature display, all the fetching of data was done on the ESP8266 itself. For the new system, I decided to just make the display dump the contents of raw UDP packets. That way, I can do the hard work in an external program (like Python) and send it over to the screen when done. I did the same thing with the Winter Camp Mission timer setup with the Nixie Clocks, and a character VFD hooked to an 8266, and it worked very well.
The screen is driven using u8g2lib, and since the ST7920 doesn't have a built in text mode with this library, it was up to me to pick out a font and position the characters on the screen. U8g2lib will draw the characters graphically. I wound up with 21 columns and 7 rows, 147 characters total. On a screen this size, this makes for large and clearly readable text, even at a distance.
#include <Arduino.h> #include <U8g2lib.h> #include <ESP8266WiFi.h> #include <WiFiUdp.h> #include <ESP8266mDNS.h> #include <ArduinoOTA.h> const char* ssid = "ssidname"; // your network SSID (name) const char* pass = "password"; // your network password unsigned int localPort = 4212; WiFiUDP Udp; U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 12, /* data=*/ 13, /* CS=*/ 4, /* reset=*/ 14); char zbuffer[32]; char sbuf[148]; unsigned int millistimer=0; void setup(void) { u8g2.begin(); Serial.begin(74880); u8g2.setFont(u8g2_font_profont11_tr); u8g2.setFontRefHeightExtendedText(); u8g2.setDrawColor(1); u8g2.setFontPosTop(); u8g2.setFontDirection(0); sprintf(zbuffer, "Starting"); u8g2.drawStr(0, 0, zbuffer); u8g2.sendBuffer(); WiFi.mode(WIFI_STA); WiFi.softAPdisconnect (true); WiFi.begin(ssid, pass); while(WiFi.status() != WL_CONNECTED){ delay(1000); } Serial.println(WiFi.localIP()); u8g2.clearBuffer(); sprintf(zbuffer, "OK: %d.%d.%d.%d",WiFi.localIP()[0],WiFi.localIP()[1],WiFi.localIP()[2],WiFi.localIP()[3]); u8g2.drawStr(0, 0, zbuffer); u8g2.sendBuffer(); Udp.begin(localPort); ArduinoOTA.setHostname("graphomatic-udp"); ArduinoOTA.begin(); millistimer=millis(); } void loop(void) { ArduinoOTA.handle(); int packetSize = Udp.parsePacket(); if(packetSize){ Udp.read(sbuf, sizeof(sbuf)); u8g2.clearBuffer(); u8g2.setFont(u8g2_font_profont11_tr); u8g2.setFontRefHeightExtendedText(); u8g2.setDrawColor(1); u8g2.setFontPosTop(); u8g2.setFontDirection(0); byte x=0; byte y=0; byte c=0; while(sbuf[c]!=0&&c!=255){ if(sbuf[c]>31&&sbuf[c]<127){ u8g2.drawGlyph(x*6+1,y*9-1,sbuf[c]); } if(sbuf[c]==10){y++; x=255;} x++; if(x==21){x=0; y++;} c++; } u8g2.sendBuffer(); } }