Gå til innhold
  • Bli medlem
Støtt hjemmeautomasjon.no!

berland

Medlemmer
  • Innlegg

    552
  • Ble med

  • Besøkte siden sist

  • Dager vunnet

    24

Alt skrevet av berland

  1. Et forsøk på estimat av besparelse: Ta typeprofilen, finn ut hvor mye den koster med kommende priser. Flytt så samme antall kWh over til de timene som er valgt til å være på, og beregn hva samme antall kWh koster i de timene, skaler til 24 timer (antall tilgjengelige timer med priser varierer mellom 12 og 36) og sammenlign tallene. Dette blir en prediksjon av besparelse som jeg kan beregne løpende. For øyeblikket estimerer jeg da til å spare hele 7 øre de neste 24 timene (!) Men så er prisforskjellen bare 5-6 øre fra billigste til dyreste så dette er uansett en bortkastet dag..
  2. Jeg hadde klart meg ypperlig med bare gulvføler, så lenge det faktisk finnes en gulvføler i gulvet. Intern romføler inni enheten betrakter jeg som en nødløsning når man ikke har gjort skikkelig installasjonsjobb med gulvføler.
  3. Varmetapet (i watt) vil være lineært i temperaturforskjell. Man kan løse varmeledningsligningen for en sylinder for å finne ut hvordan formen påvirker, men siden dette ikke er noe du får gjort noe med, er det enklere å estimere det fra målinger. Jeg har lite forskjell mellom vinter og sommertemperatur i vaskerommet, så jeg vil kanskje ikke klare se dette utifra temperaturlogg og forbrukslogg, du vil kunne se denne lineære sammenhengen. Hos meg har jeg 22 grader i vaskerommet i snitt siste halvår, og tanken har holdt 60 grader - forskjell på 38 grader. Jeg beregner 148 W når huset er forlatt, og da mister tanken 148W/38grader = 3.9W/grad. Hvis det var 10 grader om vinteren, ville jeg da tapt 3.9*50 = 194 W gjennom isolasjonen. Siden jeg vet temperatur inni tank og utenfor kunne jeg forsåvidt enkelt korrigert for dette i koden over, men hos meg vil det nok ha lite å si.
  4. Hvorfor i hjørne heller enn midt i tak? Visuelt eller funksjonelt?
  5. Satt opp mot optimalisering av husoppvarming, så er dette ganske motsatt. Matematisk sett er det ingen grunn til å forholde seg til forskjell på dyreste og billigste time, så til og med med disse grisekjedelige dagene med bare høy pris kontinuerlig gjennom døgnet, så vil berederen min være mer avskrudd enn på. Et tilleggselement til algoritmen kunne selvsagt være å legge til mer komfort (øke minimumstallet fra 11) hvis det er lite å hente, men det er ikke sikkert at det vil være noen merkbar økning i komfort. Det gjenstår å finne ut hvordan jeg kan beregne "hvor mye jeg sparer". Heavy-duty-switchen og elektrikerbesøk er sunk cost, så å sette i verk styring som dette er nå en enkel beslutning. Men hvordan beregne besparelse? Jeg beregner forventet kostnad i hver time framover, og kan summere det og sette det opp mot hva typeprofilen hadde brukt framover i tid. Men siden siste rad i tabellen min ikke ender på maksimalt energiinnhold, kan jeg ikke sammenligne. Hvilken times pris skal jeg bruke for å korrigere det? Bakover i tid er det kanskje enklere, så om noen måneder er det nok mulig å beregne hva jeg hadde brukt uten smart-styring, og sammenligne med det som faktisk er brukt.
  6. Eksempelberegning fra just nu: Her er tabellen med alle data, og et tilhørende plott
  7. Dette har dratt ut litt i tid, og jeg venter på elektriker skal få tid til besøk. Men jeg har bekreftet at det virker når man har riktig trafo og også kobler ting riktig
  8. Algoritmen som gjør selve jobben er ikke lengre enn dette: daymode = 'Hverdag' data['onoff'] = 0 data['energycontent'] = 0 data['consumption'] = 0 lowerlimit = 11 effect = 2.7 insulationloss = data['Ferie_midlet'].mean() data.loc[data.index.values[0], 'energycontent'] = 16.08 while data.energycontent.min() < lowerlimit: onhours = data.onoff.astype(int).sum() + 1 data.loc[data.nsmallest(onhours, 'NOK/KWh').index.values,'onoff'] = '1' for row in data.index.values[:-1]: newenergycontent = data.loc[row, 'energycontent'] - data.loc[row, daymode] newenergycontent = int(data.loc[row, 'onoff']) * (effect - insulationloss) + newenergycontent data.loc[row+1, 'energycontent'] = min(newenergycontent, 15.79) for row in data.index.values[:-1]: data.loc[row, 'consumption'] = int(data.loc[row, 'onoff']) * \ round(data.loc[row+1, 'energycontent'] - data.loc[row, 'energycontent'] + data.loc[row, daymode],3) Dette er Python-kode med bruk av pandas-biblioteket, der jeg jobber på en tabell kalt 'data' som inneholder en rad for hver time 24 timer fram i tid. Tabellen inneholder prisinformasjon, og bruksprofilen er limt inn. Øyeblikkets energiinnhold er estimert fra temperaturmåling, og blir startpunkt for algoritmen. Jeg starter med å kun sette tanken på den billigste timen, og estimerer energiinnhold for hver time framover. Hvis denne en gang kommer under 11, så starter jeg forfra med å ha den på de to billigste timene, helt fram til at jeg er over 11 kWh i alle timer framover. Når dette er ferdig, så skrur jeg av eller på berederen utifra om 'onoff' er 0 eller 1 i første rad. I tillegg trengs det litt kode for å hente prisdata fra Tibber (pyTibber på github, installeres med pip)
  9. # Varmekapasitet for vann Cv = 4187 #J/kg oC (I tabeller oftest oppgitt med grader Kelvin; gjerne kJ/kg K - der 1K = 1oC) # Regn om til watt-timer: # * 1J = 1 Ws; # * 3600J = 3600 Ws = 1W * 3600s = 1Wh # * 4189J = (4189/3600)Wh = 1,163Wh # * 1liter vann veier ca. 1,0 kg Cv = 1.163055556 #Wh/kg oC liter = 194 effekt = 2700 grader = 75 - 5 # antar 5 grader inntak.. oppvarmingstid = Cv * liter / effekt * grader print("Oppvarmingstid {:.2f}".format(oppvarmingstid,"%d") + " timer") print("Energimengde i varm tank {:.2f} KWh".format(Cv * liter * grader/1000)) Jeg bruker "energimengde" i tanken (relativt kaldtinntaket) som begrep i styringen/optimaliseringen. Med tallene over får jeg at oppvarmingstid blir 5.85 timer hos meg, og energimengde på varm tank er 15.79 kWh. "Energimengde" på tanken kan regnes tilbake til temperatur, som kan sammenlignes med temperaturen jeg måler. Dette klarer jeg verifisere at stemmer (ved å se på hvor mange grader målt temperatur har steget etter at elementet har vært innekoblet f.eks. 40 minutter). Så å sette en nedre grense på energimengde jeg tillatter i tanken, så betyr det en nedre temperaturgrense. Akkurat hva jeg skal bruke som energigrense har jeg noe tilfeldig satt til 11 kWH for øyeblikket - jeg skal se an noen dager om dette er for høyt eller for lavt, det tilsvarer ca 55 grader på tanken. Hvis tanken er påskrudd i to sammenhengende timer, så vet jeg da at den ca vil nå makstemperatur (2.7 kW * 2 timer + 11 = 15.4 kWh), men jeg er uansett langt over legionellagrensa.
  10. Intelligens som i maskinlæring innebærer som regel bare noe statistikk. Jeg har noen måneders logg fra en Aeotec Smart Switch og dernest en Aeotec Heavy Duty Switch som har stått på tanken. Utifra kumulativt-forbruk gjennom hvert døgn, kan jeg beregne type-profiler for når varmtvannstanken står på: Dataene kategoriserte jeg etter om huset er i feriemodus, hverdag eller helg. Ferie-linja (blå) burde vært flat, men jeg har ikke samlet nok data til det, så derfor bruker jeg den røde linja i praksis for ferie-modus. Enheten på y-aksen er kWh, og angir da hvor mye strøm varmtvannstanken vanligvis bruker i gitte time. Utifra dataene leser jeg at vi står opp tidligere på hverdager enn i helger, men det skjer mer dusjing på kvelden i helgene enn på hverdager. Oscillasjonen på dagtid i helg er kanskje ikke reell, men bare symptom på lite data. Ferie-tallet (på 0.148 kWh) betyr også at varmtvannstanken i snitt taper 148 W til rommet kontinuerlig når den ligger på 60 grader. Etter at jeg setter igang med styring av tank, så kan jeg ikke lenger bruke strømmåleren for å forbedre bruksprofilen, siden den blir styrt av pris og ikke bruk. Det kan hende det er mulig å forbedre profilen med bruk av deteksjon av vamrtvannstappingen senere, men det er heller ikke sikkert at det trengs. Profilen kan selvsagt også håndtegnes etter behov. Tanken videre er å bruke dette for å predikere hvor mye varmtvann som brukes de neste timene, og dermed predikere hva som er temperatur på tanken om X antall timer.
  11. Så ble det noen lange kvelder med å tenke på hvordan jeg kan styre dette mot pris, samtidig som at man skal ha varmt nok vann i springen (og unngå legionella). Diverse lesing på nettet gjør at jeg finner ut hvordan jeg sjekker og justerer temperaturinnstillingen på tanken ved å finne skruen som holdt plastdekselet i bunn fast. Termostatinnstillingen er en liten skrue nede til venstre i bildet. Det er selvsagt også irriterende hvor lett det hadde vært å stikke en temperatursensor inni her, så hadde jeg også fått måling av temperatur som var uavhengig av tapping. Men, det viktige her er at jeg finner at tanken var innstilt på 60 grader (nedre grense i forhold til legionella). Jeg setter den opp til 75 (den går ikke høyere) dette gir meg umiddelbart 15 grader mer å spille på i forhold til å utsette oppvarming av vann.
  12. Temperaturdataene visualiserer jeg i Grafana (lagret i InfluxDB), og jeg har også programmert en snutt i OpenHAB for å detektere om det tappes vann. Dette er indikert med rødt bakgrunn i plottet under. Trigger for å tro at det tappes er at både varmtvannsutløpet øker i temperatur og kaldtvannet minker i temperatur. Det var en prøvelse å få programmert disse derivert-funksjonene i OpenHAB sin Xtend. Grønt er temperaturmåler på varmtvannet som tappes fra tank. Gult er temperaturmåler nedstrøms på varmtvannet og er etter blandeventilen. Blått er kaldtvann inn (det ligger også lilla bakgrunn i tidsperioden der varmeelementet er på) rule "Varmtvannstapping" when Item Varmtvannsbereder_ut_diff changed or Item Vartmvannsbereder_kaldtinn_diff changed then if (Varmtvannsbereder_tapper.state == NULL) { Varmtvannsbereder_tapper.postUpdate(OFF) } if (Varmtvannsbereder_ut_diff.state > 0.015 && Varmtvannsbereder_kaldtinn_diff.state < -0.015) { if (Varmtvannsbereder_tapper.state == OFF) { logInfo("Varmtvann", "det tappes") Varmtvannsbereder_tapper.postUpdate(ON) } } if (Varmtvannsbereder_ut_diff.state < -0.05 && Varmtvannsbereder_kaldtinn_diff.state > 0) { if (Varmtvannsbereder_tapper.state == ON) { logInfo("Varmtvann", "stillstand") Varmtvannsbereder_tapper.postUpdate(OFF) } } end rule "Varmtvannsderiverte varmt ut" when Item Varmtvannsbereder_ut changed then var foo = Varmtvannsbereder_ut.lastUpdate().getMillis() var deltatid = (now.getMillis() - foo)/1000.0 var deltatemp = ((Varmtvannsbereder_ut.state as DecimalType) - (Varmtvannsbereder_ut.previousState.state as DecimalType)) var diff = deltatemp / deltatid if (deltatid > 1) { Varmtvannsbereder_ut_diff.postUpdate(diff) } end
  13. Med utgangspunkt i at jeg fikk på plass temperaturovervåking av varmtvannstanken min nylig, så har ting ballet på seg. Først litt bilder fra temperaturloggingsprosjektet Strips er klippet av etter bildet ble tatt og så har jeg isolert det inne. Koden på ESP8266 er laget med Arduino IDE, og med eksempelkode for D18B20. Temperaturene leses av flere ganger i sekundet, men data sendes kun over MQTT hvis det skjer en stor nok endring, og uansett hvert minutt.
  14. Jeg fikk også refusjon for alle varmekabeltermostatene, varmepumpefjernkontroll og elektrikerregninger for montering av varmekabeltermostater. La ved fakturaer (elektriker lagde egne faktura'er for bare termostatutbytting). La ved noen avsnitt som beskrev varmestyringssystemet, med peker til en av mine tråder her på hjemmeautomasjon.no. Godkjent på et par dager.
  15. Her er utledningen av at det er 5 meter til motfasen av sommer og vinter. Setter man inn tall for døgnvariasjon, får man at motfasen skal ligge på 26 cm dyp, og det kan allerede se ut som det stemmer på dine kurver. Hva er årstemperatur der du bor, og hvor kaldt blir det om vinteren? La oss gjette 4 grader i årstemperatur, og -4 i vintertemperatur (altså 8 grader mindre enn middeltemperatur), da skal du nå -0.3 på 1 meters dyp (forskjøvet ut på våren).
  16. Dette er jeg skikkelig misunnelig på og har lyst på selv. Fra ei gammel lærebok i termisk fysikk har jeg at på fem meters dyp er det kaldest midtsommers. Så dypt har du ikke gravd men temperaturene dine skal følge samme ligninger.
  17. Motorisert rullegardin - ✔️ Smart ringeklokke ✔️ (egen tråd) AMS-leser med RPI ✔️ (men hadde nok heller valgt Tibber Pulse om den var tilgjengelig allerede) I tillegg: Temperatursensorer på varmtvannstank. (kommentar i annen tråd)
  18. Takk @bjornepappa for inspirasjon, nå har jeg fått montert en tilsvarende løsning hos meg. Jeg har satt på tre D18B20, koblet til en ESP8266 som rapporterer temperaturen via MQTT. En sensor der varmtvannet kommer ut, en etter blandeventil, og en på kaldtvannsinntaket. Hensikten er å kunne være mer aggressiv i når tanken er avskrudd. Etter bildet er tatt er strips klippet av, og glava + alufolie lagt rundt. Grafana-plottet viser en liten tappesekvens (jeg har brukt mye varmtvann for å teste!). Den røde bakgrunnen er når jeg i programvare tror at det tappes varmtvann (utløp for varmtvann stiger samtidig som kaldtvannstemperatur synker). Jeg klarer detektere tapping innen 10 sekunder, men det tar opptil et minutt å detektere at tapping er slutt (med mindre koden blir mer intelligent).
  19. Koden over er den jeg har kompilert til firmware i Arduino IDE, og så flasher jeg ESP8266 med den. Brikka var kanske en "NodeMCU" når jeg kjøpte den, men etter at jeg har flashet min egen ringeklokke-firmware, er det ingen spor av NodeMCU lenger på den.
  20. Koden er egenlaget, med utgangspunkt i eksemplene som følger med Arduino IDE; #include <PubSubClient.h> #include <ESP8266WiFi.h> #include <ArduinoOTA.h> #include <stdlib.h> void callback(char* topic, byte* payload, unsigned int length); //EDIT THESE LINES TO MATCH YOUR SETUP const char* mqtt_server = ""; const char* ssid = ""; const char* password = ""; // Pin 16 is "not safe", it goes to HIGH on boot.. Cannot be used for ding-dong. const int switchPin1 = 16; // for deactivating all ding-dong-sound. goes high for 100ms on boot. s const int switchPin2 = 15; // OpenHAB triggered ding-dong. unsigned long lastDebounceTime = 0; unsigned long debounceDelay = 2000; // Don't allow less than two secs for state change unsigned long lastHeartbeat = 0; unsigned long heartbeatDelay = 60000; int heartbeatcounter = 0; char const* switchTopic1 = "doorbell/activate"; char const* switchTopic2 = "doorbell/force"; int doorbellChimeState; int prevChimeState; const int inputPin = 14; WiFiClient wifiClient; PubSubClient client(mqtt_server, 1883, callback, wifiClient); void setup() { //initialize the switch as an output and set to LOW (off) pinMode(switchPin1, OUTPUT); // Relay Switch 1, deaktivering av all ding-dong. digitalWrite(switchPin1, LOW); pinMode(switchPin2, OUTPUT); // Relay Switch 2; ding-dong digitalWrite(switchPin2, LOW); pinMode(inputPin, INPUT_PULLUP); ArduinoOTA.setHostname("Doorbell ESP8266"); // A name given to your ESP8266 module when discovering it as a port in ARDUINO IDE ArduinoOTA.begin(); // OTA initialization //start the serial line for debugging Serial.begin(115200); delay(100); //start wifi subsystem WiFi.begin(ssid, password); //attempt to connect to the WIFI network and then connect to the MQTT server reconnect(); client.publish("doorbell/unit", "booted"); //wait a bit before starting the main loop delay(100); client.publish("doorbell/unit", "starting"); String ipaddress = WiFi.localIP().toString(); char ipchar[ipaddress.length()+1]; ipaddress.toCharArray(ipchar,ipaddress.length()+1); client.publish("doorbell/IP", ipchar); } char buffer[10]; void loop(){ // read the state of the doorbell active sensing circuit doorbellChimeState = digitalRead(inputPin); //client.publish("doorbell/state", itoa(doorbellChimeState, buffer, 10)); if ((doorbellChimeState == HIGH) && (prevChimeState != HIGH) && (millis() > lastDebounceTime + debounceDelay)) { lastDebounceTime = millis(); client.publish("doorbell/chiming", "OFF"); prevChimeState = doorbellChimeState; } if ((doorbellChimeState == LOW) && (prevChimeState != LOW) && (millis() > lastDebounceTime + debounceDelay)) { lastDebounceTime = millis(); client.publish("doorbell/chiming", "ON"); prevChimeState = doorbellChimeState; } // Check heartbeat if (millis() > lastHeartbeat + heartbeatDelay) { lastHeartbeat = millis(); client.publish("doorbell/heartbeat", itoa(heartbeatcounter, buffer, 10)); heartbeatcounter++; } //reconnect if connection is lost if (!client.connected() && WiFi.status() == 3) {reconnect(); } //maintain MQTT connection client.loop(); //MUST delay to allow ESP8266 WIFI functions to run delay(10); ArduinoOTA.handle(); } void callback(char* topic, byte* payload, unsigned int length) { //convert topic to string to make it easier to work with String topicStr = topic; //EJ: Note: the "topic" value gets overwritten everytime it receives confirmation (callback) message from MQTT //Print out some debugging info Serial.println("Callback update."); Serial.print("Topic: "); Serial.println(topicStr); if (topicStr == switchTopic1) { //turn the switch on if the payload is '1' and publish to the MQTT server a confirmation message if(payload[0] == '1'){ digitalWrite(switchPin1, HIGH); client.publish("doorbell/confirmActive", "1"); } //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message else if (payload[0] == '0'){ digitalWrite(switchPin1, LOW); client.publish("doorbell/confirmActive", "0"); } } else if (topicStr == switchTopic2) { if (payload[0] == '3'){ // Quick ding-dong client.publish("doorbell/confirmForce", "3"); digitalWrite(switchPin2, HIGH); delay(40); digitalWrite(switchPin2, LOW); } if (payload[0] == '2'){ // Quick double ding-dong client.publish("doorbell/confirmForce", "2"); digitalWrite(switchPin2, HIGH); delay(100); digitalWrite(switchPin2, LOW); delay(150); digitalWrite(switchPin2, HIGH); delay(100); digitalWrite(switchPin2, LOW); } if(payload[0] == '1'){ digitalWrite(switchPin2, HIGH); client.publish("doorbell/confirmForce", "1"); client.publish("doorbell/forcechiming", "on"); delay(400); digitalWrite(switchPin2, LOW); client.publish("doorbell/forcechiming", "off"); } //turn the switch off if the payload is '0' and publish to the MQTT server a confirmation message // THIS SHOULD NEVER BE NECESSARY else if (payload[0] == '0'){ digitalWrite(switchPin2, LOW); client.publish("doorbell/confirmForce", "0"); } } } void reconnect() { //attempt to connect to the wifi if connection is lost if(WiFi.status() != WL_CONNECTED){ //debug printing Serial.print("Connecting to "); Serial.println(ssid); //loop while we wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //print out some more debug once connected Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } //make sure we are connected to WIFI before attemping to reconnect to MQTT if(WiFi.status() == WL_CONNECTED){ // Loop until we're reconnected to the MQTT server while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Generate client name based on MAC address and last 8 bits of microsecond counter String clientName; clientName = "esp8266-doorbell"; //if connected, subscribe to the topic(s) we want to be notified about //EJ: Delete "mqtt_username", and "mqtt_password" here if you are not using any if (client.connect((char*) clientName.c_str())) { Serial.println("\tMQTT Connected"); client.subscribe(switchTopic1); client.subscribe(switchTopic2); client.publish("doorbell/unit", "connected mqtt"); // client.publish("doorbell/ip", WiFi.localIP()); } //otherwise print failed for debugging else{Serial.println("\tFailed."); abort();} } } }
  21. Loddet opp resten og satt inn i sikringskap - det funker! Det trengs litt debouncing for optokobleren, det gjør jeg i programvare. Koden får kun bytte tilstand hvert 2. sekund mellom PÅ og AV for dingelyd. Laget en vanlig ding-dong-lyd (400ms) en lynkjapp (50ms) og en dobbel kjapp (100ms, 50ms pause, 100 ms lyd). Dette kan sikkert brukes til noe etterhvert, og flere sekvenser kan jo lett lages. STOR takk til @DeVille og @Televimsen for hjelp. Uten dere hadde jeg gitt opp ?
  22. Koblet opp ding-dong reléet med svakere motstand og med emitter mot jord - funker! Lærte at pin 16 på ESP8266 ikke bør brukes til dette reléet som lager ding-dong-lyd, pin'en går HIGH i 100ms ved boot, og det sømmer seg ikke. Pin 15 skal passe bedre.
  23. Jeg har Aeotec smart switch på min vaskemaskin, skal tåle 3000W. Ser ikke ut som om kjell har denne. Den finnes f.eks. her: https://store.tibber.com/no/store/aeotec-smart-switch/
×
×
  • Opprett ny...

Viktig informasjon

Vi har plassert informasjonskapsler/cookies på din enhet for å gjøre denne siden bedre. Du kan justere dine innstillinger for informasjonskapsler, ellers vil vi anta at dette er ok for deg.