Unngå høyt Effektleddet ved å redusere temperaturen på termostater

Jeg forsøker programmere et system som skal forhindre at forbruket i boligen kommer over 10KW pr. time.

Har laget en Flow som leser fra akkumulert energi fra Tiber pulse. Planen er da å senke temperaturen på gulvvarme etter en prioritert liste.

Da ønsker jeg å lese hvilke temperatur termostaten er satt til redusere med f.eks. 3 grader og skrive tilbake. I det vedlagte programmet er dette forsøkt.

  • Leser SET Punktet fra termostaten. (ch1)
  • Skriver denne temperaturen til den globale variablen «Bad_2etg_Temp_float»
  • En transform som subtraherer 3 fra variablene og skrivere verdien tilbake.

Koden frem til dette fungerer :blush:

Deretter blir jobben å bygge en «strMAP» og skrive denne tilbake til termostaten. Dette fungerer IKKE :frowning:

I listen over variabler kan man ikke se innholdet av «map of string», så jeg er usikker på om dette fungerer.

Ser jo i «Transform» som skal bygge «map of string» at det er et rødt X, det er vel ikke noe bra tegn ?

Ellers er jeg usikker på bruk av: «Input variable», «Trigger variable», «Left variable» osv. Finnes det en oversikt som forklarer ting ?

Er også usikker på hvordan «map of string» skrives tilbake til termostaten.
(Ser hardkoding ved å skrive temperaturen rett inn i «Default value» fungerer)

Noen som har tips ?

Flowen ser slik ut:

Globale Variabler:

