Gå til innhold
  • Bli medlem

Strømstyring i Node Red


Eirek
 Del

Anbefalte innlegg

God kveld.

 

Regner med at Node Red er såpass utbredt i Home Assistant at det faller inn i denne kategorien. Om jeg bommer er det bare på flytte posten 🙂

 

Jeg bruker Nordpool-integrasjonen i HA (og i Node Red) for å automatisere varmen/strømforbruk i forhold til timespris. På den måten unngår jeg å brenne av en del watt når prisen er som værst (slik som enkelte timer i dag og i morgen)

 

Dog føler jeg at jeg magler en del fleksibilitet (og kunnskap hos meg) knyttet til bruken av timesprising

 

Nordpool-integrasjonen fungerer sånn sett veldig bra, og jeg har allerede lagt inn logikk knyttet til "Low Price" og f.eks 90% av "low price". Denne logikken kjører kun de dagene hvor:

Prisen er over 0.25,- pr kWh og at det er en viss differanse mellom billigste og dyreste time. Ergo har jo dette ikke vært i bruk på lang tid pga de billige strømprisene vi har hatt i mange måneder.

 

Svakheten med min logikk, slik jeg ser det, er at når prisene er som i dag, så vil snittprisen bli såpass høy at de fleste timene er under snittprisen. Det betyr at varmen skrur seg på en pris/time som er langt fra den billigste, men som likevel er under snittprisen.

 

Jeg kunne ønske meg å få ut (i Node Red) f.eks billigste time (eller to timer, for den sak skyld) mellom 05:00 og 12:00. Tilsvarende for mellom f.eks 12:00 og 20:00) På den måten blir varmeproduksjonen såpass jevn at komforten blir uforandret. Uten denne logikken risikerer man f.eks at alle timer under snittpris er fra 01:00 til 07:00, og det er jo ikke så hensiktsmessig igjen. Nå er jo klokkeslettene bare noen eksempler, så antall timer og antall timer mellom to klokkeslett burde jo kunne endres etter behov.

 

Man kan jo også leke med tanken om at selv om f.eks 21:00 til 23:59 er "dyre" timer, så kan disse timene i enkelte tilfeller være langt billigere enn prisbildet i det man går over til neste dag. Ergo hadde det f.eks vært lønnsomt å fyre opp den billigste timen mellom 21:00 og 00:00 i stedet for å vente til f.eks 01:00

 

Jeg vet det er noe som heter Off peak 1 og Off peak 2 i Nordpool-integrasjonen, men denne gir for lite fleksibilitet i mine øyne.

 

Jeg kjenner jeg har for lite kunnskap rundt arrays, json og behandling av disse i Node Red 😞

Er det noen som har utforsket noen prinsipper rundt dette?

  • Like 1
Lenke til kommentar
Del på andre sider

Har ikke undersøkt akkurat det du ser etter, men har selv lagt inn priser fra Nordpool i NodeRed. Har ikke laget noe styring utifra dette igjen, men det jeg har gjort er å lage en regel om lav, middels eller høy timespris utifra standardavviket, og ikke bare prosentvis av gjennomsnittet. Bildet under er fra i dag, lørdag, for Kristiansandsregionen. Det andre bildet jeg la til nå er fra 1.desember til og med i morgen.

Strømprisen jeg går utifra er inkludert alt (nettleie, moms, elsertifikat osv).

Du kunne jo brukt dette igjen for å lage regler, enten enkle som at varme på bare når pris <= middels, og når pris <= lav, så setter du opp en grad, så du akkumulerer litt ekstra varme, men bare i 2 timer sammenhengende eller noe sånn.

Du kan jo også dele opp prisnivåene litt mer fint, så du har kanskje 5 nivåer, i stedenfor 3 som jeg har.
Hos meg er strømpris minus standardavvik definert som lav, og pris + stdavvik er høy. Alt annet er medium.

 

Skriver mest for å være med på laget når noen kloke hoder har gode ideer i denne tråde.

