mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-24 00:05:36 +01:00
Merge branch 'master' of https://github.com/jjwbruijn/OpenEPaperLink
This commit is contained in:
2
.github/workflows/build-test.yml
vendored
2
.github/workflows/build-test.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Build NRF firmware
|
||||
run: |
|
||||
cd ARM_Tag_FW/Newton_M3_nRF52811
|
||||
pio run --environment Newton_M3_29_BWR
|
||||
pio run --environment Newton_M3_Universal
|
||||
|
||||
- name: Build Simple_AP
|
||||
run: |
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -25,3 +25,4 @@
|
||||
*.o
|
||||
sdcc/sdcc
|
||||
|
||||
ESP32_AP-Flasher/.vscode/extensions.json
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -35,7 +35,8 @@ bool getJsonTemplateFile(String &filename, String jsonfile, tagRecord *&taginfo,
|
||||
extern bool getJsonTemplateFileExtractVariables(String &filename, String jsonfile, JsonDocument &variables, tagRecord *&taginfo, imgParam &imageParams);
|
||||
int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams);
|
||||
void drawElement(const JsonObject &element, TFT_eSprite &spr);
|
||||
void rotateBuffer(uint8_t rotation, uint8_t ¤tOrientation, TFT_eSprite &spr, imgParam &imageParams);
|
||||
void drawElement(const JsonObject &element, TFT_eSprite &spr, imgParam &imageParams, uint8_t ¤tOrientation);
|
||||
uint16_t getColor(const String &color);
|
||||
char *formatHttpDate(const time_t t);
|
||||
String urlEncode(const char *msg);
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
extern int defaultLanguage;
|
||||
|
||||
extern String languageList[];
|
||||
|
||||
/*EN English language section*/
|
||||
extern String languageEnDaysShort[];
|
||||
extern String languageEnDays[];
|
||||
|
||||
@@ -69,6 +69,7 @@ struct Config {
|
||||
uint8_t stopsleep;
|
||||
uint8_t runStatus;
|
||||
uint8_t preview;
|
||||
uint8_t lock;
|
||||
uint8_t wifiPower;
|
||||
char timeZone[52];
|
||||
uint8_t sleepTime1;
|
||||
|
||||
@@ -1173,12 +1173,13 @@ void drawAPinfo(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
|
||||
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
DynamicJsonDocument loc(2048);
|
||||
uint8_t screenCurrentOrientation = 0;
|
||||
getTemplate(loc, 21, taginfo->hwType);
|
||||
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
const JsonArray jsonArray = loc.as<JsonArray>();
|
||||
for (const JsonVariant &elem : jsonArray) {
|
||||
drawElement(elem, spr);
|
||||
drawElement(elem, spr, imageParams, screenCurrentOrientation);
|
||||
}
|
||||
|
||||
spr2buffer(spr, filename, imageParams);
|
||||
@@ -1371,8 +1372,11 @@ int getJsonTemplateUrl(String &filename, String URL, time_t fetched, String MAC,
|
||||
}
|
||||
|
||||
void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgParam &imageParams) {
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
TFT_eSprite spr = TFT_eSprite(&tft);
|
||||
initSprite(spr, imageParams.width, imageParams.height, imageParams);
|
||||
uint8_t screenCurrentOrientation = 0;
|
||||
//spr.setRotation(2);
|
||||
//imageParams.rotatebuffer = imageParams.rotatebuffer + 1;
|
||||
DynamicJsonDocument doc(500);
|
||||
if (stream.find("[")) {
|
||||
do {
|
||||
@@ -1381,7 +1385,7 @@ void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgPa
|
||||
wsErr("json error " + String(error.c_str()));
|
||||
break;
|
||||
} else {
|
||||
drawElement(doc.as<JsonObject>(), spr);
|
||||
drawElement(doc.as<JsonObject>(), spr, imageParams, screenCurrentOrientation);
|
||||
doc.clear();
|
||||
}
|
||||
} while (stream.findUntil(",", "]"));
|
||||
@@ -1391,7 +1395,44 @@ void drawJsonStream(Stream &stream, String &filename, tagRecord *&taginfo, imgPa
|
||||
spr.deleteSprite();
|
||||
}
|
||||
|
||||
void drawElement(const JsonObject &element, TFT_eSprite &spr) {
|
||||
void rotateBuffer(uint8_t rotation, uint8_t ¤tOrientation, TFT_eSprite &spr, imgParam &imageParams){
|
||||
rotation = rotation % 4; //First of all, let's be sure that the rotation have a valid value (0, 1, 2 or 3)
|
||||
if(rotation != currentOrientation){ //If we have a rotation to do, let's do it
|
||||
int stepToDo = currentOrientation - rotation; //rotation we have to do
|
||||
//-2, 2: upside down
|
||||
//-1, 3: 270° rotation
|
||||
//-3, 1: 90° rotation
|
||||
|
||||
if(abs(stepToDo) == 2){ //If we have to do a 180° rotation:
|
||||
TFT_eSprite sprCpy = TFT_eSprite(&tft); //We create a new sprite that will act as a buffer
|
||||
initSprite(sprCpy, spr.width(), spr.height(), imageParams); //initialisation of the new sprite
|
||||
spr.pushRotated(&sprCpy, 180, TFT_WHITE); //We fill the new sprite with the old one rotated by 180°
|
||||
spr.fillSprite(TFT_WHITE); //We fill the old one in white as anything that's white will be ignored by the pushRotated function
|
||||
sprCpy.pushRotated(&spr, 0, TFT_WHITE); //We copy the buffer sprite to the main one
|
||||
sprCpy.deleteSprite(); //We delete the buffer sprite to avoid memory leak
|
||||
}else{
|
||||
int angle = 90;
|
||||
if(stepToDo == -1 || stepToDo == 3){
|
||||
angle = 270;
|
||||
}
|
||||
TFT_eSprite sprCpy = TFT_eSprite(&tft);
|
||||
initSprite(sprCpy, spr.height(), spr.width(), imageParams);
|
||||
spr.pushRotated(&sprCpy, angle, TFT_WHITE);
|
||||
spr.deleteSprite();
|
||||
initSprite(spr, sprCpy.width(), sprCpy.height(), imageParams);
|
||||
sprCpy.pushRotated(&spr, 0, TFT_WHITE);
|
||||
sprCpy.deleteSprite();
|
||||
if(imageParams.rotatebuffer==1){
|
||||
imageParams.rotatebuffer = 0;
|
||||
}else{
|
||||
imageParams.rotatebuffer = 1;
|
||||
}
|
||||
}
|
||||
currentOrientation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
void drawElement(const JsonObject &element, TFT_eSprite &spr, imgParam &imageParams, uint8_t ¤tOrientation) {
|
||||
if (element.containsKey("text")) {
|
||||
const JsonArray &textArray = element["text"];
|
||||
const uint16_t align = textArray[5] | 0;
|
||||
@@ -1414,6 +1455,9 @@ void drawElement(const JsonObject &element, TFT_eSprite &spr) {
|
||||
} else if (element.containsKey("circle")) {
|
||||
const JsonArray &circleArray = element["circle"];
|
||||
spr.fillCircle(circleArray[0].as<int>(), circleArray[1].as<int>(), circleArray[2].as<int>(), getColor(circleArray[3]));
|
||||
} else if (element.containsKey("rotate")) {
|
||||
uint8_t rotation = element["rotate"].as<int>();
|
||||
rotateBuffer(rotation, currentOrientation, spr, imageParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
int defaultLanguage = 0;
|
||||
|
||||
String languageList[] = {"EN - English", "NL - Nederlands", "DE - Deutsch", "NO - Norwegian", "FR - French"};
|
||||
|
||||
/*EN English language section*/
|
||||
String languageEnDaysShort[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
|
||||
String languageEnDays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
|
||||
@@ -33,21 +31,45 @@ String languageNoDays[] = {"Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag",
|
||||
String languageNoMonth[] = {"Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"};
|
||||
/*END Norwegian language section END*/
|
||||
|
||||
/*CZ Czech language section*/
|
||||
String languageCzDaysShort[] = {"NE", "PO", "ÚT", "ST", "ČT", "PÁ", "SO"};
|
||||
String languageCzDays[] = {"Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"};
|
||||
String languageCzMonth[] = {"Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"};
|
||||
/*END Czech language section END*/
|
||||
|
||||
/*SK Slovak language section*/
|
||||
String languageSkDaysShort[] = {"NE", "PO", "UT", "ST", "ŠT", "PI", "SO"};
|
||||
String languageSkDays[] = {"Nedeľa", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatok", "Sobota"};
|
||||
String languageSkMonth[] = {"Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Oktober", "November", "December"};
|
||||
/*END Slovak language section END*/
|
||||
|
||||
/*PL Polish language section*/
|
||||
String languagePlDaysShort[] = {"Ni", "Po", "Wt", "Śr", "Cz", "Pt", "So"};
|
||||
String languagePlDays[] = {"Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"};
|
||||
String languagePlMonth[] = {"Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"};
|
||||
/*END Polish language section END*/
|
||||
|
||||
/*ES Spanish language section*/
|
||||
String languageEsDaysShort[] = {"D", "L", "MA", "MI", "J", "V", "S"};
|
||||
String languageEsDays[] = {"Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"};
|
||||
String languageEsMonth[] = {"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"};
|
||||
/*END Spanish language section END*/
|
||||
|
||||
/*FR French language section*/
|
||||
String languageFrDaysShort[] = {"DI", "LU", "MA", "ME", "JE", "VE", "SA"};
|
||||
String languageFrDays[] = {"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"};
|
||||
String languageFrMonth[] = {"Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Decembre"};
|
||||
/*END French language section END*/
|
||||
|
||||
String* languageDaysShort[] = {languageEnDaysShort, languageNlDaysShort, languageDeDaysShort, languageNoDaysShort, languageFrDaysShort};
|
||||
String* languageDays[] = {languageEnDays, languageNlDays, languageDeDays, languageNoDays, languageFrDays};
|
||||
String* languageMonth[] = {languageEnMonth, languageNlMonth, languageDeMonth, languageNoMonth, languageFrMonth};
|
||||
String* languageDaysShort[] = {languageEnDaysShort, languageNlDaysShort, languageDeDaysShort, languageNoDaysShort, languageFrDaysShort, languageCzDaysShort, languageSkDaysShort, languagePlDaysShort, languageEsDaysShort};
|
||||
String* languageDays[] = {languageEnDays, languageNlDays, languageDeDays, languageNoDays, languageFrDays, languageCzDays, languageSkDays, languagePlDays, languageEsDays};
|
||||
String* languageMonth[] = {languageEnMonth, languageNlMonth, languageDeMonth, languageNoMonth, languageFrMonth, languageCzMonth, languageSkMonth, languagePlMonth, languageEsMonth};
|
||||
|
||||
int currentLanguage = defaultLanguage;
|
||||
|
||||
void updateLanguageFromConfig() {
|
||||
int tempLang = config.language;
|
||||
if (tempLang < 0 || tempLang >= sizeof(languageList)) {
|
||||
if (tempLang < 0 || tempLang > 8) {
|
||||
Serial.println("Language not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ void prepareCancelPending(const uint8_t dst[8]) {
|
||||
|
||||
tagRecord* taginfo = tagRecord::findByMAC(dst);
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return;
|
||||
wsErr("Tag not found, this shouldn't happen.");
|
||||
return;
|
||||
}
|
||||
@@ -80,6 +81,7 @@ void prepareIdleReq(const uint8_t* dst, uint16_t nextCheckin) {
|
||||
void prepareDataAvail(uint8_t* data, uint16_t len, uint8_t dataType, const uint8_t* dst) {
|
||||
tagRecord* taginfo = tagRecord::findByMAC(dst);
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return;
|
||||
wsErr("Tag not found, this shouldn't happen.");
|
||||
return;
|
||||
}
|
||||
@@ -129,6 +131,7 @@ bool prepareDataAvail(String& filename, uint8_t dataType, uint8_t dataTypeArgume
|
||||
|
||||
tagRecord* taginfo = tagRecord::findByMAC(dst);
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return true;
|
||||
wsErr("Tag not found, this shouldn't happen.");
|
||||
return true;
|
||||
}
|
||||
@@ -345,6 +348,7 @@ void processBlockRequest(struct espBlockRequest* br) {
|
||||
|
||||
tagRecord* taginfo = tagRecord::findByMAC(br->src);
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return;
|
||||
prepareCancelPending(br->src);
|
||||
Serial.printf("blockrequest: couldn't find taginfo %02X%02X%02X%02X%02X%02X%02X%02X\n", br->src[7], br->src[6], br->src[5], br->src[4], br->src[3], br->src[2], br->src[1], br->src[0]);
|
||||
return;
|
||||
@@ -458,6 +462,7 @@ void processDataReq(struct espAvailDataReq* eadr, bool local, IPAddress remoteIP
|
||||
|
||||
tagRecord* taginfo = tagRecord::findByMAC(eadr->src);
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return;
|
||||
taginfo = new tagRecord;
|
||||
memcpy(taginfo->mac, eadr->src, sizeof(taginfo->mac));
|
||||
taginfo->pending = false;
|
||||
@@ -657,6 +662,7 @@ void updateTaginfoitem(struct TagInfo* taginfoitem, IPAddress remoteIP) {
|
||||
tagRecord* taginfo = tagRecord::findByMAC(taginfoitem->mac);
|
||||
|
||||
if (taginfo == nullptr) {
|
||||
if (config.lock) return;
|
||||
taginfo = new tagRecord;
|
||||
memcpy(taginfo->mac, taginfoitem->mac, sizeof(taginfo->mac));
|
||||
taginfo->pending = false;
|
||||
|
||||
@@ -130,9 +130,17 @@ void saveDB(const String& filename) {
|
||||
|
||||
Storage.begin();
|
||||
xSemaphoreTake(fsMutex, portMAX_DELAY);
|
||||
|
||||
fs::File existingFile = contentFS->open(filename, "r");
|
||||
if (existingFile) {
|
||||
existingFile.close();
|
||||
String backupFilename = filename + ".bak";
|
||||
contentFS->rename(filename.c_str(), backupFilename.c_str());
|
||||
}
|
||||
|
||||
fs::File file = contentFS->open(filename, "w");
|
||||
if (!file) {
|
||||
Serial.println("saveDB: Failed to open file");
|
||||
Serial.println("saveDB: Failed to open file for writing");
|
||||
xSemaphoreGive(fsMutex);
|
||||
return;
|
||||
}
|
||||
@@ -307,6 +315,7 @@ void initAPconfig() {
|
||||
config.maxsleep = APconfig["maxsleep"] | 10;
|
||||
config.stopsleep = APconfig["stopsleep"] | 1;
|
||||
config.preview = APconfig["preview"] | 1;
|
||||
config.lock = APconfig["lock"] | 0;
|
||||
config.sleepTime1 = APconfig["sleeptime1"] | 0;
|
||||
config.sleepTime2 = APconfig["sleeptime2"] | 0;
|
||||
// default wifi power 8.5 dbM
|
||||
@@ -333,6 +342,7 @@ void saveAPconfig() {
|
||||
APconfig["maxsleep"] = config.maxsleep;
|
||||
APconfig["stopsleep"] = config.stopsleep;
|
||||
APconfig["preview"] = config.preview;
|
||||
APconfig["lock"] = config.lock;
|
||||
APconfig["wifipower"] = config.wifiPower;
|
||||
APconfig["timezone"] = config.timeZone;
|
||||
APconfig["sleeptime1"] = config.sleepTime1;
|
||||
|
||||
@@ -471,6 +471,9 @@ void init_web() {
|
||||
if (request->hasParam("preview", true)) {
|
||||
config.preview = static_cast<uint8_t>(request->getParam("preview", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("lock", true)) {
|
||||
config.lock = static_cast<uint8_t>(request->getParam("lock", true)->value().toInt());
|
||||
}
|
||||
if (request->hasParam("sleeptime1", true)) {
|
||||
config.sleepTime1 = static_cast<uint8_t>(request->getParam("sleeptime1", true)->value().toInt());
|
||||
config.sleepTime2 = static_cast<uint8_t>(request->getParam("sleeptime2", true)->value().toInt());
|
||||
|
||||
@@ -21,14 +21,11 @@
|
||||
<div class="tab-container">
|
||||
<div class="tablinks material-symbols-outlined" data-target="hometab" title="Dashboard">home</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="tagtab" title="Tags">sell</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="aptab" title="Access Points">cell_tower
|
||||
</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="aptab" title="Access Points">cell_tower</div>
|
||||
<!--<div class="tablinks material-symbols-outlined" data-target="templatetab" title="Templates">browse
|
||||
</div>-->
|
||||
<div class="tablinks material-symbols-outlined" data-target="configtab" title="Settings">settings
|
||||
</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="logtab" title="Logging">text_snippet
|
||||
</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="configtab" title="Settings">settings</div>
|
||||
<div class="tablinks material-symbols-outlined" data-target="logtab" title="Logging">text_snippet</div>
|
||||
</div>
|
||||
<!-- /tabs -->
|
||||
<div><span id="runstate"></div>
|
||||
@@ -116,68 +113,55 @@
|
||||
<div id="tagtab" class="tabcontent">
|
||||
<div class="tagheader">
|
||||
<h3>Currently active tags</h3>
|
||||
<div id="activefilter"></div><button class="material-symbols-outlined"
|
||||
id="toggleFilters">filter_alt</button>
|
||||
<div id="activefilter"></div><button class="material-symbols-outlined" id="toggleFilters">filter_alt</button>
|
||||
</div>
|
||||
<div id="filterOptions">
|
||||
<div>
|
||||
<div>group by</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="" id="rnone" checked><label
|
||||
for="rnone">None</label>
|
||||
<input type="radio" name="group" value="" id="rnone" checked><label for="rnone">None</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="model" id="rtagtype"><label for="rtagtype">Tag
|
||||
model</label>
|
||||
<input type="radio" name="group" value="model" id="rtagtype"><label for="rtagtype">Tag model</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="contentmode" id="rcontent"><label
|
||||
for="rcontent">Content</label>
|
||||
<input type="radio" name="group" value="contentmode" id="rcontent"><label for="rcontent">Content</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="group" value="data-channel" id="rchannel"><label
|
||||
for="rchannel">Channel</label>
|
||||
<input type="radio" name="group" value="data-channel" id="rchannel"><label for="rchannel">Channel</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>sort by</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="alias" id="ralias" checked><label
|
||||
for="ralias">Alias</label>
|
||||
<input type="radio" name="sort" value="alias" id="ralias" checked><label for="ralias">Alias</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="mac" id="rmac"><label for="rmac">Mac</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-lastseen" id="rlastseen"><label
|
||||
for="rlastseen">Last seen</label>
|
||||
<input type="radio" name="sort" value="data-lastseen" id="rlastseen"><label for="rlastseen">Last seen</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="radio" name="sort" value="data-nextupdate" id="rnext"><label
|
||||
for="rnext">Next update</label>
|
||||
<input type="radio" name="sort" value="data-nextupdate" id="rnext"><label for="rnext">Next update</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>filter</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="local" id="rlocal"><label
|
||||
for="rlocal">local</label>
|
||||
<input type="checkbox" name="filter" value="local" id="rlocal"><label for="rlocal">local</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="remote" id="rremote"><label
|
||||
for="rremote">remote</label>
|
||||
<input type="checkbox" name="filter" value="remote" id="rremote"><label for="rremote">remote</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="inactive" id="rinactive"><label
|
||||
for="rinactive">timed out</label>
|
||||
<input type="checkbox" name="filter" value="inactive" id="rinactive"><label for="rinactive">timed out</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="pending" id="rpending"><label
|
||||
for="rpending">pending</label>
|
||||
<input type="checkbox" name="filter" value="pending" id="rpending"><label for="rpending">pending</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" name="filter" value="lowbatt" id="rlowbatt"><label
|
||||
for="rlowbatt">low battery</label>
|
||||
<input type="checkbox" name="filter" value="lowbatt" id="rlowbatt"><label for="rlowbatt">low battery</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -193,8 +177,7 @@
|
||||
<div class="nextcheckin"></div>
|
||||
<div class="nextupdate"></div>
|
||||
<div class="corner">
|
||||
<div class="pendingicon" title="A new message is waiting for the tag to pick up">
|
||||
↻</div>
|
||||
<div class="pendingicon" title="A new message is waiting for the tag to pick up">↻</div>
|
||||
<div class="warningicon" title="This tag has not been seen for a long time">⚠
|
||||
</div>
|
||||
</div>
|
||||
@@ -206,8 +189,7 @@
|
||||
<div class="tabheader">
|
||||
<div><img id="clearlog" src="data:image/gif;base64,R0lGODlhEAAQAPMAANXV1e3t7d/f39HR0dvb2/Hx8dTU1OLi4urq6mZmZpmZmf///wAAAAAAAAAAAAAAACH5BAEAAAwALAAAAAAQABAAAARBkMlJq71Yrp3ZXkr4WWCYnOZSgQVyEMYwJCq1nHhe20qgCAoA7QLyAYU7njE4JPV+zOSkCEUSFbmTVPPpbjvgTAQAOw==
|
||||
"></div>
|
||||
<div><input type="checkbox" id="showdebug" value="1"><label for="showdebug">Show all websocket
|
||||
traffic</label></div>
|
||||
<div><input type="checkbox" id="showdebug" value="1"><label for="showdebug">Show all websocket traffic</label></div>
|
||||
</div>
|
||||
<ul id="messages" class="messages">
|
||||
</ul>
|
||||
@@ -287,8 +269,12 @@
|
||||
<option value="0" selected>EN English</option>
|
||||
<option value="1">NL Nederlands</option>
|
||||
<option value="2">DE Deutsch</option>
|
||||
<option value="4">FR French</option>
|
||||
<option value="3">NO Norwegian</option>
|
||||
<option value="4">FR Français</option>
|
||||
<option value="3">NO Norsk</option>
|
||||
<option value="5">CZ Čeština</option>
|
||||
<option value="6">SK Slovenčina</option>
|
||||
<option value="7">PL Polski</option>
|
||||
<option value="8">ES Español</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Depending on the content, a tag can sleep for
|
||||
@@ -313,7 +299,8 @@
|
||||
</select>
|
||||
</p>
|
||||
<p
|
||||
title="Stops updates at night, and put the tags to sleep. During the configured night time, this overrides the maximum sleep time.">
|
||||
title="Stops updates at night, and put the tags to sleep.
|
||||
During the configured night time, this overrides the maximum sleep time.">
|
||||
<label for="apcnight1">No updates between</label>
|
||||
<select id="apcnight1"></select>
|
||||
<span style="align-self:center;">and</span>
|
||||
@@ -327,6 +314,17 @@
|
||||
<option value="0">no</option>
|
||||
</select>
|
||||
</p>
|
||||
<p
|
||||
title="* Work in progress * When locking the tag inventory, the AP will only
|
||||
show tags that are already in the database. For now, the AP will still keep answering
|
||||
new tags, because that needs to be fixed in the radio firmware.
|
||||
This will probably change in the future.">
|
||||
<label for="apclock">Lock tag inventory</label>
|
||||
<select id="apclock">
|
||||
<option value="1">yes</option>
|
||||
<option value="0" selected>no</option>
|
||||
</select>
|
||||
</p>
|
||||
<p title="Wifi transmit power">
|
||||
<label for="apcwifipower">Wifi power</label>
|
||||
<select id="apcwifipower">
|
||||
@@ -394,8 +392,7 @@
|
||||
</p>
|
||||
<h3>Manage</h3>
|
||||
<p>
|
||||
<button type="button" id="rebootbutton">Reboot AP</button> Saves the tagDB and instantly reboots the Access
|
||||
Point
|
||||
<button type="button" id="rebootbutton">Reboot AP</button> Saves the tagDB and instantly reboots the Access Point
|
||||
</p>
|
||||
<p>
|
||||
<a href="/backup_db" id="downloadDBbutton">Download tagDB</a>
|
||||
@@ -404,15 +401,12 @@
|
||||
<button type="button" id="updatebutton" class="tablinks" data-target="updatetab" title="Update">Update</button> Manage firmware of the ESP32
|
||||
</p>
|
||||
<p>
|
||||
<a href="/setup" target="setup" class="wifibutton">WiFi config</a> Opens a new window with WiFi
|
||||
config options
|
||||
<a href="/setup" target="setup" class="wifibutton">WiFi config</a> Opens a new window with WiFi config options
|
||||
</p>
|
||||
<p>
|
||||
<br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink" target="_new">Github
|
||||
OpenEPaperLink</a><br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki" target="_new">OpenEPaperLink
|
||||
Wiki</a><br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink" target="_new">Github OpenEPaperLink</a><br>
|
||||
<a href="https://github.com/jjwbruijn/OpenEPaperLink/wiki" target="_new">OpenEPaperLink Wiki</a><br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -436,13 +430,16 @@
|
||||
<h4>Other actions</h4>
|
||||
<div>
|
||||
<p>
|
||||
<div id="rollbackOption" style="display:none"><button type="button" id="rollbackBtn">Rollback to previous
|
||||
firmware</button></div>
|
||||
<div id="rollbackOption" style="display:none">
|
||||
<button type="button" id="rollbackBtn">Rollback to previous firmware</button>
|
||||
</div>
|
||||
</p>
|
||||
<p>
|
||||
<span id="c6Option">
|
||||
<div id="updateC6Option"><button type="button" id="updateC6Btn">Update ESP32-C6</button> <input type="checkbox"
|
||||
value="1" checked id="c6download"> download latest version</div>
|
||||
<div id="updateC6Option">
|
||||
<button type="button" id="updateC6Btn">Update ESP32-C6</button>
|
||||
<input type="checkbox" value="1" checked id="c6download">download latest version
|
||||
</div>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
@@ -525,4 +522,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
@@ -590,6 +590,7 @@ document.addEventListener("loadTab", function (event) {
|
||||
$("#apclatency").value = data.maxsleep;
|
||||
$("#apcpreventsleep").value = data.stopsleep;
|
||||
$("#apcpreview").value = data.preview;
|
||||
$("#apclock").value = data.lock;
|
||||
$("#apcwifipower").value = data.wifipower;
|
||||
$("#apctimezone").value = data.timezone;
|
||||
$("#apcnight1").value = data.sleeptime1;
|
||||
@@ -614,6 +615,7 @@ $('#apcfgsave').onclick = function () {
|
||||
formData.append('maxsleep', $('#apclatency').value);
|
||||
formData.append('stopsleep', $('#apcpreventsleep').value);
|
||||
formData.append('preview', $('#apcpreview').value);
|
||||
formData.append('lock', $('#apclock').value);
|
||||
formData.append('wifipower', $('#apcwifipower').value);
|
||||
formData.append('timezone', $('#apctimezone').value);
|
||||
formData.append('sleeptime1', $('#apcnight1').value);
|
||||
@@ -858,7 +860,7 @@ function processQueue() {
|
||||
return;
|
||||
}
|
||||
const { id, imageSrc } = imageQueue.shift();
|
||||
const hwtype = $('#tag' + id).dataset.hwtype;
|
||||
const hwtype = $('#tag' + id).dataset?.hwtype;
|
||||
if (tagTypes[hwtype]?.busy) {
|
||||
imageQueue.push({ id, imageSrc });
|
||||
setTimeout(processQueue, 100);
|
||||
@@ -1076,7 +1078,7 @@ async function getTagtype(hwtype) {
|
||||
tagTypes[hwtype] = { busy: true };
|
||||
const response = await fetch('/tagtypes/' + hwtype.toString(16).padStart(2, '0').toUpperCase() + '.json');
|
||||
if (!response.ok) {
|
||||
let data = { name: 'unknown id ' + hwtype, width: 0, height: 0, bpp: 0, rotatebuffer: 0, colortable: [], busy: false };
|
||||
let data = { name: 'unknown id ' + hwtype.toString(16), width: 0, height: 0, bpp: 0, rotatebuffer: 0, colortable: [], busy: false };
|
||||
tagTypes[hwtype] = data;
|
||||
getTagtypeBusy = false;
|
||||
return data;
|
||||
@@ -1231,22 +1233,25 @@ $('#taglist').addEventListener('contextmenu', (e) => {
|
||||
if (clickedGridItem) {
|
||||
let mac = clickedGridItem.dataset.mac;
|
||||
const hwtype = clickedGridItem.dataset.hwtype;
|
||||
let contextMenuOptions = [
|
||||
{ id: 'refresh', label: 'Force refresh' },
|
||||
{ id: 'clear', label: 'Clear pending status' }
|
||||
];
|
||||
if (clickedGridItem.dataset.isexternal == "false") {
|
||||
let contextMenuOptions = [];
|
||||
if (tagTypes[hwtype]?.width > 0) {
|
||||
contextMenuOptions.push(
|
||||
{ id: 'scan', label: 'Scan channels' },
|
||||
{ id: 'reboot', label: 'Reboot tag' },
|
||||
);
|
||||
};
|
||||
if (tagTypes[hwtype].options?.includes("led")) {
|
||||
contextMenuOptions.push(
|
||||
{ id: 'ledflash', label: 'Flash the LED' },
|
||||
{ id: 'ledflash_long', label: 'Flash the LED (long)' },
|
||||
{ id: 'ledflash_stop', label: 'Stop flashing' }
|
||||
{ id: 'refresh', label: 'Force refresh' },
|
||||
{ id: 'clear', label: 'Clear pending status' }
|
||||
);
|
||||
if (clickedGridItem.dataset.isexternal == "false") {
|
||||
contextMenuOptions.push(
|
||||
{ id: 'scan', label: 'Scan channels' },
|
||||
{ id: 'reboot', label: 'Reboot tag' },
|
||||
);
|
||||
};
|
||||
if (tagTypes[hwtype]?.options?.includes("led")) {
|
||||
contextMenuOptions.push(
|
||||
{ id: 'ledflash', label: 'Flash the LED' },
|
||||
{ id: 'ledflash_long', label: 'Flash the LED (long)' },
|
||||
{ id: 'ledflash_stop', label: 'Stop flashing' }
|
||||
);
|
||||
}
|
||||
}
|
||||
contextMenuOptions.push(
|
||||
{ id: 'del', label: 'Delete tag from list' }
|
||||
|
||||
Reference in New Issue
Block a user