{
  "Id": "Vj8mDUCOxGHvJDO",
  "ClassId": "Vj8mDUCOxGHvJDO",
  "Author": "",
  "Version": 0,
  "CreatedAt": "2023-11-28T17:30:13.062176347+01:00",
  "UpdatedAt": "2023-11-28T17:45:34.415628472+01:00",
  "Name": "Test Senk Temp",
  "Group": "",
  "Description": "",
  "Nodes": [
    {
      "Id": "2",
      "Type": "trigger",
      "Label": "Leser termostat set punkt til Bad 2 etg.",
      "SuccessTransition": "3",
      "TimeoutTransition": "",
      "ErrorTransition": "",
      "Address": "pt:j1/mt:evt/rt:dev/rn:zw/ad:1/sv:thermostat/ad:9_1",
      "Service": "thermostat",
      "ServiceInterface": "evt.setpoint.report",
      "Config": {
        "IsValueFilterEnabled": false,
        "LookupServiceNameAndLocation": false,
        "RegisterAsVirtualService": false,
        "Timeout": 0,
        "ValueFilter": {
          "Value": ""
        },
        "VirtualServiceGroup": "ch_0",
        "VirtualServiceProps": {}
      },
      "Ui": {
        "nodeType": "",
        "x": 370,
        "y": 148
      },
      "TypeAlias": "Trigger"
    },
    {
      "Id": "3",
      "Type": "transform",
      "Label": "\"Set temp\" to Bad2etg Temp variabel",
      "SuccessTransition": "4",
      "TimeoutTransition": "",
      "ErrorTransition": "",
      "Address": "",
      "Service": "",
      "ServiceInterface": "",
      "Config": {
        "Expression": "",
        "IsLVariableGlobal": false,
        "IsRVariableGlobal": false,
        "IsTargetVariableGlobal": false,
        "IsTargetVariableInMemory": true,
        "LVariableName": "",
        "RValue": {
          "Value": 0,
          "ValueType": "int"
        },
        "RVariableName": "",
        "Rtype": "var",
        "TargetVariableName": "",
        "TargetVariableType": "",
        "Template": "",
        "TransformType": "jpath",
        "ValueMapping": [],
        "XPathMapping": [
          {
            "IsTargetVariableGlobal": true,
            "IsTargetVariableInMemory": false,
            "Path": "$.val.temp",
            "TargetVariableName": "Bad_2etg_Temp_float",
            "TargetVariableType": "float",
            "UpdateInputVariable": false
          }
        ]
      },
      "Ui": {
        "nodeType": "",
        "x": 360,
        "y": 332
      },
      "TypeAlias": "Transform"
    },
    {
      "Id": "4",
      "Type": "transform",
      "Label": " Bad_2etg_Temp - 3",
      "SuccessTransition": "5",
      "TimeoutTransition": "",
      "ErrorTransition": "",
      "Address": "",
      "Service": "",
      "ServiceInterface": "",
      "Config": {
        "Expression": "Bad_2etg_Temp_float - 3",
        "IsLVariableGlobal": false,
        "IsRVariableGlobal": false,
        "IsTargetVariableGlobal": true,
        "IsTargetVariableInMemory": false,
        "LVariableName": "",
        "RValue": {
          "Value": 0,
          "ValueType": "int"
        },
        "RVariableName": "",
        "Rtype": "var",
        "TargetVariableName": "Bad_2etg_Temp_float",
        "TargetVariableType": "float",
        "Template": "",
        "TransformType": "calc",
        "ValueMapping": [],
        "XPathMapping": []
      },
      "Ui": {
        "nodeType": "",
        "x": 363,
        "y": 521
      },
      "TypeAlias": "Transform"
    },
    {
      "Id": "5",
      "Type": "transform",
      "Label": "  Bad_2etg_Temp -> StrMAP",
      "SuccessTransition": "6",
      "TimeoutTransition": "",
      "ErrorTransition": "",
      "Address": "",
      "Service": "",
      "ServiceInterface": "",
      "Config": {
        "Expression": "",
        "IsLVariableGlobal": false,
        "IsRVariableGlobal": false,
        "IsTargetVariableGlobal": true,
        "IsTargetVariableInMemory": false,
        "LVariableName": "",
        "RValue": {
          "Value": 0,
          "ValueType": "int"
        },
        "RVariableName": "",
        "Rtype": "var",
        "TargetVariableName": "Bad_2etg_Low_Temp",
        "TargetVariableType": "str_map",
        "Template": "{\n    \"temp\": \"{{variable \"Bad_2etg_Temp_float\" true}}\",\n    \"type\": \"heat\",\n    \"unit\": \"C\"\n}",
        "TransformType": "template",
        "ValueMapping": [],
        "XPathMapping": []
      },
      "Ui": {
        "nodeType": "",
        "x": 369,
        "y": 731
      },
      "TypeAlias": "Transform"
    },
    {
      "Id": "6",
      "Type": "action",
      "Label": "Set Bad2 temp -3 grader",
      "SuccessTransition": "",
      "TimeoutTransition": "",
      "ErrorTransition": "",
      "Address": "pt:j1/mt:cmd/rt:dev/rn:zw/ad:1/sv:thermostat/ad:9_1",
      "Service": "thermostat",
      "ServiceInterface": "cmd.setpoint.set",
      "Config": {
        "DefaultValue": {
          "Value": "",
          "ValueType": "str_map"
        },
        "IsVariableGlobal": true,
        "Props": {},
        "RegisterAsVirtualService": false,
        "ResponseToTopic": "",
        "VariableName": "Bad_2etg_Low_Temp",
        "VariableType": "str_map",
        "VirtualServiceGroup": "",
        "VirtualServiceProps": {}
      },
      "Ui": {
        "nodeType": "",
        "x": 362,
        "y": 905
      },
      "TypeAlias": "Action"
    }
  ],
  "Settings": null,
  "IsDisabled": true,
  "IsDefault": false,
  "ParallelExecution": "parallel"
}

Har ikke prøvd dette selv, men ut fra bildet så ser det ut som " fra starten på variabel navnet i transform noden blir slutten av string. Kunne du forsøkt med \"Bad_2etg_Temp_float\" eller ved å erstatte quotes rundt selve variabelnavnet med single quotes ' ?

For å “skrive tilbake til enheten” kan du under Payload configuration velge den variabelen som du laget i transform noden i input variable drop down menyen.
CleanShot 2023-11-29 at 11.16.57

Vel, har forsøkt litt forskjellige alternativer, med får CONFIG_ERROR.
Har også forsøkt å sette «Left variable» lik innputen men får det ikke til å spille:

Slik:

image

Det er her jeg savner en beskrivelse av syntaksen. (Blir mye prøving og feiling dette)

Ellers ser jeg i loggen at temperaturen som det bygges en “str_map” av er temperaturen før med har trukket fra 3. (23 grader, skal være 20, det står 20 i den globale variabelen). Ellers er vel formatet OK ?