timespris.PNG

timespris_des.PNG

Endret av mongojarle
Lenke til kommentar
Del på andre sider

  • 5 måneder senere...

Tja, jeg kan jo egentlig ikke javscript altså, så alt kunne sikkert sett veldig mye bedre ut. Selv dytter jeg det som kommer ut av funksjonen inn i en influxDB.

Jeg bruker ikke dette selv lenger, da jeg tok et nederlag og gikk over til Tibber sin API og utregning.

 

[{"id":"3237d2ac.7f5d0e","type":"nordpool-api-plus","z":"8572bbae.6c2198","d":true,"name":"Power price","area":"Kr.sand","currency":"NOK","x":390,"y":380,"wires":[["e999179c.e69e38","d2bd8ed6.beb86"]]},{"id":"5d4eb802.61e768","type":"moment","z":"8572bbae.6c2198","name":"+1 day","topic":"","input":"","inputType":"date","inTz":"Europe/Oslo","adjAmount":"1","adjType":"days","adjDir":"add","format":"","locale":"en-GB","output":"date","outputType":"msg","outTz":"Europe/Oslo","x":230,"y":380,"wires":[["9410f18a.0194b","3237d2ac.7f5d0e"]]},{"id":"cbe6dc8a.c4e8","type":"timerswitch","z":"8572bbae.6c2198","name":"@13.00+1h","ontopic":"","offtopic":"","onpayload":"","offpayload":"","disabled":false,"schedules":[{"on_h":"13","on_m":"00","on_s":"00","off_h":"14","off_m":"00","off_s":"00","valid":true}],"x":90,"y":380,"wires":[["5d4eb802.61e768"]]},{"id":"1e32941e.54e1bc","type":"inject","z":"8572bbae.6c2198","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":340,"wires":[["5d4eb802.61e768"]]},{"id":"d2bd8ed6.beb86","type":"function","z":"8572bbae.6c2198","name":"Make array","func":"var i = 0;\nvar d = new Date();\nvar n = d.getMonth();\nvar temp = [];\nvar pricelist = [];\nvar pricestatus = [];\nvar pricelevel = [];\nvar avgPrice = 0;\nvar daysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nvar mva = 1.25;\nvar abbonnement = 39 / daysInMonth[n] / 24;\nvar elsertifikat = 0.0121;\nvar energiledd = 0.3579;\nvar fastledd = 312.5 / daysInMonth[n] / 24;\nvar highPrice = 1.25;\nvar lowPrice = 0.75;\nvar highLevel = 0;\nvar lowlevel = 0;\nvar squareDiff = [];\nvar sumSquareDiff = 0;\nvar avgSquareDiff = 0;\nvar stdDev = 0;\n\nif (msg.payload == null) {\n    return;\n}\n\n// Make list with price, all included\nfor (i = 0; i < msg.payload.length; i++) {\n    pricelist.push(\n        [msg.payload[i].price / 1000 * mva + elsertifikat + energiledd, \"price\", Date.parse(msg.payload[i].timestamp)]\n    )\n}\n\n// Make average price for day\nfor (i = 0; i < pricelist.length; i++) {\n    avgPrice = avgPrice + pricelist[i][0];\n}\navgPrice = avgPrice / pricelist.length;\n\n// Make the different pricelevels, for display or something...\nfor (i = 0; i < pricelist.length; i++) {\n    squareDiff[i] = Math.pow((pricelist[i][0] - avgPrice), 2);\n    sumSquareDiff = sumSquareDiff + squareDiff[i];\n}\navgSquareDiff = sumSquareDiff / squareDiff.length;\nstdDev = Math.sqrt(avgSquareDiff);\n\nhighLevel = avgPrice + stdDev;\nlowLevel = avgPrice - stdDev;\nfor (i=0; i < pricelist.length; i++) {\n    if (pricelist[i][0] < lowLevel) {\n        pricelevel.push(\n            [\"LOW\", \"price_level\", pricelist[i][2]]\n        )\n    } else if (pricelist[i][0] > highLevel) {\n        pricelevel.push(\n            [\"HIGH\", \"price_level\", pricelist[i][2]]\n        )\n    } else {\n        pricelevel.push(\n            [\"MEDIUM\", \"price_level\", pricelist[i][2]]\n        )\n    }\n}\n\nvar value_list = [\n        [avgPrice, \"price_avg\", pricelist[0][2]],\n        [highLevel, \"price_highLevel\", pricelist[0][2]],\n        [lowLevel, \"price_lowLevel\", pricelist[0][2]]\n    ];\n\nfor (i = 0; i < pricelist.length; i++) {\n    temp.push(\n        {\n            measurement: \"technical\",\n            fields: {\n                value: parseFloat(pricelist[i][0].toPrecision(6))\n            },\n            tags:{\n                area: \"electricity\",\n                type: pricelist[i][1]\n            },\n            timestamp: pricelist[i][2]\n        }\n    )\n}\nfor (i = 0; i < value_list.length; i++) {\n    temp.push(\n        {\n            measurement: \"technical\",\n            fields: {\n                value: parseFloat(value_list[i][0].toPrecision(6))\n            },\n            tags:{\n                area: \"electricity\",\n                type: value_list[i][1]\n            },\n            timestamp: value_list[i][2]\n        }\n    )\n}\nfor (i = 0; i < pricelevel.length; i++) {\n    temp.push(\n        {\n            measurement: \"status\",\n            fields: {\n                value: pricelevel[i][0].toString()\n            },\n            tags:{\n                area:\"electricity\",\n                type:pricelevel[i][1]\n            },\n            timestamp: pricelevel[i][2]\n        }\n    )\n}\nmsg.payload = temp;\nmsg.pricelist = pricelist;\nmsg.avgPrice = avgPrice;\nmsg.squareDiff = squareDiff;\nmsg.sumSquareDiff = sumSquareDiff;\nmsg.avgSquareDiff = avgSquareDiff;\nmsg.standardDeviation = stdDev;\nmsg.highLevel = highLevel;\nmsg.lowLevel = lowLevel;\n//msg.pricelevel = pricelevel;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":570,"y":380,"wires":[["54b2bba1.209ac4","7066b303.eb075c"]]}]

