diff --git a/ConfigSettings.h b/ConfigSettings.h index 3455678..d01f252 100644 --- a/ConfigSettings.h +++ b/ConfigSettings.h @@ -3,7 +3,7 @@ #ifndef configsettings_h #define configsettings_h -#define FW_VERSION "v2.1.10" +#define FW_VERSION "v2.2.0" enum DeviceStatus { DS_OK = 0, DS_ERROR = 1, diff --git a/GitOTA.cpp b/GitOTA.cpp index 850b437..66f9ed0 100644 --- a/GitOTA.cpp +++ b/GitOTA.cpp @@ -46,7 +46,7 @@ bool GitRelease::toJSON(JsonObject &obj) { } #define ERR_CLIENT_OFFSET -50 -int8_t GitRepo::getReleases(uint8_t num) { +int16_t GitRepo::getReleases(uint8_t num) { WiFiClientSecure *client = new WiFiClientSecure; if(client) { client->setInsecure(); @@ -63,8 +63,8 @@ int8_t GitRepo::getReleases(uint8_t num) { strcpy(main->version.name, "main"); strcpy(main->name, "Main"); if(https.begin(*client, url)) { - Serial.print("[HTTPS] GET...\n"); int httpCode = https.GET(); + Serial.printf("[HTTPS] GET... code: %d\n", httpCode); if(httpCode > 0) { int len = https.getSize(); Serial.printf("[HTTPS] GET... code: %d - %d\n", httpCode, len); @@ -154,6 +154,7 @@ int8_t GitRepo::getReleases(uint8_t num) { } https.end(); } + delete client; } return 0; } @@ -201,9 +202,13 @@ void GitUpdater::checkForUpdate() { GitRepo repo; this->lastCheck = millis(); this->updateAvailable = false; - if(repo.getReleases(2) == 0) { // Get 2 releases so we can filter our pre-releases + this->error = repo.getReleases(2); + if(this->error == 0) { // Get 2 releases so we can filter our pre-releases this->setCurrentRelease(repo); } + else { + this->emitUpdateCheck(); + } this->status = GIT_STATUS_READY; } void GitUpdater::setCurrentRelease(GitRepo &repo) { diff --git a/GitOTA.h b/GitOTA.h index 241e8c5..973397f 100644 --- a/GitOTA.h +++ b/GitOTA.h @@ -28,7 +28,7 @@ class GitRelease { class GitRepo { public: - int8_t getReleases(uint8_t num = GIT_MAX_RELEASES); + int16_t getReleases(uint8_t num = GIT_MAX_RELEASES); GitRelease releases[GIT_MAX_RELEASES + 1]; bool toJSON(JsonObject &obj); }; @@ -39,7 +39,7 @@ class GitUpdater { bool updateAvailable = false; appver_t latest; bool cancelled = false; - int8_t error = 0; + int16_t error = 0; char targetRelease[32]; char currentFile[64] = ""; char baseUrl[128] = ""; diff --git a/Network.cpp b/Network.cpp index e3e6390..c67878f 100644 --- a/Network.cpp +++ b/Network.cpp @@ -326,7 +326,7 @@ bool Network::connectWiFi() { case WL_NO_SSID_AVAIL: Serial.print(" Connection failed the SSID "); Serial.print(settings.WIFI.ssid); - Serial.print(" could not be found"); + Serial.println(" could not be found"); return false; default: break; @@ -497,10 +497,7 @@ void Network::networkEvent(WiFiEvent_t event) { Serial.println("WiFi AP Started"); break; case ARDUINO_EVENT_WIFI_STA_START: - Serial.println("WiFi STA Started"); if(settings.hostname[0] != '\0') WiFi.setHostname(settings.hostname); - Serial.print("Set hostname event to:"); - Serial.println(WiFi.getHostname()); break; case ARDUINO_EVENT_WIFI_STA_CONNECTED: break; diff --git a/Somfy.cpp b/Somfy.cpp index 9a58852..e5b7c82 100644 --- a/Somfy.cpp +++ b/Somfy.cpp @@ -785,6 +785,7 @@ bool SomfyRemote::hasLight() { return (this->flags & static_cast(somfy_ void SomfyRemote::setSunSensor(bool bHasSensor ) { bHasSensor ? this->flags |= static_cast(somfy_flags_t::SunSensor) : this->flags &= ~(static_cast(somfy_flags_t::SunSensor)); } void SomfyRemote::setLight(bool bHasLight ) { bHasLight ? this->flags |= static_cast(somfy_flags_t::Light) : this->flags &= ~(static_cast(somfy_flags_t::Light)); } void SomfyGroup::updateFlags() { + uint8_t oldFlags = this->flags; this->flags = 0; for(uint8_t i = 0; i < SOMFY_MAX_GROUPED_SHADES; i++) { if(this->linkedShades[i] != 0) { @@ -793,6 +794,7 @@ void SomfyGroup::updateFlags() { } else break; } + if(oldFlags != this->flags) this->emitState(); } bool SomfyShade::isInGroup() { if(this->getShadeId() == 255) return false; @@ -2107,14 +2109,14 @@ void SomfyShade::processInternalCommand(somfy_commands cmd, uint8_t repeat) { } break; case somfy_commands::Flag: + this->p_sunFlag(false); if(this->hasSunSensor()) { - this->p_sunFlag(false); - //this->flags &= ~(static_cast(somfy_flags_t::SunFlag)); somfy.isDirty = true; this->emitState(); } - else + else { Serial.printf("Shade does not have sensor %d\n", this->flags); + } break; case somfy_commands::SunFlag: if(this->hasSunSensor()) { diff --git a/SomfyController.ino.esp32.bin b/SomfyController.ino.esp32.bin index ccbe722..d11197e 100644 Binary files a/SomfyController.ino.esp32.bin and b/SomfyController.ino.esp32.bin differ diff --git a/SomfyController.littlefs.bin b/SomfyController.littlefs.bin index 88d6d5c..96d6f61 100644 Binary files a/SomfyController.littlefs.bin and b/SomfyController.littlefs.bin differ diff --git a/data/appversion b/data/appversion index 41bb57b..e3a4f19 100644 --- a/data/appversion +++ b/data/appversion @@ -1 +1 @@ -2.1.10 \ No newline at end of file +2.2.0 \ No newline at end of file diff --git a/data/index.html b/data/index.html index 0f89584..a3df51a 100644 --- a/data/index.html +++ b/data/index.html @@ -3,11 +3,11 @@ - - - + + + - +
diff --git a/data/index.js b/data/index.js index 4c4b641..cddbb5c 100644 --- a/data/index.js +++ b/data/index.js @@ -977,6 +977,23 @@ class UIBinder { div.querySelector('#btnYes').addEventListener('click', onYes); return div; } + infoMessage(el, msg, onOk) { + if (arguments.length === 1) { + onOk = msg; + msg = el; + el = document.getElementById('divContainer'); + } + let div = document.createElement('div'); + div.innerHTML = '
' + msg + '
'; + div.classList.add('info-message'); + div.classList.add('message-overlay'); + el.appendChild(div); + if (typeof onOk === 'function') div.querySelector('#btnOk').addEventListener('click', onOk); + else div.querySelector('#btnOk').addEventListener('click', (e) => { div.remove() }); + //div.querySelector('#btnYes').addEventListener('click', onYes); + return div; + + } clearErrors() { let errors = document.querySelectorAll('div.message-overlay'); if (errors && errors.length > 0) errors.forEach((el) => { el.remove(); }); @@ -1235,7 +1252,7 @@ var security = new Security(); class General { initialized = false; - appVersion = 'v2.1.10'; + appVersion = 'v2.2.0'; reloadApp = false; init() { if (this.initialized) return; @@ -2444,7 +2461,7 @@ class Somfy { } divCtl += ''; divCtl += `
`; - divCtl += `
`; + divCtl += `
`; divCtl += `
`; divCtl += `
my
`; divCtl += `
`; @@ -2648,7 +2665,7 @@ class Somfy { let flags = document.querySelectorAll(`.button-sunflag[data-groupid="${state.groupId}"]`); for (let i = 0; i < flags.length; i++) { flags[i].style.display = state.sunSensor ? '' : 'none'; - flags[i].setAttribute('data-on', state.flags & 0x01 === 0x01 ? 'true' : 'false'); + flags[i].setAttribute('data-on', state.flags & 0x20 === 0x20 ? 'true' : 'false'); } } procShadeState(state) { @@ -4180,12 +4197,12 @@ class Firmware { div.style.alignContent = 'center'; let html = `
Select a version from the repository to install using the dropdown below. Then press the update button to install that version.
Select Main to install the most recent alpha version from the repository.
`; html += `
`; - html += `` for (let i = 0; i < rel.releases.length; i++) { html += `` } - html += ``; - html += '
'; + html += `
`; + html += ``; if (this.isMobile()) { html += `
WARNING
`; html += '
This browser does not support automatic backups. It is highly recommended that you back up your configuration using the backup button before proceeding.
'; @@ -4204,10 +4221,104 @@ class Firmware { div.innerHTML = html; document.getElementById('divContainer').appendChild(div); + this.gitReleaseSelected(div); } }); } + gitReleaseSelected(div) { + let obj = ui.fromElement(div); + let divNotes = div.querySelector('#divReleaseNotes'); + if (divNotes) { + if (!obj.version || obj.version === 'main' || obj.version === '') divNotes.style.display = 'none'; + else divNotes.style.display = ''; + } + } + async getReleaseInfo(tag) { + let overlay = ui.waitMessage(document.getElementById('divContainer')); + try { + let ret = {}; + ret.resp = await fetch(`https://api.github.com/repos/rstrouse/espsomfy-rts/releases/tags/${tag}`); + if (ret.resp.ok) + ret.info = await ret.resp.json(); + return ret; + } + catch (err) { + return { err: err }; + } + finally { overlay.remove(); } + } + async showReleaseNotes(tagName) { + console.log(tagName); + let r = await this.getReleaseInfo(tagName); + console.log(r); + let fnToItem = (txt, tag) => { } + if (r.resp.ok) { + // Convert this to html. + let lines = r.info.body.split('\r\n'); + let ctx = { html: '', llvl: 0, lines: r.info.body.split('\r\n'), ndx: 0 }; + ctx.toHead = function (txt) { + let num = txt.indexOf(' '); + return `${txt.substring(num).trim()}`; + }; + ctx.toUL = function () { + let txt = this.lines[this.ndx++]; + let tok = this.token(txt); + this.html += `
    ${this.toLI(tok.txt)}`; + while (this.ndx < this.lines.length) { + txt = this.lines[this.ndx]; + let t = this.token(txt); + if (t.ch === '*') { + if (t.indent !== tok.indent) this.toUL(); + else { + this.html += this.toLI(t.txt); + this.ndx++; + } + } + else break; + } + this.html += '
'; + }; + ctx.toLI = function (txt) { return `
  • ${txt.trim()}
  • `; } + ctx.token = function (txt) { + let tok = { ch: '', indent: 0, txt:'' } + for (let i = 0; i < txt.length; i++) { + if (txt[i] === ' ') tok.indent++; + else { + tok.ch = txt[i]; + let tmp = txt.substring(tok.indent); + tok.txt = tmp.substring(tmp.indexOf(' ')); + break; + } + } + return tok; + }; + ctx.next = function () { + if (this.ndx >= this.lines.length) return false; + let tok = this.token(this.lines[this.ndx]); + switch (tok.ch) { + case '#': + this.html += this.toHead(this.lines[this.ndx]); + this.ndx++; + break; + case '*': + this.toUL(); + break; + case '': + this.ndx++; + this.html += `
    ${tok.txt}
    `; + break; + default: + this.ndx++; + break; + } + return true; + }; + while (ctx.next()); + console.log(ctx); + ui.infoMessage(ctx.html); + } + } updateFirmware() { let div = this.createFileUploader('/updateFirmware'); let inst = div.querySelector('div[id=divInstText]'); diff --git a/data/main.css b/data/main.css index 646b153..a668fe5 100644 --- a/data/main.css +++ b/data/main.css @@ -218,6 +218,7 @@ a { bottom: 7px; border-bottom: 1px solid #00bcd4; } +div.info-message, div.prompt-message, div.error-message { position:absolute; diff --git a/data/widgets.css b/data/widgets.css index db15c0b..ebeeec6 100644 --- a/data/widgets.css +++ b/data/widgets.css @@ -54,6 +54,12 @@ padding-bottom: 2px; min-height: 147px; } +.info-message .info-text { + text-align:left; + font-size:14px; + max-height:calc(100% - 77px); + overflow:auto; +} .prompt-message .sub-message { font-size: 17px; padding-left: 10px;