Tenker du da slik: ?

image

Hei igjen :slight_smile:
Grunnen til du får 23 og ikke 20 er at du må sette left variable i “Bad_2etg_Temp - 3” til å bruke verdien fra “Bad_2etg_Temp_float(float)”. Sånn den er konfigurert nå så bil den ta meldingen som “kom inn på” trigger noden.

Leser set punkt
henter ut temp og setter variabelen i float
kalkulerer variabelen i float - 3 (her er endringen)
bygge str_map fra den nye float variabelen
sende melding til termostat med input fra str_map (det du sendte ser riktig ut) :slight_smile:

Kunne du forsøkt dette først - tror ikke vi er så langt unna nå :slight_smile:

Kanskje off topic, men vil ikke denne flowen løpe løpsk? Ettersom trigger lytter etter event.setpoint.report, som jo publiseres i streamen når du oppdaterer termostatsetpunkt i siste action node, som igjen trigger flowen, osv… Bør heller ha en separat flow som først etterspør setpunkt fra termostaten (en eller annen trigger, deretter action node med cmd.setpoint.get_report), også deretter plukker opp dette i streamen ved hjelp av de to første nodene i trådstarters flow (trigger event.setpoint.report og deretter transform til en float).

Jo det er helt korrekt, hvis man får dette til å spille vil Flowen løpe løpsk. Dette er kun for å teste at alle blokkene fungerer. Dette skal kjøres i tre forskjellige Flows.

En flow som leser av temperaturene til alle termostatene og lagrer verdiene i globale variabler. Trigges når SET punktet endres, men skal ikke skrive til termostaten.

Flow 2 skal lese av effekt forbruket til alle gulv og lagre verdiene i globale variabler. Trigges ved endring og skal ikke skrive noen ting.

Flow 3 skal lese effekt forbruket fra Tibber puls, hvis da akkumulert effekt ligger høyt over tid skal man senke temperaturen 3 grader på de gulv som står på, etter en prioritert rekkefølge til total forbruket er under ønsket verdi. Flow 3 leser da temp og effekt fra variablene.

Det første jeg forsøkte på var å lese temperaturen ved behov i Flow3 med «cmd.setpoint.get_report» med dette fikk jeg aldri til. Hele systemet hang seg og verken restart eller restore førte frem. Måtte da få Futurehome til å slette den aktuelle Flowen. Så det tør jeg ikke forsøke på mere. Går derfor for å bruke flere Flows og globale variabler. Så dette eksemplet er kun for å se att de enkelte delene fungerer. Type Cast er jo en utfordring.

Takk for innspill, får se om det blir tid i kveld til testing :blush:

Skjønner, det er mer eller mindre slik jeg gjør det selv. Rart at det hang seg.

Jeg bruker en global variabel som åpner et “innhentingsvindu” når modus endres til home. I home-modus er da alle mine setpunkt/komforttemperaturer satt i appen. Når dette vinduet åpnes lagres alle setpunktene til globale variabler. Når siste setpunkt er lagt til lukkes vinduet. Bruker en liten time delay mellom hver termostat slik at jeg vet hvilken som rapporterer sist, og dermed når jeg skal lukke vinduet. Nå vet jeg at jeg ikke endrer disse setpunktene når disse senere endres og publiseres i message stream. Jeg har også en flow som lagrer avlest effekt på alle forbruksenheter til globale variable, slik at jeg vet om de er av eller på. Til slutt har jeg, akkurat som du skriver, en flow som slår av forbruksenheter i en rekkefølge dersom timeseffekten predikeres til å overstige en gitt grense.