Du trenger også denne noden: https://flows.nodered.org/node/node-red-contrib-nordpool-api-plus

Lenke til kommentar
Del på andre sider

  • 2 uker senere...
  • 6 måneder senere...
mongojarle skrev (På 24.5.2021 den 19.40):
[{"id":"3237d2ac.7f5d0e","type":"nordpool-api-plus","z":"8572bbae.6c2198","d":true,"name":"Power price","area":"Kr.sand","currency":"NOK","x":390,"y":380,"wires":[["e999179c.e69e38","d2bd8ed6.beb86"]]},{"id":"5d4eb802.61e768","type":"moment","z":"8572bbae.6c2198","name":"+1 day","topic":"","input":"","inputType":"date","inTz":"Europe/Oslo","adjAmount":"1","adjType":"days","adjDir":"add","format":"","locale":"en-GB","output":"date","outputType":"msg","outTz":"Europe/Oslo","x":230,"y":380,"wires":[["9410f18a.0194b","3237d2ac.7f5d0e"]]},{"id":"cbe6dc8a.c4e8","type":"timerswitch","z":"8572bbae.6c2198","name":"@13.00+1h","ontopic":"","offtopic":"","onpayload":"","offpayload":"","disabled":false,"schedules":[{"on_h":"13","on_m":"00","on_s":"00","off_h":"14","off_m":"00","off_s":"00","valid":true}],"x":90,"y":380,"wires":[["5d4eb802.61e768"]]},{"id":"1e32941e.54e1bc","type":"inject","z":"8572bbae.6c2198","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":340,"wires":[["5d4eb802.61e768"]]},{"id":"d2bd8ed6.beb86","type":"function","z":"8572bbae.6c2198","name":"Make array","func":"var i = 0;\nvar d = new Date();\nvar n = d.getMonth();\nvar temp = [];\nvar pricelist = [];\nvar pricestatus = [];\nvar pricelevel = [];\nvar avgPrice = 0;\nvar daysInMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\nvar mva = 1.25;\nvar abbonnement = 39 / daysInMonth[n] / 24;\nvar elsertifikat = 0.0121;\nvar energiledd = 0.3579;\nvar fastledd = 312.5 / daysInMonth[n] / 24;\nvar highPrice = 1.25;\nvar lowPrice = 0.75;\nvar highLevel = 0;\nvar lowlevel = 0;\nvar squareDiff = [];\nvar sumSquareDiff = 0;\nvar avgSquareDiff = 0;\nvar stdDev = 0;\n\nif (msg.payload == null) {\n    return;\n}\n\n// Make list with price, all included\nfor (i = 0; i < msg.payload.length; i++) {\n    pricelist.push(\n        [msg.payload[i].price / 1000 * mva + elsertifikat + energiledd, \"price\", Date.parse(msg.payload[i].timestamp)]\n    )\n}\n\n// Make average price for day\nfor (i = 0; i < pricelist.length; i++) {\n    avgPrice = avgPrice + pricelist[i][0];\n}\navgPrice = avgPrice / pricelist.length;\n\n// Make the different pricelevels, for display or something...\nfor (i = 0; i < pricelist.length; i++) {\n    squareDiff[i] = Math.pow((pricelist[i][0] - avgPrice), 2);\n    sumSquareDiff = sumSquareDiff + squareDiff[i];\n}\navgSquareDiff = sumSquareDiff / squareDiff.length;\nstdDev = Math.sqrt(avgSquareDiff);\n\nhighLevel = avgPrice + stdDev;\nlowLevel = avgPrice - stdDev;\nfor (i=0; i < pricelist.length; i++) {\n    if (pricelist[i][0] < lowLevel) {\n        pricelevel.push(\n            [\"LOW\", \"price_level\", pricelist[i][2]]\n        )\n    } else if (pricelist[i][0] > highLevel) {\n        pricelevel.push(\n            [\"HIGH\", \"price_level\", pricelist[i][2]]\n        )\n    } else {\n        pricelevel.push(\n            [\"MEDIUM\", \"price_level\", pricelist[i][2]]\n        )\n    }\n}\n\nvar value_list = [\n        [avgPrice, \"price_avg\", pricelist[0][2]],\n        [highLevel, \"price_highLevel\", pricelist[0][2]],\n        [lowLevel, \"price_lowLevel\", pricelist[0][2]]\n    ];\n\nfor (i = 0; i < pricelist.length; i++) {\n    temp.push(\n        {\n            measurement: \"technical\",\n            fields: {\n                value: parseFloat(pricelist[i][0].toPrecision(6))\n            },\n            tags:{\n                area: \"electricity\",\n                type: pricelist[i][1]\n            },\n            timestamp: pricelist[i][2]\n        }\n    )\n}\nfor (i = 0; i < value_list.length; i++) {\n    temp.push(\n        {\n            measurement: \"technical\",\n            fields: {\n                value: parseFloat(value_list[i][0].toPrecision(6))\n            },\n            tags:{\n                area: \"electricity\",\n                type: value_list[i][1]\n            },\n            timestamp: value_list[i][2]\n        }\n    )\n}\nfor (i = 0; i < pricelevel.length; i++) {\n    temp.push(\n        {\n            measurement: \"status\",\n            fields: {\n                value: pricelevel[i][0].toString()\n            },\n            tags:{\n                area:\"electricity\",\n                type:pricelevel[i][1]\n            },\n            timestamp: pricelevel[i][2]\n        }\n    )\n}\nmsg.payload = temp;\nmsg.pricelist = pricelist;\nmsg.avgPrice = avgPrice;\nmsg.squareDiff = squareDiff;\nmsg.sumSquareDiff = sumSquareDiff;\nmsg.avgSquareDiff = avgSquareDiff;\nmsg.standardDeviation = stdDev;\nmsg.highLevel = highLevel;\nmsg.lowLevel = lowLevel;\n//msg.pricelevel = pricelevel;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":570,"y":380,"wires":[["54b2bba1.209ac4","7066b303.eb075c"]]}]

