@alcalzone
Bitte, wenn Du dir das antun möchtest - ist recht umfangreich.
Inzwischen denke ich, dass es besser wäre, statt mit dem festen Timeout
setTimeout(function () {
darauf zu warten, bis die funktion evohome_IF() komplett fertig ist.
Der komplette Code ist weiter unten.
Danke.
function RaumAbw(obj) {
let Startzeit = getState(Out_Root+D_Raum[0]+".Soll").ts
evohome_IF() // Ist- und Solltemperaturen abrufen, Absenkung prüfen
let Endtzeit = getState(Out_Root+D_Raum[0]+".Soll").ts
log('evohome_IF() Funktion Dauer: '+(Endtzeit-Startzeit)+' ms.')
RTdiff = 0;
TempDiff_Sum = 0;
MaxTempRaum = ""
RTdiff_max = 0
maxSollTemp = 0
Heizleistung_Soll = 0
var LastTS = Date.now()
var SollTemp = 0, IstTemp = 0
setTimeout(function () { // 1sec. Warten auf Callback von evohome_IF()
/*
https://github.com/svrooij/evohome
evohome wird installiert in /root/node_modules/@svrooij/evohome
und muß in /opt/iobroker/node_modules/iobroker.javascript/node_modules/evohome verschoben werden
in ioBroker JS Instance das additional NPM module: evohome eintragen
Berechnet die Heizlastanforderung in °C (Soll-Ist aller Räume) für WTC-EvoHome Interface
Regelung der Vorlauftemperatur über WTC-COM bzw. WTC-WEM Portal
EVO Home auf Ausfall Prüfung
*/
// Eingangsdaten
var Out_Root="javascript." + instance + ".haus.Heizung."
// Zimmer
var S_Raum=[];
S_Raum[0]='Büro' // Büro - Raum namen müssen mit EvoHome übereinstimmen
S_Raum[1]='Küche' // Küche
S_Raum[2]='Bad' // Bad
S_Raum[3]='Wohnzimmer' // Wohnzimmer
S_Raum[4]='OG Zi links' // OG Zi Links
S_Raum[5]='OG Wohnen'; // OG Wohnen
S_Raum[6]='OG Küche'; // OG Küche
S_Raum[7]='OG Zi rechts'; // OG Zi Rechts
// Neue Alias Daten Objekte
var D_Raum=[];
D_Raum[0]='Buero'; // Raumnamen für Script
D_Raum[1]='Kueche';
D_Raum[2]='Bad';
D_Raum[3]='Wohnzimmer';
D_Raum[4]='OG_Zi_Links';
D_Raum[5]='OG_Wohnen';
D_Raum[6]='OG_Kueche';
D_Raum[7]='OG_Zi_Rechts';
// Korrekturwerte für Raum Temperatur (Faktor für RTdiff < 0)
var K_Raum=[];
K_Raum[0]=1 // 'Buero';
K_Raum[1]=1 // Küche
K_Raum[2]=1 //'Bad';
K_Raum[3]=1 //'Wohnzimmer';
K_Raum[4]=1 //'OG_Zi_Links';
K_Raum[5]=1 //'OG_Wohnen';
K_Raum[6]=1 //'OG_Kueche';
K_Raum[7]=1 //'OG_Zi_Rechts'
//Konstanten für erforderliche Heizleistung
const Kwert = 0.4 // kWert 1.1 = Neubau; 2.2 = Gebäude ab 1975; 3 = Altbau
var V_Raum=[]; // Raum Volumen in m³
V_Raum[0]=26.00*2.53 // 'Buero' Fläche * Raumhöhe in qm*m
V_Raum[1]=45.77*2.30 // 'Kueche'
V_Raum[2]=18.75*2.63 // 'Bad'
V_Raum[3]=72.68*2.55 // 'Wohnzimmer'
V_Raum[4]=25.00*2.53 // 'OG_Zi_Links';
V_Raum[5]=12.00*2.53 // 'OG_Wohnen'
V_Raum[6]=16.00*2.53 // 'OG_Kueche';
V_Raum[7]=25.00*2.53 // 'OG_Zi_Rechts' Summe Volumen: 603m³ WF UG: 163 OG: 72
var Raum_VTemp=[0,0,0,0,0,0,0,0];
var Raum_SollTemp=[0,0,0,0,0,0,0,0];
var RTdiff = 0
var RTdiff_max = 0
var maxSollTemp = 0
var TempDiff_Sum = 0;
var Heizleistung_Soll = 0
var Heizleistung_Ist = 0
var MaxTempRaum = "";
var LastIndex = 0
// Alle Zimmer Tempraturen
const Temp_Aus = 13.0 // Urlaub, Heizung aus
const Temp_FOA = 13.6 // Fenster offen Alarm
const Temp_Abw = 15.0 // abwesend (Smartphone)
const Temp_Anw = 21.1 // anwesend (Smartphone)
const Temp_Abs = 18.0 // Absenktemp (EvoHome)
const Temp_Norm = 21.0 // Normaltemp (EvoHome)
const Temp_Max = 22.5 // Max. Temperatur (Sonneneinstrahlung)
var ArrayTD=[]
// ------------------------- Alias Daten Objekte anlegen -----------------
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".Soll", {
name: D_Raum[index]+"-Soll",
type: 'number',
unit: '°C',
});
});
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".Temperatur", {
name: D_Raum[index]+"-Ist",
type: 'number',
unit: '°C',
});
});
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".FensterOffen", {
name: "ist Fenster offen",
type: 'boolean',
unit: '',
});
});
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".Abwesend", {
name: "ist Smartphone abwesend",
type: 'boolean',
unit: '',
});
})
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".evoDeviceID", {
name: "EvoHome Device ID",
type: 'number',
unit: '',
})
})
/*
S_Raum.forEach(function(element, index) {
createState(Out_Root+D_Raum[index]+".Steigung", {
name: D_Raum[index]+"-Steigung",
type: 'number',
unit: 'K/Std.',
});
});
*/
createState(Out_Root+"Kessel.RTdiff_max_Raum", {
name: "RTdiff welcher Raum",
type: 'string',
unit: '',
});
createState(Out_Root+"Kessel.RTdiff", {
name: "akt. Soll-Ist Raumtemp",
type: 'number',
unit: 'K',
});
createState(Out_Root+"Kessel.RTdiff_max", {
name: "max. Soll-Ist Raumtemp",
type: 'number',
unit: 'K',
});
createState(Out_Root+"Kessel.Heizleistung_Soll", {
name: "Summe erforderliche Heizleistung",
type: 'number',
unit: 'Watt',
});
createState(Out_Root+"Stoerung.EHLastTS", {
name: "EvoHome letzte RT Änderung vor",
type: 'number',
unit: 'Min.',
})
createState(Out_Root+"Stoerung.EHLastTS_R", {
name: "bei Raum",
type: 'string',
unit: 'Min.',
})
createState(Out_Root+"Stoerung.EHLastTS_max", {
name: "EvoHome letzte RT Änderung max.",
type: 'number',
unit: 'Min.',
})
createState(Out_Root+"Stoerung.EHLastTS_max_R", {
name: "bei Raum",
type: 'string',
unit: 'Min.',
})
// ---- letzte Temperaturänderung feststellen
function LastTempCh(LastTS, index){
let RTobj = getState(Out_Root+D_Raum[index]+'.Temperatur')
if (RTobj.ts < LastTS){
LastTS = RTobj.ts
let Dauer = Math.round( (Date.now()-LastTS)/1000/60 )
// log('#### '+D_Raum[index]+' EVOHome letzte Temperatur vor min.: '+Dauer )
setState("javascript.0.haus.Heizung.Stoerung.EHLastTS",Dauer ) // letzte Raumtemperatur Änderung vor x Min.
setState("javascript.0.haus.Heizung.Stoerung.EHLastTS_R",D_Raum[index])
if ( Dauer >= getState('javascript.0.haus.Heizung.Stoerung.EHLastTS_max').val ){
setState('javascript.0.haus.Heizung.Stoerung.EHLastTS_max',Dauer)
setState('javascript.0.haus.Heizung.Stoerung.EHLastTS_max_R',D_Raum[index])
}
}
} // LastTemp
schedule("1 0 * * *", function () { // "1 0 * * *" um 0:01 täglich
setState('javascript.0.haus.Heizung.Stoerung.EHLastTS_max',0) // max Werte Vortag löschen
setState('javascript.0.haus.Heizung.Stoerung.EHLastTS_max_R','')
})
//############################### Ist und Soll Temperatur abrufen ###########################################
RaumAbw() // Für Programmstart
setInterval(RaumAbw,5*60*1000) // Intervall wg Fenster offen u. Handy ab
function RaumAbw(obj) {
let Startzeit = getState(Out_Root+D_Raum[0]+".Soll").ts
evohome_IF() // Ist- und Solltemperaturen abrufen, Absenkung prüfen
let Endtzeit = getState(Out_Root+D_Raum[0]+".Soll").ts
log('evohome_IF() Funktion Dauer: '+(Endtzeit-Startzeit)+' ms.')
RTdiff = 0;
TempDiff_Sum = 0;
MaxTempRaum = ""
RTdiff_max = 0
maxSollTemp = 0
Heizleistung_Soll = 0
var LastTS = Date.now()
var SollTemp = 0, IstTemp = 0
setTimeout(function () { // 1sec. Warten auf Callback von evohome_IF()
S_Raum.forEach(function(element, index) { // Schleife für jeden Raum
LastTempCh(LastTS, index) // letzte Temperaturänderung feststellen
SollTemp = getState(Out_Root+D_Raum[index]+".Soll").val
IstTemp = getState(Out_Root+D_Raum[index]+".Temperatur").val
// Berechnung der maximalen negativen Temperaturdifferenz (Ist-Soll) aller Räume
if (IstTemp > Temp_Max) IstTemp = Temp_Max + 0.1 // wg. Sonneneinstrahlung
RTdiff = (IstTemp-SollTemp)
if (RTdiff < 0) RTdiff = RTdiff * K_Raum[index]
// Temperatur für benötigte Heizleistung = RTsoll - AT
let Tempdiff = SollTemp - getState('mqtt.0.haus.keller.HumiFan.Sensor.Aussen.Temperatur').val
var Heizleistung = Math.round((V_Raum[index] * Kwert * Tempdiff * 1.16) ) // 1.16 = kcal in Watt
if (Heizleistung > 0 ) Heizleistung_Soll += Heizleistung // summe Heizleistung in Watt
Heizleistung_Ist = getState('mqtt.0.haus.keller.WMZ.WMleistung').val
// log(D_Raum[index]+' RTdiff: '+RTdiff+' RTdiff_max: '+ RTdiff_max);
TempDiff_Sum += RTdiff;
if ( RTdiff < RTdiff_max ) { // der "kälteste Raum" wird gesucht
RTdiff_max = RTdiff; // -1 = Raum zu kalt, aufheizen
MaxTempRaum = D_Raum[index];
}
if (SollTemp > maxSollTemp) maxSollTemp = SollTemp // aktuell max. Solltemperatur
if (MaxTempRaum == 'Kueche') MaxTempRaum = 'Küche'
if (MaxTempRaum == 'Buero') MaxTempRaum = 'Büro'
LastIndex = index+1
}); // Schleife für jeden Raum ######################################
// TempSteigung(element, index) // Berechnet die Temperatur-Steigung des Raumes
// Durchschnitt Energiebedarf - Wennn ein Raum zu kalt (<-1.1), dann bestimmt er die Temperatur
RTdiff = RTdiff_max/4
if (RTdiff_max >= -0.9) RTdiff = round(TempDiff_Sum/LastIndex,1) // 19.1.2021 0.6; 4.2.2021 1.1
// RTdiff = AAverage(ArrayTD,RTdiff,5)
// log('RTdiff: '+ArrayTD+' Median: '+AMedian(ArrayTD)+' Average: '+AAverage(ArrayTD))
// log('--- '+MaxTempRaum+' '+RTdiff_max+' RTDiff: '+RTdiff)
setState(Out_Root+"Kessel.RTdiff",round(RTdiff,3)) // Temp.Differenz für Regelung
setState(Out_Root+"Kessel.RTdiff_max",round(RTdiff_max,3)) // max. Temp Differenz
setState(Out_Root+"Kessel.RTdiff_max_Raum",MaxTempRaum); // bei Raum im Klartext
setState(Out_Root+"Kessel.Heizleistung_Soll",round(Heizleistung_Soll*1.1,0)) // +10% für übrige Räume
},1000)
} // function RaumAbw
//############################### Ist und Soll Temperatur abrufen ###########################################
// Berechnet die Steigung der Raumtemperatur der letzten 30min. in K/Std.
// Normalwerte: Aufheizen: ca. 3K/h ; abkühlen ca. 1K/h
function TempSteigung(element, index){
var IstTemp = parseFloat( getState(Out_Root+D_Raum[index]+".Temperatur").val)
// ++++++++++++++++ evtl. nur bei Änderung Steigung berechnen, dann aber jede Min. aufrufen
// if (Raum_VTemp[index] != IstTemp) { // Raumtemperatur geändert
Raum_VTemp[index] = IstTemp
// var vonDatum = new Date("2020-02-06 6:00:00").getTime() // in UnixTime ms.
// var bisDatum = new Date("2020-02-06 8:00:00").getTime()
var bisDatum = Date.now()
var vonDatum = bisDatum - 3600*1000; // vor 1 Std.
mysqlData_Steigung(vonDatum, bisDatum, Out_Root+D_Raum[index]+".Temperatur", index) // return steigung nicht möglich, weil asynchron
// }
} // function TempSteigung
function mysqlData_Steigung(vonDatum, bisDatum, DatObj, index){
var vTemp, vDatum, bTemp, bDatum
var myQuery="SELECT val AS wert, ts as datum \
FROM iobroker.ts_number \
WHERE id=(SELECT id FROM iobroker.datapoints WHERE NAME='"+DatObj+"') \
AND ts <= '"+vonDatum+"' \
ORDER BY ts DESC LIMIT 1"
// ts < Datum weil das die Temperatur zur Zeit vonDatum ist
// log("--->>>>"+myQuery);
sendTo('sql.0', 'query', myQuery, function (result) {
if (result.error) {
logerror("Heizung_Alias SQL querry Fehler 1: "+result.error);
} else {
vTemp=result.result[0].wert;
vDatum = result.result[0].datum; // var date = new Date(unix_timestamp * 1000);
var myQuery="SELECT val AS wert, ts as datum \
FROM iobroker.ts_number \
WHERE id=(SELECT id FROM iobroker.datapoints WHERE NAME='"+DatObj+"') \
AND ts <= '"+bisDatum+"' \
ORDER BY ts DESC LIMIT 1"
sendTo('sql.0', 'query', myQuery, function (result) {
if (result.error) {
logerror("Heizung_Alias SQL querry Fehler 2: "+result.error);
} else {
bTemp=result.result[0].wert;
bDatum = result.result[0].datum; // var date = new Date(unix_timestamp * 1000);
var Temperatur = (bTemp-vTemp)
var Datum = (bDatum-vDatum)/1000 // in sec.
var steigung = 0
if (Datum != 0) steigung = Math.round(Temperatur/Datum*36000) /10; // in K/Std.
// log(D_Raum[index]+ " Steigung: "+steigung)
setState(Out_Root+D_Raum[index]+".Steigung",steigung);
}
});
}
});
} // function mysqlData_Steigung
//############################ alle Raumemperaturen von EvoHome auslesen ############################
function evohome_IF(){
const EvohomeClient = require('evohome').EvohomeClient
const HeatSetpointStatus = require('evohome').HeatSetpointStatus
const username = 'xxxxxxxxx'
const password = 'yyyyyyy'
const evohomeClient = new EvohomeClient(username, password)
evohomeClient.getLocationsWithAutoLogin(300).then(locations => { // (x) = Session Abbruch nach x Sekunden
// log('JSON OBJ: '+JSON.stringify(locations))
S_Raum.forEach(function(element, index){ // z.Zt. 8 Räume 0-7
const deviceId = locations[0].devices[index].deviceID
var Raum_name = locations[0].devices[index].name
var Rindex = S_Raum.indexOf(Raum_name) // suchen Raumname in S_Raum Array
if (Rindex != -1) {
var IstTemp = locations[0].devices[index].thermostat.indoorTemperature
var SollTemp = locations[0].devices[index].thermostat.changeableValues.heatSetpoint.value
// log(Rindex+'-Zimmer: '+Raum_name+' Temperatur: '+IstTemp+' Soll Temp: '+SollTemp)
SollTemp = Absenkung(deviceId,Rindex,SollTemp,evohomeClient,HeatSetpointStatus)
setStateAsync(Out_Root+D_Raum[Rindex]+".Temperatur",IstTemp)
setStateAsync(Out_Root+D_Raum[Rindex]+".Soll",SollTemp)
setStateAsync(Out_Root+D_Raum[Rindex]+".evoDeviceID",deviceId)
// if (x==7) evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Hold, 15) // Wohnzimmer Temp. setzen
// if (x==7) evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Temporary, 15,10) // Wohnzimmer auf 15° 30 min. lang
// if (x==7) evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Scheduled) // Wohnzimmer auf Zeitplan zurücksetzen
} else {
logerror('Raum '+Raum_name+' nicht gefunden')
}
}) // forEach
}).catch(err => {
log('Fehler bei EvoHome Abfrage: '+ err)
// process.exit(3)
})
} // evohome_IF
//############################ Absenkung bei Fenster offen oder Handy ab ########################################
function Absenkung(deviceId,Rindex,SollTemp,evohomeClient,HeatSetpointStatus){
if ( getState(Out_Root+D_Raum[Rindex]+'.FensterOffen').val ){ // Fenster offen
// log('Fenster offen: '+D_Raum[Rindex])
if (SollTemp != Temp_FOA) {
evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Hold,Temp_FOA) // Temp. setzen
SollTemp = Temp_FOA
}
} else { // Fenster zu
// log('Fenster zu: '+D_Raum[Rindex])
if (SollTemp == Temp_FOA){
// log('Fenster zu: '+D_Raum[Rindex])
evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Scheduled) // Zeitplan Temperatur
}
if ( getState(Out_Root+D_Raum[Rindex]+'.Abwesend').val ){ // Handy ab
if (getState('javascript.0.haus.Heizung.Stoerung.Abs_Abwesend').val) { // Absenkung ausgeschaltet?
// log('Handy ab: '+D_Raum[Rindex]+' SollTemp: '+SollTemp)
if (SollTemp != Temp_Abw) {
evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Hold,Temp_Abw)
SollTemp = Temp_Abw
}
}
} else {
if (SollTemp == Temp_Abw) {
// log('Handy an-: '+D_Raum[Rindex]+' SollTemp: '+SollTemp) // Handy an
evohomeClient.setHeatSetpoint(deviceId, HeatSetpointStatus.Scheduled) // Zeitplan Temperatur
}
}
}
return SollTemp
} // Absenkung