Måten jeg gjør timeseffektbegrensningen på er:

  1. Flow som logger momentaneffekten fra tibber pulse til global variabel power_han (rate limit 20 sek for å ikke oversvømme flow). Her har jeg også en versjon som lager en power_han_runmean over en gitt tid som glatter ut korte variasjoner i effekt.

  2. Flow som via Tibber Pulse evt.meter_ext.report, kontinuerlig leser inn $.val.last_e_import (akkumulert energi hvert døgn [kWh]) til en variabel energy_day (rate limit 20 sek). Denne lagres i en parallel flow til en ny variabel energy_hour_start hver hele klokketime. Videre i flowen trekker jeg fra timesstarten, slik at jeg har antall kWh forbrukt inneværende time i variabel energy_hour_consumed. Deretter bruker jeg node time tools-current minute, samt power_han_runmean til å estimere videre foruk inneværende time. Total timeseffekt estimeres fra: energy_hour_estimated=energy_hour_consumed+(power_han_runmean/1000)*((60-current_min)/60).

  3. Selve powerlimiter-flowen kjører hvert andre minutt og begynner å skru av ting i prioritert rekkefølge dersom energy_hour_estimated>9.8kWh AND energy_hour_consumed>2.5kWh AND power_easee<2000W.

Siste kriterie er fordi limiter bare skal kjøre dersom Tibber ikke klarer å styre effektbalanseringen i huset via billader. Altså; når laderen lader med høy effekt er det Tibber som har kontrollen.

Kanskje dette er banalt for deg, eller kanskje det gir noen idéer. Det fungerer i alle fall dønn stabilt her i huset, har aldri oversteget satt grense.



Vel, da her jeg forsøkt å endre dette:

Ser jo at den globale variabelen har blitt riktig både før og etter denne endringen.
(Jeg henger nok ikke helt med på hvordan systemet fungerer)

Men jeg ser jo i loggen at det kommer en feilmelding når denne subtraksjonen utføres.

La inn et par delayer for å være sikker på at variablene blir oppdatert uten at det hjalp.

Så bra. Det er kjekt å se at det er noen som har fått det til. Dette er jo i prinsippet ganske likt det jeg forsøker å få til, men sliter med elementære Type Cast Transformer.

Jeg har også en Easee lader som Tibber kan regulere effekten ned på. Men ser jo at det ikke alltid fungerer som forventet. Derfor kjekt å ha en sikkerhetsventil i Futurehome. Men det begynner å bli en del IF THEN ELSE her også og har vel 37 globale variabler. En del er bare noen tellere som jeg inkrementerer i koden for å se hva som blir kjørt. (Det er jo begrenset med debuggings muligheter i systemet)

Som du ser i svaret jeg skrev til Espen har jeg fremdeles problemer. Ser du har fått til det jeg prøver på. Tror egentlig jeg er nesten i mål, men i programmeringsspråk er ikke nesten godt nok. Kunne du ha lagt ut en Snip av f.eks

«Setpoint_stue-4»
«Strmap»
«Send setpoint»

Det hadde vært kjekt, må jo si jeg savner LabVIEW i denne debuggingsfasen.

Ja, det var mye prøv og feil for å få det riktig, og som du sier, lite/ingen muligheter for å debugge. Jeg har jo fått endel feilmeldinger i kalkuleringer tidligere, men har aldri sett den “records from memory store, flow not found”… Denne var veldig merkelig. Har du prøvd å bare begynne fra scratch i en ny flow? Kan det være noe med triggeren eller selve flowen? Forsøkes det å hente noen variabler som har ligget i memory? Er på tynn is nå…

EDIT: I siste transformnode du la ut, bør du ikke skrive resultatet av Bad_2etg_Temp_float-3 til et nytt variabelnavn (i “Result”)?

I mitt eksempel er setpoint_stue global variabel, mens setpoint og setpoint_strmap er lokale. Det røde krysset, som man skulle tro indikerer gal syntaks, har visst ingenting å si.

Bildene under er en annen flow (tidsstyring/nattsenking stue), men gjør akkurat det samme:




Tusen takk for mange gode tips. :blush:
Da har jeg litt å leke med til uka. Er opptatt hel helgen.

Vel, nå nærmer det seg noe, men er ikke helt fornøyd enda.

Nå har jeg endret koden slik at man leser setpunktet til Bad2 trekker fra 3 og skriver til Bad1.