Super flow du har laget her.

Hvordan får du frem grafen du viser her?

Bruker du Influxdb og Grafana??

 

MVH

Jan Erik

Lenke til kommentar
Del på andre sider

14 minutes ago, Kvamsdal said:

Hei igjen mongojarle,

 

mangler det en funksjonsnode, eller gjør jeg noe galt?

har testet flowen din men får feilmeldinger på influxnoden.

 

ville bare høre med deg om du har en komplett flow som jeg kan teste?

 

MVH

Jan Erik

 

Jeg vet kanskje hva som skjer her. Skal være nok å bare sette på en influx node batch på utgangen av den function noden (batch fordi jeg skriver til forskjellige measurements). Men, jeg kjører influx 1.8.5, ikke 2.x.x... Grunnen til det er at jeg hadde så sinnsykt dårlig ytelse i influx2.

Se vedlagt bilde, det fungerer her.

Influx-noden er denne: https://flows.nodered.org/node/node-red-contrib-influxdb

influx_NR.png

Endret av mongojarle
Lenke til kommentar
Del på andre sider

Den +1day noden er en time/date formatter som bare legger på en dag... Den kan ersattes med en function node med dette innholdet:

let today = new Date();
let tomorrow = new Date();
tomorrow = Date.parse(today) + 86400*1000;

