From f308359fbd419045146155843a360b2f50ad89fa Mon Sep 17 00:00:00 2001 From: Jussi Isotalo Date: Sun, 5 Nov 2023 09:38:05 +0200 Subject: [PATCH] ## [2.7.0] - 05.11.2023 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Uusi ominaisuus: automaattinen aikavyöhyke (eli myös autom. kesä/talviaika) - Shelly laskee aikaeron UTC-ajan ja paikallisen ajan välillä -> Käytetään aina oikeaa aikavyöhykettä hintojen haussa - Jos aikaero muuttuu, haetaan hinnat uusiksi (esim. kun kesä/talviaika vaihtuu) - Lisätiedot: [Issue #7](https://github.com/jisotalo/shelly-porssisahko/issues/7) - Firmware-vaatimus on 1.0.7. Vanhemmille ei luvata tukea. - Tässä firmisversiossa parannettiin skriptien muistinhallintaa --- CHANGELOG.md | 14 ++++++++++ README.md | 9 +++++-- dist/shelly-porssisahko.js | 2 +- shelly-builder.js | 2 +- shelly-library.json | 7 ++++- src/shelly-porssisahko.js | 55 ++++++++++++++++++++++++++++++++++---- 6 files changed, 79 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25d3289..ddc1610 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). # Suomeksi +## [2.7.0] - 05.11.2023 +- Uusi ominaisuus: automaattinen aikavyöhyke (eli myös autom. kesä/talviaika) + - Shelly laskee aikaeron UTC-ajan ja paikallisen ajan välillä -> Käytetään aina oikeaa aikavyöhykettä hintojen haussa + - Jos aikaero muuttuu, haetaan hinnat uusiksi (esim. kun kesä/talviaika vaihtuu) + - Lisätiedot: [Issue #7](https://github.com/jisotalo/shelly-porssisahko/issues/7) +- Firmware-vaatimus on 1.0.7. Vanhemmille ei luvata tukea. + - Tässä firmisversiossa parannettiin skriptien muistinhallintaa + ## [2.6.1] - 29.10.2023 - Bugikorjaus: Pikainen paikkaus jotta toimii kellojen siirron jälkeen - Koodiin on valitettavasti unohtunut kiinteä aikavyöhyke @@ -69,6 +77,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Versio 2 julkaistu (tehty täysin uusiksi) # In English +## [2.7.0] - 05.11.2023 +- New feature: automatic timezone detection (also automatic DST) + - Calculating time difference between UTC and local time -> if time difference changes, prices are updated + - Handles changing of DST automatically +- Firmware requirement: 1.0.7 or newer + ## [2.6.1] - 29.10.2023 - Bugfix: Quick patch to fix problem with DST - Better fix under development diff --git a/README.md b/README.md index 8672d00..de9761d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ [![License](https://img.shields.io/badge/License-AGPLv3-orange)](https://choosealicense.com/licenses/agpl-3.0/) [![GitHub](https://img.shields.io/badge/View%20on-GitHub-brightgreen)](https://github.com/jisotalo/shelly-porssisahko) [![Support](https://img.shields.io/badge/Support_with-PayPal-yellow)](https://www.paypal.com/donate/?business=KUWBXXCVGZZME&no_recurring=0¤cy_code=EUR) - + + + *In English - see bottom of the page.* Shelly-laitteisiin selaimella ohjattava pörssisähkösovellus, joka venyttää laitteen skriptien rajoja. Pyörittää käyttöliittymää omalla web-serverillä ja tallentaa asetuksensa Shellyn muistiin. @@ -59,7 +61,10 @@ Käyttää suoraan Viron kantaverkkoyhtiön [elering.ee](https://dashboard.eleri Katso päivitysten sisältö [CHANGELOG.md-tiedostosta](https://github.com/jisotalo/shelly-porssisahko/blob/master/CHANGELOG.md). ## Asennus -1. Ota Shelly käyttöön, yhdistä se wifi-verkkoon ja päivitä sen firmware (ainakin varmista että se on 1.0.0 tai uudempi) +1. Ota Shelly käyttöön, yhdistä se wifi-verkkoon ja päivitä sen firmware. + + **HUOMIO: Firmware 1.0.7 tai uudempi vaaditaan versiosta 2.7.0 eteenpäin.** + 2. Valinnainen: Laita **Websocket debug** päälle (Settings -> Debug -> Enable websocket debug). Näin näet suoraan hallintapaneelin osoitteen skriptin alla. 3. Avaa **Scripts**-sivu Shellyn hallinnasta. Poista olemassaolevat skriptit, jos niitä on. 4. Paina **Library**-painiketta diff --git a/dist/shelly-porssisahko.js b/dist/shelly-porssisahko.js index faddff7..6fa3012 100644 --- a/dist/shelly-porssisahko.js +++ b/dist/shelly-porssisahko.js @@ -1 +1 @@ -let C_HIST=24,C_ERRC=3,C_ERRD=120,C_DEF={mode:0,m0:{cmd:0},m1:{lim:0},m2:{per:24,cnt:0,lim:-999,sq:0,m:999},vat:24,day:0,night:0,bk:0,err:0,out:0,fh:0,inv:0},a={s:{v:"2.6.1",st:0,cmd:0,chkTs:0,errCnt:0,errTs:0,upTs:0,timeOK:0,configOK:0,fCmdTs:0,p:{ts:0,now:0,low:0,high:0,avg:0}},p:[],h:[],c:C_DEF},l=!1,i=!1;function o(t,e){e-=t;return 0<=e&&e<3600}function c(t){return Math.floor((t?t.getTime():Date.now())/1e3)}function n(t,e,s){let n=t.toString();for(;n.length=C_ERRC&&c(t)-a.s.errTs=C_ERRC&&(a.s.errCnt=0);return e}()){let e=new Date;try{let t=e.getFullYear()+"-"+n(e.getMonth()+1,2,"0")+"-"+n(f(e),2,"0")+"T00:00:00%2b02:00";var s=t.replace("T00:00:00","T23:59:59");let l={url:"https://dashboard.elering.ee/api/nps/price/csv?fields=fi&start="+t+"&end="+s,timeout:5,ssl_ca:"*"};e=null,t=null,Shelly.call("HTTP.GET",l,function(e,t,s){l=null;try{if(0!==t||null==e||200!==e.code||!e.body_b64)throw new Error("conn.err ("+s+") "+JSON.stringify(e));{e.headers=null,s=e.message=null,a.p=[],a.s.p.high=-999,a.s.p.low=999,e.body_b64=atob(e.body_b64),e.body_b64=e.body_b64.substring(e.body_b64.indexOf("\n")+1);let t=0;for(;0<=t;){e.body_b64=e.body_b64.substring(t);var n=[t=0,0];if(0===(t=e.body_b64.indexOf('"',t)+1))break;n[0]=Number(e.body_b64.substring(t,e.body_b64.indexOf('"',t))),t=e.body_b64.indexOf('"',t)+2,t=e.body_b64.indexOf(';"',t)+2,n[1]=Number(e.body_b64.substring(t,e.body_b64.indexOf('"',t)).replace(",",".")),n[1]=n[1]/10*(100+(0a.s.p.high&&(a.s.p.high=n[1]),n[1]("avg"==a.c.m2.m?a.s.p.avg:a.c.m2.m)&&(i=!1,a.s.st=11)):a.s.timeOK?(a.s.st=7,t=1<=C_HIST;)a.h.splice(0,1);a.h.push([c(),i?1:0]),n&&n(!0)}else n&&n(!1)},s)}catch(t){m(t),l=!1}}let g=0,h=0,p=0;function v(){var e=c();for(let t=0;t=C_ERRC&&c(t)-a.s.errTs=C_ERRC&&(a.s.errCnt=0);return s}()){let s=new Date;f(s);try{let t=s.getFullYear()+"-"+r(1+s.getMonth(),2,"0")+"-"+r(u(s),2,"0")+"T00:00:00"+a.s.tz;var e=t.replace("T00:00:00","T23:59:59");let l={url:"https://dashboard.elering.ee/api/nps/price/csv?fields=fi&start="+t+"&end="+e,timeout:5,ssl_ca:"*"};s=null,t=null,Shelly.call("HTTP.GET",l,function(s,t,e){l=null;try{if(0!==t||null==s||200!==s.code||!s.body_b64)throw Error("conn.err ("+e+") "+JSON.stringify(s));{s.headers=null,e=s.message=null,a.p=[],a.s.p.high=-999,a.s.p.low=999,s.body_b64=atob(s.body_b64),s.body_b64=s.body_b64.substring(1+s.body_b64.indexOf("\n"));let t=0;for(;0<=t;){s.body_b64=s.body_b64.substring(t);var r=[t=0,0];if(0===(t=1+s.body_b64.indexOf('"',t)))break;r[0]=+s.body_b64.substring(t,s.body_b64.indexOf('"',t)),t=2+s.body_b64.indexOf('"',t),t=2+s.body_b64.indexOf(';"',t),r[1]=+(""+s.body_b64.substring(t,s.body_b64.indexOf('"',t)).replace(",",".")),r[1]=r[1]/10*(100+(0a.s.p.high&&(a.s.p.high=r[1]),r[1]("avg"==a.c.m2.m?a.s.p.avg:a.c.m2.m)&&(o=!1,a.s.st=11)):a.s.timeOK?(a.s.st=7,t=1<=C_HIST;)a.h.splice(0,1);a.h.push([c(),o?1:0]),r&&r(!0)}else r&&r(!1)},e)}catch(t){m(t),l=!1}}let A=0,h=0,v=0;function S(){var s=c();for(let t=0;t { 'DBG', 'me' ], - //unsafe: true + unsafe: true }, }); diff --git a/shelly-library.json b/shelly-library.json index 60b8c61..13932cf 100644 --- a/shelly-library.json +++ b/shelly-library.json @@ -2,6 +2,11 @@ { "fname": "dist/shelly-porssisahko.js", "title": "Pörssisähköohjaus (shelly-porssisahko.js)", - "description": "Pörssisähköohjaus Shellyyn. Klikaa Insert code -painiketta skriptin asentamiseksi. Github-sivu: https://github.com/jisotalo/shelly-porssisahko" + "description": "Pörssisähköohjaus Shellyyn (uusin versio - firmware 1.0.7 tai uudempi). Klikaa Insert code -painiketta skriptin asentamiseksi. Github-sivu: https://github.com/jisotalo/shelly-porssisahko" + }, + { + "fname": "https://raw.githubusercontent.com/jisotalo/shelly-porssisahko/v.2.6.1/dist/shelly-porssisahko.js", + "title": "Pörssisähköohjaus v. 2.6.1 (shelly-porssisahko.js)", + "description": "VANHA VERSIO 2.6.1. Tukee firmwareja 1.0.0-1.0.6." } ] \ No newline at end of file diff --git a/src/shelly-porssisahko.js b/src/shelly-porssisahko.js index 0785cf7..5a1f899 100644 --- a/src/shelly-porssisahko.js +++ b/src/shelly-porssisahko.js @@ -82,7 +82,7 @@ let C_DEF = { let _ = { s: { /** version number */ - v: "2.6.1", + v: "2.7.0", /** status as number */ st: 0, /** active command */ @@ -101,6 +101,8 @@ let _ = { configOK: 0, /** If forced manually to ON, then this is the timestamp until cmd shall be on */ fCmdTs: 0, + /** Active time zone as string (URL encoded - such as %2b02:00 = +02:00)*/ + tz: "%2b02:00", /** current price info */ p: { /** time when prices were read */ @@ -176,6 +178,46 @@ function getDate(dt) { return dt.getDate(); } +/** + * Updates current timezone to state as hh:mm string format (url encoded) + * For example if UTC time is 04:55 and local time is 06:55, tz is %2b02:00 + * + * NOTE: Technically incorrect, only handles timezones with full hour offsets + * + * @param {Date} now Current time + * @returns + */ +function updateTz(now) { + //Get UTC time as string (e.g. Sun, 29 Oct 2023 04:55:00 GMT) + let utc = now.toUTCString(); + + //Extract time from UTC time string (e.g. "04:55:00 GMT") + utc = utc.substring(utc.indexOf("" + now.getFullYear()) + 5); + + //Extract hours (e.g. "04") + utc = Number(utc.substring(0, utc.indexOf(":"))); + + //Calculate time difference + let diff = now.getHours() - utc; + + let tz = padStart(Math.abs(diff), 2, "0") + ":00"; + + if (diff < 0) { + tz = "-" + tz; + } else if (diff > 0) { + tz = "%2b" + tz; + } else { + tz = "Z"; + } + + if (tz !== _.s.tz) { + //Timezone has changed -> we should get prices + _.s.p.ts = 0; + } + + _.s.tz = tz; +} + /** * Adds new log line row * @param {*} str @@ -372,6 +414,7 @@ function logicRunNeeded() { */ function getPrices() { let now = new Date(); + updateTz(now); try { //let me = "getPrices()"; @@ -383,7 +426,7 @@ function getPrices() { + "-" + padStart(getDate(now), 2, "0") + "T00:00:00" - + "%2b02:00"; + + _.s.tz; let end = start.replace("T00:00:00", "T23:59:59"); @@ -399,7 +442,6 @@ function getPrices() { end = null; //log("URL:" + req.url, me); - Shelly.call("HTTP.GET", req, function (res, err, msg) { req = null; @@ -529,6 +571,7 @@ function getPrices() { logic(); }); + } catch (err) { log(err); //Run logic no matter what happened @@ -536,6 +579,7 @@ function getPrices() { } } + /** * Sets relay output to cmd * If callback given, its called with success status, like cb(true) @@ -577,8 +621,9 @@ function setRelay(cb) { function logic() { //let me = "logic()"; let now = new Date(); + updateTz(now); cmd = false; - + try { if (_.s.timeOK && (_.s.p.ts > 0 && getDate(new Date(_.s.p.ts * 1000)) === getDate(now))) { //We have time and we have price data for today @@ -687,7 +732,7 @@ function logic() { * This worked! * */ -let _perStart = 0; +let _perStart = 0; let _ind = 0; let _ind2 = 0; function isCheapestHour() {