(Så slipper man at system «løper løpsk».

Har forsøkt å bygge denne Flowen på nytt, i tilfelle noe skulle ha blitt korrupt. (Ser at av og til at hvis man endrer på noe, og lagrer er det ikke alltid at systemet har fått med seg endringene.)

Men jeg fikk ikke dette til å fungere før jeg endret i templaten for å bygge «str_map»

Der måtte jeg endre false til true, ser på nette at det finnes eksempler på dette.

Hva betyr dette ?

De globale variablene blir oppdatert. Men jeg ser at variablen «Bad_2etg_Temp» er satt True på «In Memory»

Nå fungerer denne flowen, men får feilmelding i loggen:

Noen som har noen tips ?

True og false i strmap henviser til om variabelen er lokal (false) eller global (true). Dette så riktig ut i det aller første innlegget du postet.

Når du lager en ny variabel er det greit å være bevisst på to ting;

  1. Om variabel er lokal eller global
  2. Om du huker for “in memory”

In memory betyr at variabel lagres i minnet på huben. Jeg bruker aldri dette, bortsett fra hvis jeg feks har en stoppeklokkefunksjon som lagrer til en midlertidig variabel i en flow.

OK, takk for info.

Jeg har nå bevist valg å ha alle variablene som globale, da disse skal nåes fra forskjellige «Flows». Ellers så huker jeg IKKE av for «in memory». Det mystiske nå er at hvis jeg sletter denne variablen, så dukker den automatisk opp igjen når jeg kjører denne Flowen, og da er «in memory» satt til true. Men det gjøre kanskje ingenting ? Ellers liker jeg ikke feilmeldingen jeg ser i loggen. Forsøkte å sette inn litt delay mellom de forskjellige nodene uten at det hjalp.

Ja, det er greit å ha en del variable som globale. Jeg har erfart at jeg ofte må lage en ny variabel (nytt navn!) for å overskrive “gammel morro”. Dersom du gjør endringer i flowen og saver er det ikke alltid at dette blir oppdatert i kildekoden (“show source”). Her kan det fortsatt være satt “in memory: true”.

Da var jeg inn i Source Coden og endret en (“IsTargetVariableInMemory”: true), til (“IsTargetVariableInMemory”: false) Det løste problemet med variabelen som dukket opp med «In Memory» satt til true. Tydelig at det henger igjen gamle ting.

Da fungerer det hele som forventet bortsett fra at jeg fremdeles for feilmeldingen i loggen.

Da fikk jeg fjernet feilmeldingen i loggen ved å fjerne:
“PropFilterName”: “unit”,
“PropFilterValue”: “C”,

Fra source koden.
Da eksprementerer jeg litt mere med dette før jeg som nevnt vil splitte dette opp i tre forskjellige Flows. Men syntes det er kjekt å vite hvordan systemet fungerer før man bygger videre.

Har nå satt inn en trigger for hver termostat, totalt 4 stk. Når jeg hadde kun en trigger fungerte det som forventet. Men nå henger jeg ikke helt med. Trodde at det kun er tråden som er under Triggeren som er blitt aktivert som blir kjørt med det ser ut som om det er flere som blir kjørt.

Eksperimentet er som følger:
• Trigger Bad2 skriver til Bad1
• Trigger Bad1 skriver til Vaskerom
• Trigger Gang skriver ikke
• Trigger Vaskerom skriver ikke

Har laget en teller som blir oppdatert i hver av trådene.
Når man endrer på setpunktet på et av gulvene trigger systemet med følgende oppførsel.

• Vaskerom. Ser at telleren inkrementere med 1 for hver gang man endrer temperaturen på vaskerommet, som forventet. Men «Executed» til Flowen inkrementeres med 2 for hver gang. Det forstår jeg ikke.
• Gang. Telleren inkrementere med 1 for hver gang man endrer tempen, og «Executed» til Flowen inkrementeres med 1. Dette er det jeg forventer.
• Bad1. Her inkrementeres Bad1 1 eller 2x, og Vaskerom telleren inkrementers 2x. «Executed» til Flowen inkrementeres med 4. Dette er merkelig. (Hadde forventet at begge tellerene ble oppdatert med 1, og «Executed» med 2)
• Bad2. Her oppdateres «Executed» med 5 for hver gang. (Hadde forventet 3.) Bad1 og Bad2 inkrementeres med 1, mens vaskerom inkrementeres med 2. (Hadde forventet 1 på hver av de tre)

Eksperiment sekvensen ser slik ut.

Et annet spørsmål er hvordan man børe kjøre en slik sekvens, nå har jeg valgt: «Run all instances in parallell»

Noen som har noen tips for å få systemet mest mulig stabilt ?