msg.date = new Date(tomorrow);
return msg;

Men den +1day noden heter uansett node-red-contrib-moment

Lenke til kommentar
Del på andre sider

mongojarle skrev (23 timer siden):

Den +1day noden er en time/date formatter som bare legger på en dag... Den kan ersattes med en function node med dette innholdet:

let today = new Date();
let tomorrow = new Date();
tomorrow = Date.parse(today) + 86400*1000;

msg.date = new Date(tomorrow);
return msg;

Men den +1day noden heter uansett node-red-contrib-moment

Jeg har den, men hoppet over den noden og brukte kun timestamp.

resultatet ble som du ser på bildet noen merkelige verdier.

Egentlig ikke så merkelige men det er 27 av dem i "technical" men 24 verdier i "status" etter kun 1 inject??

Har du noe fornuftig svar på det også?

Hjemme hos meg har vi bare 24 timer i døgnet :-).

Jeg tror nok jeg må justere prisene på fastavgifter og nettleie, men det går nok greit.

 

Den lykkelige eier av råferske data sliter også med å få frem noe fornuftig i grafana også. 

Finner liksom ikke helt ut av hvor jeg henter "value" dataene. Kan bare velge area eller type.

 

Jan Erik

20220113_192426.jpg

Lenke til kommentar
Del på andre sider

De 3 extra verdiene er jo pga oppføring av "price_avg", "price_highLevel" og "price_lowLevel" :-)

 

men jeg får ikke frem prisene i grafana? Jeg kan bare velge "area og type" i technical tabellen?

 

Noen som har et hint å komme med så takker jeg for det.

 

Jan Erik

Lenke til kommentar
Del på andre sider

Jobb eller ei, godt øl har de der i hvertfall, men styr unna coronaen den har jeg hørt ikke er så god :-o

 

Jeg kan velge price men det kommer ikke noe data i grafana bortsett fra dao og klokkeslett.

Skal det ikke gå an å hente ut prisene fra "value" kolonnen?

Etter valg av "prise" i FROM feltet kan jeg bare velge "area" og "type" men ikke "value".

Som du ser på bildet har jeg 4 valg i type feltet.

