mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-22 00:06:24 +01:00
Merge pull request #14 from nlimper/development
new content and improvements
This commit is contained in:
BIN
esp32_fw/data/fonts/GillSC16.vlw
Normal file
BIN
esp32_fw/data/fonts/GillSC16.vlw
Normal file
Binary file not shown.
BIN
esp32_fw/data/fonts/GillSC20.vlw
Normal file
BIN
esp32_fw/data/fonts/GillSC20.vlw
Normal file
Binary file not shown.
Binary file not shown.
BIN
esp32_fw/data/fonts/weathericons70.vlw
Normal file
BIN
esp32_fw/data/fonts/weathericons70.vlw
Normal file
Binary file not shown.
@@ -30,6 +30,8 @@
|
||||
<option value="2">count days</option>
|
||||
<option value="3">count hours</option>
|
||||
<option value="4">current weather</option>
|
||||
<option value="8">weather forecast</option>
|
||||
<option value="9">rss feed</option>
|
||||
<option value="6">memo text</option>
|
||||
<option value="7">image url</option>
|
||||
<option value="5">firmware update</option>
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
const $ = document.querySelector.bind(document);
|
||||
|
||||
const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url"];
|
||||
const WAKEUP_REASON_TIMED = 0;
|
||||
const WAKEUP_REASON_GPIO = 2;
|
||||
const WAKEUP_REASON_NFC = 3;
|
||||
const WAKEUP_REASON_FIRSTBOOT = 0xFC;
|
||||
const WAKEUP_REASON_NETWORK_SCAN = 0xFD;
|
||||
const WAKEUP_REASON_WDT_RESET = 0xFE;
|
||||
|
||||
const contentModes = ["Static image", "Current date", "Counting days", "Counting hours", "Current weather", "Firmware update", "Memo text", "Image url", "Weather forecast","RSS feed"];
|
||||
const models = ["1.54\" 152x152px", "2.9\" 296x128px", "4.2\" 400x300px"];
|
||||
const contentModeOptions = [];
|
||||
contentModeOptions[0] = ["filename","timetolive"];
|
||||
@@ -11,6 +18,8 @@ contentModeOptions[4] = ["location"];
|
||||
contentModeOptions[5] = ["filename"];
|
||||
contentModeOptions[6] = ["text"];
|
||||
contentModeOptions[7] = ["url","interval"];
|
||||
contentModeOptions[8] = ["location"];
|
||||
contentModeOptions[9] = ["title", "url", "interval"];
|
||||
|
||||
const imageQueue = [];
|
||||
let isProcessing = false;
|
||||
@@ -123,6 +132,28 @@ function processTags(tagArray) {
|
||||
div.dataset.hash = element.hash;
|
||||
$('#tag' + tagmac + ' .warningicon').style.display = 'none';
|
||||
$('#tag' + tagmac).style.background = "inherit";
|
||||
switch (element.wakeupReason) {
|
||||
case WAKEUP_REASON_TIMED:
|
||||
break;
|
||||
case WAKEUP_REASON_GPIO:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "GPIO wakeup"
|
||||
break;
|
||||
case WAKEUP_REASON_NFC:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "NFC wakeup"
|
||||
break;
|
||||
case WAKEUP_REASON_FIRSTBOOT:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>First boot</font>"
|
||||
$('#tag' + tagmac).style.background = "purple";
|
||||
break;
|
||||
case WAKEUP_REASON_NETWORK_SCAN:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "<font color=yellow>Network scan</font>"
|
||||
$('#tag' + tagmac).style.background = "green";
|
||||
break;
|
||||
case WAKEUP_REASON_WDT_RESET:
|
||||
$('#tag' + tagmac + ' .nextcheckin').innerHTML = "Watchdog reset!"
|
||||
$('#tag' + tagmac).style.background = "red";
|
||||
break;
|
||||
}
|
||||
$('#tag' + tagmac + ' .pendingicon').style.display = (element.pending ? 'inline-block' : 'none');
|
||||
div.classList.add("tagflash");
|
||||
(function(tagmac) {
|
||||
|
||||
@@ -22,10 +22,12 @@ struct blockData {
|
||||
#define SOLUM_29_033 1
|
||||
#define SOLUM_42_033 2
|
||||
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_BOOTUP 1
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
#define WAKEUP_REASON_TIMED 0
|
||||
#define WAKEUP_REASON_GPIO 2
|
||||
#define WAKEUP_REASON_NFC 3
|
||||
#define WAKEUP_REASON_FIRSTBOOT 0xFC
|
||||
#define WAKEUP_REASON_NETWORK_SCAN 0xFD
|
||||
#define WAKEUP_REASON_WDT_RESET 0xFE
|
||||
|
||||
struct AvailDataReq {
|
||||
uint8_t checksum;
|
||||
@@ -49,6 +51,11 @@ struct espAvailDataReq {
|
||||
#define DATATYPE_IMGRAW 2
|
||||
#define DATATYPE_UPDATE 3
|
||||
|
||||
#define EPD_LUT_DEFAULT 0
|
||||
#define EPD_LUT_NO_REPEATS 1
|
||||
#define EPD_LUT_FAST_NO_REDS 2
|
||||
#define EPD_LUT_FAST 3
|
||||
|
||||
struct AvailDataInfo {
|
||||
uint8_t checksum;
|
||||
uint64_t dataVer; // MD5 of potential traffic
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
#include "tag_db.h"
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
struct contentTypes {
|
||||
uint16_t id;
|
||||
String name;
|
||||
uint16_t tagTypes;
|
||||
void (*functionname)();
|
||||
String description;
|
||||
String optionList;
|
||||
};
|
||||
|
||||
void contentRunner();
|
||||
void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo);
|
||||
bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin);
|
||||
@@ -14,8 +23,10 @@ void initSprite(TFT_eSprite &spr, int w, int h);
|
||||
void drawDate(String &filename, tagRecord *&taginfo);
|
||||
void drawNumber(String &filename, int32_t count, int32_t thresholdred, tagRecord *&taginfo);
|
||||
void drawWeather(String &filename, String location, tagRecord *&taginfo);
|
||||
void drawForecast(String &filename, String location, tagRecord *&taginfo);
|
||||
void drawIdentify(String &filename, tagRecord *&taginfo);
|
||||
bool getImgURL(String &filename, String URL, time_t fetched);
|
||||
bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo);
|
||||
char *formatHttpDate(time_t t);
|
||||
String urlEncode(const char *msg);
|
||||
int windSpeedToBeaufort(float windSpeed);
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
class tagRecord {
|
||||
public:
|
||||
uint16_t nextCheckinpending;
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, CheckinInMinPending(0), expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0) {}
|
||||
tagRecord() : mac{0}, alias(""), lastseen(0), nextupdate(0), contentMode(0), pending(false), md5{0}, md5pending{0}, expectedNextCheckin(0), modeConfigJson(""), LQI(0), RSSI(0), temperature(0), batteryMv(0), hwType(0), wakeupReason(0), capabilities(0), lastfullupdate(0) {}
|
||||
|
||||
uint8_t mac[6];
|
||||
String alias;
|
||||
@@ -28,7 +28,6 @@ class tagRecord {
|
||||
bool pending;
|
||||
uint8_t md5[16];
|
||||
uint8_t md5pending[16];
|
||||
uint16_t CheckinInMinPending;
|
||||
uint32_t expectedNextCheckin;
|
||||
String modeConfigJson;
|
||||
uint8_t LQI;
|
||||
@@ -37,7 +36,8 @@ class tagRecord {
|
||||
uint16_t batteryMv;
|
||||
uint8_t hwType;
|
||||
uint8_t wakeupReason;
|
||||
uint8_t capabilities;
|
||||
uint8_t capabilities;
|
||||
uint32_t lastfullupdate;
|
||||
static tagRecord* findByMAC(uint8_t mac[6]);
|
||||
};
|
||||
|
||||
|
||||
@@ -24,5 +24,7 @@ lib_deps =
|
||||
bblanchon/ArduinoJson
|
||||
bodmer/TFT_eSPI
|
||||
https://github.com/Bodmer/TJpg_Decoder.git
|
||||
https://github.com/garretlab/shoddyxml2
|
||||
https://github.com/Bodmer/U8g2_for_TFT_eSPI
|
||||
upload_port = COM12
|
||||
monitor_port = COM12
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
#include "newproto.h"
|
||||
#include <MD5Builder.h>
|
||||
#include <locale.h>
|
||||
#include <rssClass.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "U8g2_for_TFT_eSPI.h"
|
||||
#include "commstructs.h"
|
||||
#include "makeimage.h"
|
||||
#include "web.h"
|
||||
@@ -21,6 +23,8 @@ enum contentModes {
|
||||
Firmware,
|
||||
Memo,
|
||||
ImageUrl,
|
||||
Forecast,
|
||||
RSSFeed,
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +126,13 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
updateTagImage(filename, mac, 15);
|
||||
break;
|
||||
|
||||
case Forecast:
|
||||
|
||||
drawForecast(filename, cfgobj["location"], taginfo);
|
||||
taginfo->nextupdate = now + 3 * 3600;
|
||||
updateTagImage(filename, mac, 15);
|
||||
break;
|
||||
|
||||
case Firmware:
|
||||
|
||||
filename = cfgobj["filename"].as<String>();
|
||||
@@ -156,6 +167,16 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
taginfo->nextupdate = now + 300;
|
||||
}
|
||||
break;
|
||||
|
||||
case RSSFeed:
|
||||
|
||||
if (getRSSfeed(filename, cfgobj["url"], cfgobj["title"], taginfo)) {
|
||||
taginfo->nextupdate = now + 60 * (cfgobj["interval"].as<int>() < 5 ? 5 : cfgobj["interval"].as<int>());
|
||||
updateTagImage(filename, mac, cfgobj["interval"].as<int>());
|
||||
} else {
|
||||
taginfo->nextupdate = now + 300;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
taginfo->modeConfigJson = doc.as<String>();
|
||||
@@ -169,10 +190,10 @@ bool updateTagImage(String &filename, uint8_t *dst, uint16_t nextCheckin) {
|
||||
void drawString(TFT_eSprite &spr, String content, uint16_t posx, uint16_t posy, String font, byte align,uint16_t color) {
|
||||
// drawString(spr,"test",100,10,"bahnschrift30",TC_DATUM,TFT_RED);
|
||||
spr.setTextDatum(align);
|
||||
spr.loadFont(font, LittleFS);
|
||||
if (font != "") spr.loadFont(font, LittleFS);
|
||||
spr.setTextColor(color, TFT_WHITE);
|
||||
spr.drawString(content, posx, posy);
|
||||
spr.unloadFont();
|
||||
if (font != "") spr.unloadFont();
|
||||
}
|
||||
|
||||
void initSprite(TFT_eSprite &spr, int w, int h) {
|
||||
@@ -316,8 +337,6 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) {
|
||||
weatherIcons[2] = "\0uf086";
|
||||
}
|
||||
|
||||
String windIcons[] = {"\uf0b7", "\uf0b8", "\uf0b9", "\uf0ba", "\uf0bb", "\uf0bc", "\uf0bd", "\uf0be", "\uf0bf", "\uf0c0", "\uf0c1", "\uf0c2", "\uf0c3"};
|
||||
|
||||
doc.clear();
|
||||
|
||||
LittleFS.begin();
|
||||
@@ -327,33 +346,27 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) {
|
||||
|
||||
initSprite(spr, 296, 128);
|
||||
|
||||
drawString(spr, location, 10, 10, "fonts/bahnschrift30");
|
||||
drawString(spr, location, 5, 5, "fonts/bahnschrift30");
|
||||
drawString(spr, String(wind), 280, 5, "fonts/bahnschrift30", TR_DATUM, (wind > 4 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
char tmpOutput[5];
|
||||
dtostrf(temperature, 2, 1, tmpOutput);
|
||||
drawString(spr, String(tmpOutput), 5, 65, "fonts/bahnschrift70", TL_DATUM, (temperature < 0 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
spr.loadFont("fonts/weathericons78", LittleFS);
|
||||
spr.loadFont("fonts/weathericons70", LittleFS);
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(185, 20);
|
||||
|
||||
spr.setCursor(185, 32);
|
||||
spr.printToSprite(weatherIcons[weathercode]);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
if (wind > 4) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(255, 0);
|
||||
spr.printToSprite(windIcons[wind]);
|
||||
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(230, -5);
|
||||
spr.setCursor(235, -3);
|
||||
spr.printToSprite(windDirectionIcon(winddirection));
|
||||
if (weathercode > 10) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
@@ -381,21 +394,16 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) {
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(35, 25);
|
||||
|
||||
spr.setCursor(30, 33);
|
||||
spr.printToSprite(weatherIcons[weathercode]);
|
||||
spr.unloadFont();
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
if (wind > 4) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setCursor(115, -5);
|
||||
spr.printToSprite(windIcons[wind]);
|
||||
drawString(spr, String(wind), 140, 10, "fonts/bahnschrift30", TR_DATUM, (wind > 4 ? TFT_RED : TFT_BLACK));
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(90, -5);
|
||||
spr.setCursor(100, -2);
|
||||
spr.printToSprite(windDirectionIcon(winddirection));
|
||||
if (weathercode > 10) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
@@ -413,6 +421,109 @@ void drawWeather(String &filename, String location, tagRecord *&taginfo) {
|
||||
http.end();
|
||||
}
|
||||
|
||||
void drawForecast(String &filename, String location, tagRecord *&taginfo) {
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
|
||||
wsLog("get weather");
|
||||
HTTPClient http;
|
||||
http.begin("https://geocoding-api.open-meteo.com/v1/search?name=" + urlEncode(location.c_str()) + "&count=1");
|
||||
http.setTimeout(5000); // timeout in ms
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == 200) {
|
||||
DynamicJsonDocument doc(2000);
|
||||
DeserializationError error = deserializeJson(doc, http.getStream());
|
||||
http.end();
|
||||
|
||||
http.begin("https://api.open-meteo.com/v1/forecast?latitude=" + doc["results"][0]["latitude"].as<String>() + "&longitude=" + doc["results"][0]["longitude"].as<String>() + "&daily=weathercode,temperature_2m_max,temperature_2m_min,precipitation_sum,windspeed_10m_max,winddirection_10m_dominant&windspeed_unit=ms&timeformat=unixtime&timezone=" + doc["results"][0]["timezone"].as<String>());
|
||||
|
||||
doc.clear();
|
||||
http.setTimeout(5000); // timeout in ms
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
StaticJsonDocument<500> filter;
|
||||
filter["daily"]["time"][0] = true;
|
||||
filter["daily"]["weathercode"][0] = true;
|
||||
filter["daily"]["temperature_2m_max"][0] = true;
|
||||
filter["daily"]["temperature_2m_min"][0] = true;
|
||||
filter["daily"]["precipitation_sum"][0] = true;
|
||||
filter["daily"]["windspeed_10m_max"][0] = true;
|
||||
filter["daily"]["winddirection_10m_dominant"][0] = true;
|
||||
|
||||
//DeserializationError error = deserializeJson(doc, http.getString(), DeserializationOption::Filter(filter));
|
||||
DeserializationError error = deserializeJson(doc, http.getString());
|
||||
if (error) {
|
||||
Serial.println(F("deserializeJson() failed: "));
|
||||
Serial.println(error.c_str());
|
||||
}
|
||||
|
||||
static const char *weekday_name[] = {"ZO", "MA", "DI", "WO", "DO", "VR", "ZA"};
|
||||
|
||||
String weatherIcons[] = {"\uf00d", "\uf00c", "\uf002", "\uf013", "\uf013", "\uf014", "-", "-", "\uf014", "-", "-",
|
||||
"\uf01a", "-", "\uf01a", "-", "\uf01a", "\uf017", "\uf017", "-", "-", "-",
|
||||
"\uf019", "-", "\uf019", "-", "\uf019", "\uf015", "\uf015", "-", "-", "-",
|
||||
"\uf01b", "-", "\uf01b", "-", "\uf01b", "-", "\uf076", "-", "-", "\uf01a",
|
||||
"\uf01a", "\uf01a", "-", "-", "\uf064", "\uf064", "-", "-", "-", "-",
|
||||
"-", "-", "-", "-", "\uf01e", "\uf01d", "-", "-", "\uf01e"};
|
||||
|
||||
LittleFS.begin();
|
||||
tft.setTextWrap(false, false);
|
||||
|
||||
if (taginfo->hwType == SOLUM_29_033) {
|
||||
initSprite(spr, 296, 128);
|
||||
|
||||
spr.setTextFont(2);
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.drawString(location, 5, 0);
|
||||
|
||||
for (uint8_t dag = 0; dag < 5; dag++) {
|
||||
time_t weatherday = doc["daily"]["time"][dag].as<time_t>();
|
||||
struct tm *datum = localtime(&weatherday);
|
||||
drawString(spr, String(weekday_name[datum->tm_wday]), dag * 59 + 30, 18, "fonts/twbold20", TC_DATUM, TFT_BLACK);
|
||||
|
||||
uint8_t weathercode = doc["daily"]["weathercode"][dag].as<int>();
|
||||
if (weathercode > 40) weathercode -= 40;
|
||||
|
||||
spr.loadFont("fonts/weathericons30", LittleFS);
|
||||
if (weathercode == 55 || weathercode == 65 || weathercode == 75 || weathercode == 82 || weathercode == 86 || weathercode == 95 || weathercode == 99) {
|
||||
spr.setTextColor(TFT_RED, TFT_WHITE);
|
||||
} else {
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
}
|
||||
spr.setTextDatum(TL_DATUM);
|
||||
spr.setCursor(12 + dag * 59, 58);
|
||||
spr.printToSprite(weatherIcons[weathercode]);
|
||||
|
||||
spr.setTextColor(TFT_BLACK, TFT_WHITE);
|
||||
spr.setCursor(17 + dag * 59, 27);
|
||||
spr.printToSprite(windDirectionIcon(doc["daily"]["winddirection_10m_dominant"][dag]));
|
||||
spr.unloadFont();
|
||||
|
||||
int8_t tmin = round(doc["daily"]["temperature_2m_min"][dag].as<double>());
|
||||
int8_t tmax = round(doc["daily"]["temperature_2m_max"][dag].as<double>());
|
||||
uint8_t wind = windSpeedToBeaufort(doc["daily"]["windspeed_10m_max"][dag].as<double>());
|
||||
|
||||
spr.loadFont("fonts/GillSC20", LittleFS);
|
||||
drawString(spr, String(tmin) + " ", dag * 59 + 30, 108, "", TR_DATUM, (tmin < 0 ? TFT_RED : TFT_BLACK));
|
||||
drawString(spr, String(" ") + String(tmax), dag * 59 + 30, 108, "", TL_DATUM, (tmax < 0 ? TFT_RED : TFT_BLACK));
|
||||
drawString(spr, String(" ") + String(wind), dag * 59 + 30, 43, "", TL_DATUM, (wind > 5 ? TFT_RED : TFT_BLACK));
|
||||
spr.unloadFont();
|
||||
if (dag>0) {
|
||||
for (int i = 20; i < 128; i+=3) {
|
||||
spr.drawPixel(dag * 59, i, TFT_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
spr2grays(spr, spr.width(), spr.height(), filename);
|
||||
spr.deleteSprite();
|
||||
}
|
||||
}
|
||||
http.end();
|
||||
}
|
||||
|
||||
void drawIdentify(String &filename, tagRecord *&taginfo) {
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
@@ -463,6 +574,62 @@ bool getImgURL(String &filename, String URL, time_t fetched) {
|
||||
return (httpCode == 200 || httpCode == 304);
|
||||
}
|
||||
|
||||
rssClass reader;
|
||||
|
||||
bool getRSSfeed(String &filename, String URL, String title, tagRecord *&taginfo) {
|
||||
// https://github.com/garretlab/shoddyxml2
|
||||
|
||||
// http://feeds.feedburner.com/tweakers/nieuws
|
||||
// https://www.nu.nl/rss/Algemeen
|
||||
|
||||
Serial.println("RSS feed");
|
||||
struct tm timeInfo;
|
||||
char header[32];
|
||||
getLocalTime(&timeInfo);
|
||||
sprintf(header, "%02d-%02d-%04d %02d:%02d", timeInfo.tm_mday, timeInfo.tm_mon + 1, timeInfo.tm_year + 1900, timeInfo.tm_hour, timeInfo.tm_min);
|
||||
|
||||
const char *url = URL.c_str();
|
||||
const char *tag = "title";
|
||||
const int rssArticleSize = 128;
|
||||
const int rssNumArticle = 8;
|
||||
|
||||
TFT_eSPI tft = TFT_eSPI();
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
U8g2_for_TFT_eSPI u8f;
|
||||
u8f.begin(spr);
|
||||
|
||||
if (taginfo->hwType == SOLUM_29_033) {
|
||||
initSprite(spr, 296, 128);
|
||||
if (title=="" || title=="null") title="RSS feed";
|
||||
drawString(spr, title, 5, 3, "fonts/bahnschrift20", TL_DATUM, TFT_RED);
|
||||
|
||||
u8f.setFont(u8g2_font_glasstown_nbp_tr); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
|
||||
u8f.setFontMode(0);
|
||||
u8f.setFontDirection(0);
|
||||
u8f.setForegroundColor(TFT_BLACK);
|
||||
u8f.setBackgroundColor(TFT_WHITE);
|
||||
u8f.setCursor(220, 20);
|
||||
u8f.print(header);
|
||||
|
||||
// u8g2_font_nine_by_five_nbp_tr
|
||||
// u8g2_font_7x14_tr
|
||||
// u8g2_font_crox1h_tr
|
||||
// u8g2_font_miranda_nbp_tr
|
||||
u8f.setFont(u8g2_font_glasstown_nbp_tr); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
|
||||
|
||||
int n = reader.getArticles(url, tag, rssArticleSize, rssNumArticle);
|
||||
for (int i = 0; i < n; i++) {
|
||||
u8f.setCursor(5, 34+i*13); // start writing at this position
|
||||
u8f.print(reader.itemData[i]);
|
||||
}
|
||||
}
|
||||
|
||||
spr2grays(spr, spr.width(), spr.height(), filename);
|
||||
spr.deleteSprite();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *formatHttpDate(time_t t) {
|
||||
static char buf[40];
|
||||
struct tm *timeinfo;
|
||||
|
||||
@@ -152,6 +152,12 @@ void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) {
|
||||
f_out.write(0x00);
|
||||
}
|
||||
|
||||
const int dither_matrix[4][4] = {
|
||||
{1, 9, 3, 11},
|
||||
{13, 5, 15, 7},
|
||||
{4, 12, 2, 10},
|
||||
{0, 8, 14, 6}};
|
||||
|
||||
while (numRows--) {
|
||||
uint32_t pixelValsPackedSoFar = 0, numPixelsPackedSoFar = 0, valSoFar = 0, bytesIn = 0, bytesOut = 0, bitsSoFar = 0;
|
||||
|
||||
@@ -170,8 +176,10 @@ void spr2grays(TFT_eSprite &spr, long w, long h, String &fileout) {
|
||||
uint8_t green = ((color565 >> 5) & 0x3F) * 4;
|
||||
uint8_t blue = (color565 & 0x1F) * 8;
|
||||
|
||||
if (dither)
|
||||
ditherFudge = (rand() % 255 - 127) / (int)numGrays;
|
||||
if (dither) {
|
||||
// ditherFudge = (rand() % 255 - 127) / (int)numGrays; // -64 to 64
|
||||
ditherFudge = (dither_matrix[numRows % 4][c % 4] - 8) * 24 / (int)numGrays;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdr.numColors; i++) {
|
||||
int64_t dist = 0;
|
||||
@@ -253,7 +261,7 @@ void bmp2grays(String filein, String fileout) {
|
||||
struct BitmapFileHeader hdr;
|
||||
enum EinkClut clutType;
|
||||
uint8_t clut[256][3];
|
||||
bool dither = true;
|
||||
bool dither = false;
|
||||
int skipBytes;
|
||||
srand(0);
|
||||
|
||||
|
||||
@@ -124,7 +124,8 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
md5.getBytes(md5bytes);
|
||||
}
|
||||
|
||||
uint16_t attempts = 60;
|
||||
uint16_t attempts = 60 * 24;
|
||||
uint8_t lut = EPD_LUT_DEFAULT;
|
||||
uint8_t src[8];
|
||||
*((uint64_t*)src) = swap64(*((uint64_t*)dst));
|
||||
uint8_t mac[6];
|
||||
@@ -141,9 +142,13 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
|
||||
time_t now;
|
||||
time(&now);
|
||||
time_t last_midnight = now - now % (24 * 60 * 60) + 3 * 3600; // somewhere in the middle of the night
|
||||
if (taginfo->lastfullupdate > last_midnight) lut = EPD_LUT_NO_REPEATS; // fast updates during the day
|
||||
/*
|
||||
uint16_t minutesUntilNextCheckin = 0;
|
||||
if (taginfo->expectedNextCheckin > now) minutesUntilNextCheckin = (taginfo->expectedNextCheckin - now) / 60;
|
||||
attempts += minutesUntilNextCheckin;
|
||||
*/
|
||||
} else {
|
||||
wsErr("Tag not found, this shouldn't happen.");
|
||||
}
|
||||
@@ -154,6 +159,7 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
pending.availdatainfo.dataType = dataType;
|
||||
pending.availdatainfo.dataVer = *((uint64_t*)md5bytes);
|
||||
pending.availdatainfo.dataSize = file.size();
|
||||
pending.availdatainfo.dataTypeArgument = EPD_LUT_NO_REPEATS;
|
||||
pending.availdatainfo.nextCheckIn = nextCheckin;
|
||||
pending.attemptsLeft = attempts;
|
||||
sendDataAvail(&pending);
|
||||
@@ -185,14 +191,15 @@ bool prepareDataAvail(String* filename, uint8_t dataType, uint8_t* dst, uint16_t
|
||||
|
||||
wsLog("new image pending: " + String(dst_path));
|
||||
if (taginfo != nullptr) {
|
||||
time_t now;
|
||||
time(&now);
|
||||
taginfo->pending = true;
|
||||
taginfo->CheckinInMinPending = nextCheckin;
|
||||
taginfo->expectedNextCheckin = now + nextCheckin * 60 + 60;
|
||||
memcpy(taginfo->md5pending, md5bytes, sizeof(md5bytes));
|
||||
}
|
||||
}
|
||||
else {
|
||||
wsLog("firmware upload pending");
|
||||
}
|
||||
} else {
|
||||
wsLog("firmware upload pending");
|
||||
}
|
||||
file.close();
|
||||
|
||||
wsSendTaginfo(mac);
|
||||
@@ -275,17 +282,13 @@ void processXferComplete(struct espXferComplete* xfc) {
|
||||
if (taginfo != nullptr) {
|
||||
|
||||
uint16_t minutesUntilNextUpdate = 0;
|
||||
if (taginfo->nextupdate > now + 60 * taginfo->CheckinInMinPending + 3) {
|
||||
minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60 - taginfo->CheckinInMinPending;
|
||||
if (minutesUntilNextUpdate > taginfo->CheckinInMinPending) minutesUntilNextUpdate = taginfo->CheckinInMinPending;
|
||||
if (taginfo->nextupdate > now + 2) {
|
||||
minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
|
||||
if (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME;
|
||||
|
||||
taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60;
|
||||
if (minutesUntilNextUpdate > 0) prepareIdleReq (xfc->src, minutesUntilNextUpdate);
|
||||
taginfo->CheckinInMinPending = minutesUntilNextUpdate;
|
||||
if (minutesUntilNextUpdate > 1) prepareIdleReq (xfc->src, minutesUntilNextUpdate);
|
||||
} else {
|
||||
taginfo->expectedNextCheckin = now + 60;
|
||||
taginfo->CheckinInMinPending = 0;
|
||||
}
|
||||
|
||||
taginfo->pending = false;
|
||||
@@ -310,7 +313,6 @@ void processXferTimeout(struct espXferComplete* xfc) {
|
||||
taginfo = tagRecord::findByMAC(mac);
|
||||
if (taginfo != nullptr) {
|
||||
taginfo->expectedNextCheckin = now + 60;
|
||||
taginfo->CheckinInMinPending = 0;
|
||||
taginfo->pending = false;
|
||||
memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
}
|
||||
@@ -341,15 +343,13 @@ void processDataReq(struct espAvailDataReq* eadr) {
|
||||
taginfo->lastseen = now;
|
||||
|
||||
uint16_t minutesUntilNextUpdate = 0;
|
||||
if (taginfo->nextupdate > now + 60 * taginfo->CheckinInMinPending + 3 && taginfo->pending == false) {
|
||||
minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60 - taginfo->CheckinInMinPending;
|
||||
if (minutesUntilNextUpdate > taginfo->CheckinInMinPending) minutesUntilNextUpdate = taginfo->CheckinInMinPending;
|
||||
if (taginfo->nextupdate > now + 2) {
|
||||
minutesUntilNextUpdate = (taginfo->nextupdate - now) / 60;
|
||||
if (minutesUntilNextUpdate > MIN_RESPONSE_TIME) minutesUntilNextUpdate = MIN_RESPONSE_TIME;
|
||||
taginfo->expectedNextCheckin = now + 60 * minutesUntilNextUpdate + 60;
|
||||
if (minutesUntilNextUpdate > 0) prepareIdleReq(eadr->src, minutesUntilNextUpdate);
|
||||
taginfo->CheckinInMinPending = minutesUntilNextUpdate;
|
||||
if (minutesUntilNextUpdate > 1 && taginfo->pending == false) prepareIdleReq(eadr->src, minutesUntilNextUpdate);
|
||||
} else {
|
||||
taginfo->expectedNextCheckin = now + 60 * taginfo->CheckinInMinPending + 60;
|
||||
taginfo->expectedNextCheckin = now + 60;
|
||||
}
|
||||
|
||||
if (eadr->adr.lastPacketRSSI != 0) {
|
||||
|
||||
@@ -284,7 +284,6 @@ void init_web() {
|
||||
taginfo->modeConfigJson = request->getParam("modecfgjson", true)->value();
|
||||
taginfo->contentMode = atoi(request->getParam("contentmode", true)->value().c_str());
|
||||
taginfo->nextupdate = 0;
|
||||
taginfo->CheckinInMinPending = 0;
|
||||
memset(taginfo->md5, 0, 16 * sizeof(uint8_t));
|
||||
memset(taginfo->md5pending, 0, 16 * sizeof(uint8_t));
|
||||
wsSendTaginfo(mac);
|
||||
|
||||
Reference in New Issue
Block a user