forked from wled/WLED
-
-
Notifications
You must be signed in to change notification settings - Fork 133
Expand file tree
/
Copy pathST7789_display.h
More file actions
406 lines (355 loc) · 14 KB
/
ST7789_display.h
File metadata and controls
406 lines (355 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
// Credits to @mrVanboy, @gwaland and my dearest friend @westward
// Also for @spiff72 for usermod TTGO-T-Display
// 210217
#pragma once
#include "wled.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#ifndef USER_SETUP_LOADED
#ifndef ST7789_DRIVER
#error Please define ST7789_DRIVER
#endif
#ifndef TFT_WIDTH
#error Please define TFT_WIDTH
#endif
#ifndef TFT_HEIGHT
#error Please define TFT_HEIGHT
#endif
#ifndef TFT_MOSI
#error Please define TFT_MOSI
#endif
#ifndef TFT_SCLK
#error Please define TFT_SCLK
#endif
#ifndef TFT_DC
#error Please define TFT_DC
#endif
#ifndef TFT_RST
#error Please define TFT_RST
#endif
#ifndef LOAD_GLCD
#error Please define LOAD_GLCD
#endif
#endif
#ifndef TFT_BL
#define TFT_BL -1
#endif
#define USERMOD_ID_ST7789_DISPLAY 97
TFT_eSPI tft = TFT_eSPI(TFT_WIDTH, TFT_HEIGHT); // Invoke custom library
// Extra char (+1) for null
#define LINE_BUFFER_SIZE 20
// How often we are redrawing screen
#define USER_LOOP_REFRESH_RATE_MS 1000
extern int getSignalQuality(int rssi);
//class name. Use something descriptive and leave the ": public Usermod" part :)
class St7789DisplayUsermod : public Usermod {
private:
//Private class members. You can declare variables and functions only accessible to your usermod here
unsigned long lastTime = 0;
bool enabled = true;
bool displayTurnedOff = false;
long lastRedraw = 0;
// needRedraw marks if redraw is required to prevent often redrawing.
bool needRedraw = true;
// Next variables hold the previous known values to determine if redraw is required.
String knownSsid = "";
IPAddress knownIp;
uint8_t knownBrightness = 0;
uint16_t knownMode = 0;
uint8_t knownPalette = 0;
uint8_t knownEffectSpeed = 0;
uint8_t knownEffectIntensity = 0;
uint8_t knownMinute = 99;
uint8_t knownHour = 99;
const uint8_t tftcharwidth = 19; // Number of chars that fit on screen with text size set to 2
long lastUpdate = 0;
void center(String &line, uint8_t width) {
int len = line.length();
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
for (byte i=line.length(); i<width; i++) line += ' ';
}
/**
* Display the current date and time in large characters
* on the middle rows. Based 24 or 12 hour depending on
* the useAMPM configuration.
*/
void showTime() {
if (!ntpEnabled) return;
char lineBuffer[LINE_BUFFER_SIZE];
updateLocalTime();
byte minuteCurrent = minute(localTime);
byte hourCurrent = hour(localTime);
//byte secondCurrent = second(localTime);
knownMinute = minuteCurrent;
knownHour = hourCurrent;
byte currentMonth = month(localTime);
sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(currentMonth), day(localTime));
tft.setTextColor(TFT_SILVER);
tft.setCursor(84, 0);
tft.setTextSize(2);
tft.print(lineBuffer);
byte showHour = hourCurrent;
boolean isAM = false;
if (useAMPM) {
if (showHour == 0) {
showHour = 12;
isAM = true;
} else if (showHour > 12) {
showHour -= 12;
isAM = false;
} else {
isAM = true;
}
}
sprintf_P(lineBuffer, PSTR("%2d:%02d"), (useAMPM ? showHour : hourCurrent), minuteCurrent);
tft.setTextColor(TFT_WHITE);
tft.setTextSize(4);
tft.setCursor(60, 24);
tft.print(lineBuffer);
tft.setTextSize(2);
tft.setCursor(186, 24);
//sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent);
if (useAMPM) tft.print(isAM ? "AM" : "PM");
//else tft.print(lineBuffer);
}
public:
//Functions called by WLED
/*
* setup() is called once at boot. WiFi is not yet connected at this point.
* You can use it to initialize variables, sensors or similar.
*/
void setup()
{
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
if (!pinManager.allocateMultiplePins(pins, 7, PinOwner::UM_FourLineDisplay)) { enabled = false; return; }
tft.init();
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_RED);
tft.setCursor(60, 100);
tft.setTextDatum(MC_DATUM);
tft.setTextSize(2);
tft.print("Loading...");
if (TFT_BL >= 0)
{
pinMode(TFT_BL, OUTPUT); // Set backlight pin to output mode
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
}
}
/*
* connected() is called every time the WiFi is (re)connected
* Use it to initialize network interfaces
*/
void connected() {
//Serial.println("Connected to WiFi!");
}
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*
* Tips:
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
*
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
* Instead, use a timer check as shown here.
*/
void loop() {
char buff[LINE_BUFFER_SIZE];
// Check if we time interval for redrawing passes.
if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS)
{
return;
}
lastUpdate = millis();
// Turn off display after 5 minutes with no change.
if (!displayTurnedOff && millis() - lastRedraw > 5*60*1000)
{
if (TFT_BL >= 0) digitalWrite(TFT_BL, LOW); // Turn backlight off.
displayTurnedOff = true;
}
// Check if values which are shown on display changed from the last time.
if ((((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) ||
(knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) ||
(knownBrightness != bri) ||
(knownEffectSpeed != strip.getMainSegment().speed) ||
(knownEffectIntensity != strip.getMainSegment().intensity) ||
(knownMode != strip.getMainSegment().mode) ||
(knownPalette != strip.getMainSegment().palette))
{
needRedraw = true;
}
if (!needRedraw)
{
return;
}
needRedraw = false;
if (displayTurnedOff)
{
digitalWrite(TFT_BL, HIGH); // Turn backlight on.
displayTurnedOff = false;
}
lastRedraw = millis();
// Update last known values.
#if defined(ESP8266)
knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID();
#else
knownSsid = WiFi.SSID();
#endif
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP();
knownBrightness = bri;
knownMode = strip.getMainSegment().mode;
knownPalette = strip.getMainSegment().palette;
knownEffectSpeed = strip.getMainSegment().speed;
knownEffectIntensity = strip.getMainSegment().intensity;
tft.fillScreen(TFT_BLACK);
showTime();
tft.setTextSize(2);
// Wifi name
tft.setTextColor(TFT_GREEN);
tft.setCursor(0, 60);
String line = knownSsid.substring(0, tftcharwidth-1);
// Print `~` char to indicate that SSID is longer, than our display
if (knownSsid.length() > tftcharwidth) line = line.substring(0, tftcharwidth-1) + '~';
center(line, tftcharwidth);
tft.print(line.c_str());
// Print AP IP and password in AP mode or knownIP if AP not active.
if (apActive)
{
tft.setCursor(0, 84);
tft.print("AP IP: ");
tft.print(knownIp);
tft.setCursor(0,108);
tft.print("AP Pass:");
tft.print(apPass);
}
else
{
tft.setCursor(0, 84);
line = knownIp.toString();
center(line, tftcharwidth);
tft.print(line.c_str());
// percent brightness
tft.setCursor(0, 120);
tft.setTextColor(TFT_WHITE);
tft.print("Bri: ");
tft.print((((int)bri*100)/255));
tft.print("%");
// signal quality
tft.setCursor(124,120);
tft.print("Sig: ");
if (getSignalQuality(WiFi.RSSI()) < 10) {
tft.setTextColor(TFT_RED);
} else if (getSignalQuality(WiFi.RSSI()) < 25) {
tft.setTextColor(TFT_ORANGE);
} else {
tft.setTextColor(TFT_GREEN);
}
tft.print(getSignalQuality(WiFi.RSSI()));
tft.setTextColor(TFT_WHITE);
tft.print("%");
}
// mode name
tft.setTextColor(TFT_CYAN);
tft.setCursor(0, 144);
char lineBuffer[tftcharwidth+1];
extractModeName(knownMode, JSON_mode_names, lineBuffer, tftcharwidth);
tft.print(lineBuffer);
// palette name
tft.setTextColor(TFT_YELLOW);
tft.setCursor(0, 168);
extractModeName(knownPalette, JSON_palette_names, lineBuffer, tftcharwidth);
tft.print(lineBuffer);
tft.setCursor(0, 192);
tft.setTextColor(TFT_SILVER);
sprintf_P(buff, PSTR("FX Spd:%3d Int:%3d"), effectSpeed, effectIntensity);
tft.print(buff);
// Fifth row with estimated mA usage
tft.setTextColor(TFT_SILVER);
tft.setCursor(0, 216);
// Print estimated milliamp usage (must specify the LED type in LED prefs for this to be a reasonable estimate).
tft.print("Current: ");
tft.setTextColor(TFT_ORANGE);
tft.print(strip.currentMilliamps);
tft.print("mA");
}
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
void addToJsonInfo(JsonObject& root)
{
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
JsonArray lightArr = user.createNestedArray("ST7789"); //name
lightArr.add(enabled?F("installed"):F("disabled")); //unit
}
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void addToJsonState(JsonObject& root)
{
//root["user0"] = userVar0;
}
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
void readFromJsonState(JsonObject& root)
{
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
}
/*
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
* If you want to force saving the current state, use serializeConfig() in your loop().
*
* CAUTION: serializeConfig() will initiate a filesystem write operation.
* It might cause the LEDs to stutter and will cause flash wear if called too often.
* Use it sparingly and always in the loop, never in network callbacks!
*
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
*
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
*/
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject("ST7789");
JsonArray pins = top.createNestedArray("pin");
pins.add(TFT_MOSI);
pins.add(TFT_MISO);
pins.add(TFT_SCLK);
pins.add(TFT_CS);
pins.add(TFT_DC);
pins.add(TFT_RST);
pins.add(TFT_BL);
//top["great"] = userVar0; //save this var persistently whenever settings are saved
}
/*
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
*
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
*/
bool readFromConfig(JsonObject& root)
{
//JsonObject top = root["top"];
//userVar0 = top["great"] | 42; //The value right of the pipe "|" is the default value in case your setting was not present in cfg.json (e.g. first boot)
return true;
}
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId()
{
return USERMOD_ID_ST7789_DISPLAY;
}
//More methods can be added in the future, this example will then be extended.
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
};