kan kun velge fill(null) i GROUP BY hvor du har fill(previous).

Bruker kanskje feil "visualization" også men uansett hvilen av de tilgjengelige blir resultatet det samme (ingen data)

Grafana.jpg

Lenke til kommentar
Del på andre sider

Okei, først tror jeg du må velge graph. Vet ikke hvorfor, bare gjør det :P

Value velges "automatisk", på SELECT der.

Så, får å få prisen til å være trappetrinn, så MÅ du ha inne alle disse parameterne som du ser på bildet mitt. Hvis du mangler en, så får du ikke opp noe.

 

For en graf som er "fjelltopper", så kan du ta vekk alt, bortsett fra value (som du heller ikke får lov til å ta vekk).

 

Jeg sitter på en båt her på Las Palmas, får ikke lov til å gå i land... så ingen øl, ingen morro, bare jobb.

trapp.png

fjell.png

Lenke til kommentar
Del på andre sider

Jeg har nok en annen versjon av grafana enn det du har, så jeg downgraded fra 8.3.3 til 7.5.12.

Fremdeles ingen data.

I og med at du har 'variablePricelist' og jeg har kun 'pris' er det da en liten variasjon i Node-Red som gjør at dataene ikke kommer inn i Influx på samme måte?

Jeg legger ved filene som jeg bruker, kanskje du klarer å finne ut av det.

 

Jan Erik 

Node-Red_Flow.json grafana_7.5.12_dashboard.json

Lenke til kommentar
Del på andre sider

Hm... Ikke noe galt i flowen som jeg kan se, og heller ikke i grafana. Bildet under er din config, eneste er at jeg byttet ut price med variablePricelist, siden jeg ikke har noe i min database som heter price.

Og du har jo tydeligvis noe data i databasen din, det viste du jo bilde av tidligere. Så da lurer jeg på om det er connection fra grafana til influx som ikke funker helt. Hvilken versjon av influx har du? Har du fått hentet noe annet til grafana fra influx?

Hvis du trykker på query inspector, trykker refresh, hvor mange linjer får du ut da? I bilde 2 har jeg 1009 resultater...

 

Jeg kan forresten anbefale dette lille programmet om du har pre-2.0 influxDB: https://github.com/CymaticLabs/InfluxDBStudio

grafaaaana.png

qinspector.png

Lenke til kommentar
Del på andre sider

Influx 1.8.5 i docker på en synology NAS.

Jeg kjører alt her på samme maskin. Vet ærlig talt ikke hvorfor det ikke fungerer for deg... Hvis det er forskjellige maskiner du kjører grafana og influx på, kan det være noe brannmur eller andre kommunikasjons-problemer?

ds.png

Lenke til kommentar
Del på andre sider

Ja, der ser jeg feilen... Du har lagt strømprisen inn i databasen uten timestamp, eller i hvertfall med timestamp i 1970... Så i grafana, hvis du velger der 1.januar 1970, kanskje du får noe opp der da. Skal se på koden i nodered igjen, det skal jo komme derfra. Gi meg et par minutter.

 

Function noden fungerer den, det kommer ut med riktig timestamp der. Så hvis du i influx noden din trykker advanced, og så setter time precision til milliseconds. Prøv det.

Endret av mongojarle
Lenke til kommentar
Del på andre sider

Bli med i samtalen

Du kan publisere innhold nå og registrere deg senere. Hvis du har en konto, logg inn nå for å poste med kontoen din.

Gjest
Skriv svar til emnet...

×   Du har limt inn tekst med formatering.   Lim inn uten formatering i stedet

  Du kan kun bruke opp til 75 smilefjes.

×   Lenken din har blitt bygget inn på siden automatisk.   Vis som en ordinær lenke i stedet

×   Tidligere tekst har blitt gjenopprettet.   Tøm tekstverktøy

×   Du kan ikke lime inn bilder direkte. Last opp eller legg inn bilder fra URL.

 Del

×
×
  • Opprett ny...