Hab hier im Beitrag mal einige Informationen gesammelt und mich mit ChatGPT mal um ein aktuelles Skript gekümmert. Vielen Dank für die Vorarbeit. Es hat jetzt auch schreibbare Datenpunkte für Normal und Absenktemperatur, Boiler Soll&Stütztemp, sowie Boiler Betriebsart erzeugt. Außerdem mit der Möglichkeit, für einen lokalen login. Einfach host, username und password ändern im ersten Abschnitt "Konfiguration"
/**
* Script für Mtec / Hautec / Keba Wärmepumpe
* Verwendet AXIOS statt request
*/
const axios = require('axios');
// ==== KONFIGURATION ====
const heizung_host = '192.168.xxx.xxx';
const username = 'BENUTZERNAME';
const password = 'PASSWORT';
// Konstanten
const urlOfHeatpump = 'https://' + heizung_host + '/var/readWriteVars';
const urlWriteHeatpump = 'https://' + heizung_host + '/var/readWriteVars?action=set';
// Variablen die wir lesen wollen
const jsonRequest = [
// bereits vorhandene
{ "name": "APPL.CtrlAppl.sParam.param.setControlMode" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].tempRoom.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.hotWaterTank[0].topTemp.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.outdoorTemp.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].values.setValue" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].param.offsetRoomTemp" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].values.selectedSetTemp" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].values.heatRequest" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].values.coolRequest" },
{ "name": "APPL.CtrlAppl.sParam.hotWaterTank[0].values.heatRequestTop" },
{ "name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.normalSetTempMax.value" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].tempReflux.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].values.flowSetTemp" },
{ "name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.operatingMode" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].param.normalSetTemp" },
{ "name": "APPL.CtrlAppl.sParam.heatCircuit[0].param.reducedSetTemp" },
{ "name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.reducedSetTempMax.value" },
// Quelle / WP-Temperaturen (Namen je nach Firmware, hier typische KEBA-Namen)
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].TempSourceIn.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].TempSourceOut.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].TempHeatFlow.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].TempCompressorIn.values.actValue" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].TempCompressorOut.values.actValue" },
// Pumpen- / Verdichter-Leistungen (skaliert, z.B. 0..1)
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].CircPump.values.setValueScaled" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].Source.values.setValueScaled" },
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].Compressor.values.setValueScaled" },
// WP-Zustand
{ "name": "APPL.CtrlAppl.sParam.heatpump[0].values.heatpumpState" },
// Estrichprogramm aktiv?
{ "name": "APPL.CtrlAppl.sParam.screedDrying.values.active" },
// PV-Überschuss aktiv?
{ "name": "APPL.CtrlAppl.sParam.photovoltaics.values.excessEnergyActive" }
];
// ==== STATES ANLEGEN ====
// Allgemeine Temperaturen
createState('javascript.'+instance+'.Heizung.Aussentemperatur', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Boilertemperatur.ist', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Boilertemperatur.soll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: true });
createState('javascript.'+instance+'.Heizung.Boilertemperatur.reducedSoll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: true });
// Heizkreis-Ordner (wie gewünscht)
createState('javascript.'+instance+'.Heizung.Heizkreis.Raumtemperatur.soll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: true });
createState('javascript.'+instance+'.Heizung.Heizkreis.Heizung.aufheizen', false, { type: 'boolean', role: 'indicator', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Heizkreis.NormalTemp.soll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: true });
createState('javascript.'+instance+'.Heizung.Heizkreis.ReducedTemp.soll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: true });
// Rücklauf
createState('javascript.'+instance+'.Heizung.RuecklaufTemp.ist', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.RuecklaufTemp.soll', 0, { type: 'number', role: 'level.temperature', unit: '°C', read: true, write: false });
// Boiler-Betriebsart
createState('javascript.'+instance+'.Heizung.Boiler.aufheizen', false, { type: 'boolean', role: 'indicator', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Boiler.Betriebsart', 0, {
type: 'number',
role: 'level',
states: {
"0": "Aus",
"1": "Auto",
"2": "Ein",
"3": "ManAufheizen"
},
read: true,
write: true
});
// Quelle / WP / Pumpen / Status
createState('javascript.'+instance+'.Heizung.QuelleTemp.Ein', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.QuelleTemp.Aus', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Heizkreis.VorlaufTemp.ist', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.WP.VerdichterTemp.Ein', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.WP.VerdichterTemp.Aus', 0, { type: 'number', role: 'value.temperature', unit: '°C', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Pumpe.Heizkreis.Soll', 0, { type: 'number', role: 'value', unit: '', read: true, write: false });
createState('javascript.'+instance+'.Heizung.Pumpe.Quelle.Soll', 0, { type: 'number', role: 'value', unit: '', read: true, write: false });
createState('javascript.'+instance+'.Heizung.WP.Verdichter.Soll', 0, { type: 'number', role: 'value', unit: '', read: true, write: false });
createState('javascript.'+instance+'.Heizung.WP.Status', 0, { type: 'number', role: 'value', read: true, write: false });
createState('javascript.'+instance+'.Heizung.WP.StatusText', '', { type: 'string', role: 'text', read: true, write: false });
// Estrichprogramm / PV
createState('javascript.'+instance+'.Heizung.Estrichprogramm.aktiv', false, { type: 'boolean', role: 'indicator', read: true, write: false });
createState('javascript.'+instance+'.Heizung.PV.UeberschussAktiv', false, { type: 'boolean', role: 'indicator', read: true, write: false });
// Hilfsfunktion: WP-Statuscode in Text umwandeln (Beispiel-Mapping, je nach Doku anpassen)
function mapHeatpumpStateToText(code) {
switch (code) {
case 0: return 'Standby';
case 1: return 'Anforderung';
case 2: return 'Heizen';
case 3: return 'Abtauen';
case 4: return 'Warmwasser';
case 5: return 'Fehler';
default: return 'Unbekannt (' + code + ')';
}
}
// ==== FUNKTION: Daten lesen ====
async function readHeatpump() {
try {
const response = await axios.post(urlOfHeatpump, jsonRequest, {
httpsAgent: new (require('https').Agent)({
rejectUnauthorized: false // Selbstsigniertes KEBA-Zertifikat akzeptieren
}),
auth: {
username: username,
password: password
},
headers: {
'Content-Type': 'application/json'
}
});
const data = {};
response.data.forEach(item => data[item.name] = item.value);
// Allgemeine Temperaturen
setState('javascript.'+instance+'.Heizung.Aussentemperatur',
parseFloat(data["APPL.CtrlAppl.sParam.outdoorTemp.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.Boilertemperatur.ist',
parseFloat(data["APPL.CtrlAppl.sParam.hotWaterTank[0].topTemp.values.actValue"]) || 0, true);
// Heizkreis-Soll (berechneter Sollwert der WP)
setState('javascript.'+instance+'.Heizung.Heizkreis.Raumtemperatur.soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatCircuit[0].values.setValue"]) || 0, true);
// Heizanforderung (Heizkreis) nur lesen
setState('javascript.'+instance+'.Heizung.Heizkreis.Heizung.aufheizen',
data["APPL.CtrlAppl.sParam.heatCircuit[0].values.heatRequest"] == "1", true);
// Boiler aufheizen nur lesen
const heatRequestTop = data["APPL.CtrlAppl.sParam.hotWaterTank[0].values.heatRequestTop"];
setState('javascript.'+instance+'.Heizung.Boiler.aufheizen',
heatRequestTop === "true" || heatRequestTop === "1" || heatRequestTop === true, true);
// Rücklauf
setState('javascript.'+instance+'.Heizung.RuecklaufTemp.ist',
parseFloat(data["APPL.CtrlAppl.sParam.heatCircuit[0].tempReflux.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.RuecklaufTemp.soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatCircuit[0].values.flowSetTemp"]) || 0, true);
// Boiler-Betriebsart
setState('javascript.'+instance+'.Heizung.Boiler.Betriebsart',
parseInt(data["APPL.CtrlAppl.sParam.hotWaterTank[0].param.operatingMode"]) || 0, true);
// Normal- und Absenktemperatur (Heizkreis)
setState('javascript.'+instance+'.Heizung.Heizkreis.NormalTemp.soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatCircuit[0].param.normalSetTemp"]) || 0, true);
setState('javascript.'+instance+'.Heizung.Heizkreis.ReducedTemp.soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatCircuit[0].param.reducedSetTemp"]) || 0, true);
// Boiler Soll-Temperaturen
setState('javascript.'+instance+'.Heizung.Boilertemperatur.reducedSoll',
parseFloat(data["APPL.CtrlAppl.sParam.hotWaterTank[0].param.reducedSetTempMax.value"]) || 0, true);
setState('javascript.'+instance+'.Heizung.Boilertemperatur.soll',
parseFloat(data["APPL.CtrlAppl.sParam.hotWaterTank[0].param.normalSetTempMax.value"]) || 0, true);
// === neue Datenpunkte setzen ===
// Quelle / WP Temperaturen
setState('javascript.'+instance+'.Heizung.QuelleTemp.Ein',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].TempSourceIn.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.QuelleTemp.Aus',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].TempSourceOut.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.Heizkreis.VorlaufTemp.ist',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].TempHeatFlow.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.WP.VerdichterTemp.Ein',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].TempCompressorIn.values.actValue"]) || 0, true);
setState('javascript.'+instance+'.Heizung.WP.VerdichterTemp.Aus',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].TempCompressorOut.values.actValue"]) || 0, true);
// Pumpen-/Verdichter-Sollwerte (skaliert)
setState('javascript.'+instance+'.Heizung.Pumpe.Heizkreis.Soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].CircPump.values.setValueScaled"]) || 0, true);
setState('javascript.'+instance+'.Heizung.Pumpe.Quelle.Soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].Source.values.setValueScaled"]) || 0, true);
setState('javascript.'+instance+'.Heizung.WP.Verdichter.Soll',
parseFloat(data["APPL.CtrlAppl.sParam.heatpump[0].Compressor.values.setValueScaled"]) || 0, true);
// WP-Status
const hpState = parseInt(data["APPL.CtrlAppl.sParam.heatpump[0].values.heatpumpState"]) || 0;
setState('javascript.'+instance+'.Heizung.WP.Status', hpState, true);
setState('javascript.'+instance+'.Heizung.WP.StatusText', mapHeatpumpStateToText(hpState), true);
// Estrichprogramm
setState('javascript.'+instance+'.Heizung.Estrichprogramm.aktiv',
data["APPL.CtrlAppl.sParam.screedDrying.values.active"] == "true", true);
// PV-Überschuss aktiv?
setState('javascript.'+instance+'.Heizung.PV.UeberschussAktiv',
data["APPL.CtrlAppl.sParam.photovoltaics.values.excessEnergyActive"] == "true", true);
} catch (err) {
log("Fehler beim Lesen der Wärmepumpe: " + err, 'error');
}
}
// ==== INTERVALL: alle 1 Minute lesen ====
schedule("* * * * *", readHeatpump);
// ==== SCHREIBEN: Boiler-Betriebsart ====
on('javascript.'+instance+'.Heizung.Boiler.Betriebsart', async function (obj) {
if (!obj || obj.state.ack) return;
const newValue = String(obj.state.val);
try {
await axios.post(urlWriteHeatpump, [{
"name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.operatingMode",
"value": newValue
}], {
httpsAgent: new (require('https').Agent)({
rejectUnauthorized: false
}),
auth: {
username: username,
password: password
},
headers: {
'Content-Type': 'application/json'
}
});
log("Betriebsart erfolgreich gesetzt auf: " + newValue);
} catch (err) {
log("Fehler beim Schreiben der Betriebsart: " + err, 'error');
}
});
// ==== SCHREIBEN: Boilertemperaturen ====
on('javascript.'+instance+'.Heizung.Boilertemperatur.soll', async function (obj) {
if (!obj || obj.state.ack) return;
const newValue = String(obj.state.val);
log("Heizung: schreibe Boilertemperatur.soll = " + newValue, 'info');
try {
await axios.post(urlWriteHeatpump, [{
"name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.normalSetTempMax.value",
"value": newValue
}], {
httpsAgent: new (require('https').Agent)({
rejectUnauthorized: false
}),
auth: {
username: username,
password: password
},
headers: {
'Content-Type': 'application/json'
}
});
log("Boilertemperatur.soll erfolgreich gesetzt auf: " + newValue, 'info');
} catch (err) {
log("Fehler beim Schreiben Boilertemperatur.soll: " + err, 'error');
}
});
on('javascript.'+instance+'.Heizung.Boilertemperatur.reducedSoll', async function (obj) {
if (!obj || obj.state.ack) return;
const newValue = String(obj.state.val);
log("Heizung: schreibe Boilertemperatur.reducedSoll = " + newValue, 'info');
try {
await axios.post(urlWriteHeatpump, [{
"name": "APPL.CtrlAppl.sParam.hotWaterTank[0].param.reducedSetTempMax.value",
"value": newValue
}], {
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
auth: { username: username, password: password },
headers: { 'Content-Type': 'application/json' }
});
log("Boilertemperatur.reducedSoll erfolgreich gesetzt auf: " + newValue, 'info');
} catch (err) {
log("Fehler beim Schreiben reducedSetTempMax.value: " + err, 'error');
}
});
// ==== SCHREIBEN: Normal- und Absenktemperatur Heizkreis ====
on('javascript.'+instance+'.Heizung.Heizkreis.NormalTemp.soll', async function (obj) {
if (!obj || obj.state.ack) return;
const newValue = String(obj.state.val);
log("Schreibe Normal-Temperatur (Heizkreis) = " + newValue, 'info');
try {
await axios.post(urlWriteHeatpump, [{
"name": "APPL.CtrlAppl.sParam.heatCircuit[0].param.normalSetTemp",
"value": newValue
}], {
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
auth: { username: username, password: password },
headers: { 'Content-Type': 'application/json' }
});
log("NormalTemp erfolgreich gesetzt.", 'info');
} catch (err) {
log("Fehler beim Schreiben NormalTemp: " + err, 'error');
}
});
on('javascript.'+instance+'.Heizung.Heizkreis.ReducedTemp.soll', async function (obj) {
if (!obj || obj.state.ack) return;
const newValue = String(obj.state.val);
log("Schreibe Reduzierte Temperatur (Heizkreis) = " + newValue, 'info');
try {
await axios.post(urlWriteHeatpump, [{
"name": "APPL.CtrlAppl.sParam.heatCircuit[0].param.reducedSetTemp",
"value": newValue
}], {
httpsAgent: new (require('https').Agent)({ rejectUnauthorized: false }),
auth: { username: username, password: password },
headers: { 'Content-Type': 'application/json' }
});
log("ReducedTemp erfolgreich gesetzt.", 'info');
} catch (err) {
log("Fehler beim Schreiben ReducedTemp: " + err, 'error');
}
});