103 lines
3.0 KiB
C++
103 lines
3.0 KiB
C++
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_ST7735.h>
|
|
#include <SPI.h>
|
|
#include "config.h"
|
|
#include "display_ui.h"
|
|
|
|
// Non-static so displayRender() can reference it via extern.
|
|
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
|
|
|
|
void displayBegin() {
|
|
pinMode(TFT_BLK, OUTPUT);
|
|
digitalWrite(TFT_BLK, HIGH); // backlight on
|
|
tft.initR(INITR_MINI160x80); // 0.96" ST7735S
|
|
tft.invertDisplay(false); // this panel: no inversion
|
|
tft.setRotation(3); // landscape, 160 wide x 80 tall
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
}
|
|
|
|
void displaySplash(const char* line1, const char* line2) {
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.setTextSize(2);
|
|
tft.setCursor(4, 20);
|
|
tft.print(line1);
|
|
tft.setTextSize(1);
|
|
tft.setCursor(4, 50);
|
|
tft.print(line2);
|
|
}
|
|
|
|
// Simple 34x34 weather icon at (x, y).
|
|
static void drawIcon(WxCategory c, int x, int y) {
|
|
uint16_t sun = ST77XX_YELLOW;
|
|
uint16_t cloud = ST77XX_WHITE;
|
|
uint16_t rain = ST77XX_CYAN;
|
|
switch (c) {
|
|
case WX_FINE:
|
|
tft.fillCircle(x + 17, y + 17, 11, sun);
|
|
break;
|
|
case WX_FAIR:
|
|
tft.fillCircle(x + 12, y + 12, 8, sun);
|
|
tft.fillRoundRect(x + 8, y + 18, 24, 12, 6, cloud);
|
|
break;
|
|
case WX_CHANGEABLE:
|
|
tft.fillRoundRect(x + 4, y + 12, 26, 14, 7, cloud);
|
|
break;
|
|
case WX_RAIN:
|
|
tft.fillRoundRect(x + 4, y + 8, 26, 14, 7, cloud);
|
|
for (int i = 0; i < 3; i++)
|
|
tft.drawFastVLine(x + 9 + i * 8, y + 24, 8, rain);
|
|
break;
|
|
case WX_STORM:
|
|
tft.fillRoundRect(x + 4, y + 8, 26, 14, 7, cloud);
|
|
tft.fillTriangle(x + 16, y + 22, x + 12, y + 32, x + 20, y + 30, ST77XX_YELLOW);
|
|
break;
|
|
default:
|
|
tft.drawRect(x + 4, y + 10, 26, 18, cloud); // unknown / collecting
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Layout for landscape 160 x 80.
|
|
void displayRender(const AppState& s) {
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
char buf[24];
|
|
|
|
// Time (large), top-left
|
|
snprintf(buf, sizeof(buf), "%02u:%02u", s.now.hour, s.now.minute);
|
|
tft.setTextSize(2);
|
|
tft.setCursor(4, 4);
|
|
tft.print(buf);
|
|
|
|
// Icon, top-right
|
|
drawIcon(s.haveTrend ? s.forecast.category : WX_UNKNOWN, 120, 4);
|
|
|
|
// Date
|
|
snprintf(buf, sizeof(buf), "%04u-%02u-%02u", s.now.year, s.now.month, s.now.day);
|
|
tft.setTextSize(1);
|
|
tft.setCursor(4, 26);
|
|
tft.print(buf);
|
|
|
|
// Pressure + trend arrow
|
|
snprintf(buf, sizeof(buf), "%.0f hPa", s.mslHpa);
|
|
tft.setCursor(4, 40);
|
|
tft.print(buf);
|
|
const char* arrow = (s.trend == TREND_RISING) ? "^" : (s.trend == TREND_FALLING ? "v" : "=");
|
|
tft.setCursor(96, 40);
|
|
tft.setTextColor(ST77XX_CYAN);
|
|
tft.print(arrow);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
|
|
// Temperature
|
|
snprintf(buf, sizeof(buf), "%.1f C", s.tempC);
|
|
tft.setCursor(4, 52);
|
|
tft.print(buf);
|
|
|
|
// Forecast short label (full width, bottom row)
|
|
tft.setTextColor(ST77XX_YELLOW);
|
|
tft.setCursor(4, 66);
|
|
tft.print(s.haveTrend ? categoryShort(s.forecast.category) : "Collecting...");
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
}
|