NEWS
[Skript] Atlantic Wärmepumpe über Cozytouch abfragen
-
WICHTIG: Derzeit gibt es große Probleme beim Server von Cozytouch. Ich weiß nicht, ob das Skript noch weiterentwickelt wird.
Daher rate ich allen, sich https://github.com/tspopp/AquaMQTT anzuschauen. Ist cloudfrei und läuft super!Hallo!
Ich habe eine Skript geschrieben, welches die Werte einer Atlantic / Austria Email Brauchwasserwärmepumpe abfragt. Leider habe ich keine Möglichkeit gefunden, direkt mit der Wärmepumpe zu kommunizieren (io-homecontrol -> wie Velux KLF).
Daher klappt es nur in Verbindung mit der offiziellen Cozytouch-Bridge des Herstellers. Das Skript simuliert mehr oder weniger die App dieser Bridge.
Leider ist das alles sehr "verwurschtelt" da die Abfrage recht komplex ist, aber ich erhalte schon brauchbare Ergebnisse.
Bitte im nachfolgenden Skript Eure Zugangsdaten aus der App eintragen und einfach mal testen.
Folgendes müsstet Ihr anpassen:
username / password
dpRoot: Hier wird der Gerätebaum erstellt
dpSetTemp: Dies ist der DP mit dem ihr die Zieltemperatur vorgebt (also bitte selber anlegen)Beim ersten Aufruf wird es noch Warnungen hageln. Das legt sich dann aber.
Da die Datenpunkte größtenteils generisch angelegt werden müsst ihr euch mal etwas durchkämpfen und brauchbare Details für euch selber herausfinden.
Oder aber hier nachfragen
UPDATE 25.05.2024: Axios anstelle Request verwenden - dadurch keine Warnungen mehr im Log
UPDATE 16.04.2024: Der Datenpunkt für die WW-Solltemperatur (standardmäßig 0_userdata.0.WW-Waermepumpe.WarmwasserSoll) wurde nicht angelegt.
UPDATE 28.10.2023: Es werden jetzt manche Datenpunkte auch mit den richtigen Einheiten angelegt. Das klappt aber leider nur, wenn die Datenpunkte noch nicht vorhanden sind. Im Zweifelsfall also bitte alle DP löschen und das Skript neustarten.
Bugs/Hinweise:
- Der für viele sicherlich interessante Datenpunkt core:V40WaterVolumeEstimationState (geschätzter Gesamtverbrauch Warmwasser in Liter) läuft bei 65536 über, d.h. er fängt dann wieder bei 0 an. Dies kann man aber abfangen, in dem man SourceAnalytix zur Auswertung mit Reset-Erkennung verwendet.
- Die PV-Überschussfunktion, also das manuelle Starten und Stoppen der Wärmepumpe, kann derzeit nicht via Skript gesteuert werden. Hier behelfe ich mir mit einem Shelly an dem SGReady-Kontakt. Der Heizstab kann jedoch mit dem Datenpunkt DHWBoostFull gesteuert werden.
- Für den aktuellen Stromverbrauch sind die DP io:PowerHeatElectricalState und io:PowerHeatPumpState interessant. Sie liefern den aktuellen Verbrauch in Watt. Der DP core:ElectricEnergyConsumptionState hingegen liefert den Gesamtverbrauch in Wh.
const dpRoot = "0_userdata.0.Atlantic"; const dpSetTemp = "0_userdata.0.WW-Waermepumpe.WarmwasserSoll"; const interval = 120; //sec const username = "eMail-Adresse"; const password = "KENNWORT"; // ------------- AB HIER NICHTS ÄNDERN ---------------- // // v2.0 - Migration von Request zu Axios // v1.0 - erstes Release const client_id = "ZThEMW5BM2h2djF0bmMxTXBvQTdHNXVENDZBYTo3aktaS1N3ZlVJNGRvaDdqRWZJVWRzR2VHNWth"; const client_id_api = "alkxU3pBcnYwdWk3cW91OVVGTHRyOFVTNmUwYTpjWkFmYVlMNzVfYTlfcThlMGI4Unk4akU4eWdh"; // Wasserverbrauch (Token) const scope = "openid"; const grant_type = "password"; const token_url = "https://apis.groupe-atlantic.com/token"; const jwt_url = "https://apis.groupe-atlantic.com/magellan/accounts/jwt"; const overkiz_url = "https://ha110-1.overkiz.com/enduser-mobile-web/enduserAPI/"; const atlantic_url = "https://apigam.groupe-atlantic.com:8243"; // Wasserverbrauch (über JWT) var access_token = ""; var access_token_api = ""; // Wasserverbrauch var refresh_token = ""; var id_token = ""; var token_type = ""; var expires_in = -1; var jwt = ""; var jwt_overkiz = ""; var session_cookie = ""; var tokenRefreshTimer; var DHWP_URL = ""; const axios = require('axios'); function getToken() { createState(dpRoot + ".info.connection", false, {read: true, write: false, type: "boolean", role: "indicator", def: false}); axios.post(token_url, { scope: scope, username: "GA-PRIVATEPERSON/" + username, password: password, grant_type: grant_type }, { headers: { "Authorization" : "Basic " + client_id, "Content-Type": "application/x-www-form-urlencoded" }, }) .then(function (response) { if(response.status==200) { var jsonObject = response.data; access_token = jsonObject.access_token; refresh_token = jsonObject.refresh_token; id_token = jsonObject.id_token; expires_in = parseInt(jsonObject.expires_in); session_cookie = ""; jwt = ""; //log(access_token); getJWT(); // --------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getToken(): " + error); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getToken(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function getTokenApi() { // Wasserverbrauch axios.post(atlantic_url + "/token", { grant_type: "client_credentials" }, { headers: { "Authorization" : "Basic " + client_id_api, "Content-Type": "application/x-www-form-urlencoded" }, }) .then(function (response) { if(response.status==200) { var jsonObject = response.data; access_token_api = jsonObject.access_token; getJWTOverkiz(); // --------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getTokenAPI(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getTokenAPI(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function getJWT() { axios.get(jwt_url, { headers: { "Authorization" : "Bearer " + access_token, "Content-Type": "application/json" }, }) .then(function (response) { if(response.status==200) { //log(response); jwt = response.data.replace('"', ''); //log(jwt); getSessionCookie(); // ------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getJWT(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getJWT(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function getSessionCookie() { axios.post(overkiz_url + "login", { 'jwt': jwt }, { headers: { "charset": "UTF-8", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0", "Content-Type": "application/x-www-form-urlencoded" }, }) .then(function (response) { if(response.status==200) { session_cookie = response.headers["set-cookie"][0]; //log(session_cookie); session_cookie = session_cookie.substring(session_cookie.indexOf("JSESSIONID")+11); session_cookie = session_cookie.substring(0, session_cookie.indexOf(";")); if(session_cookie!="") { refreshStates(); // --------> } else { // Error! log("Fehler bei getSessionCookie() - Cookie leer"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; } } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getSessionCookie(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getSessionCookie(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function refreshStates() { axios.post(overkiz_url + "setup/devices/states/refresh", null, { headers: { 'Cookie': "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { getSetup(); // --------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getTokenAPI(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getTokenAPI(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function getSetup() { axios.get(overkiz_url + "setup", { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json" }, }) .then(function (response) { if(response.status==200) { //log(response.data); //log("getSetup ok"); if(getState(dpRoot + ".debug").val) setState(dpRoot + ".rawJson", response.data, true); enumStates(response.data); getTokenApi(); // ------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getSetup(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getSetup(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function enumStates(devTree) { for(var iDev = 0; iDev < devTree["devices"].length; iDev++) { createState(dpRoot + "." + iDev, {name: devTree["devices"][iDev].label, type: "channel"}); createState(dpRoot + "." + iDev + ".enabled", devTree["devices"][iDev].enabled, {read: true, write: false, type: "boolean", role: "state", name: devTree["devices"][iDev].label + " enabled", def: false}); setState(dpRoot + "." + iDev + ".enabled", devTree["devices"][iDev].enabled, true); createState(dpRoot + "." + iDev + ".available", devTree["devices"][iDev].available, {read: true, write: false, type: "boolean", role: "state", name: devTree["devices"][iDev].label + " available", def: false}); setState(dpRoot + "." + iDev + ".available", devTree["devices"][iDev].available, true); createState(dpRoot + "." + iDev + ".oid", devTree["devices"][iDev].oid, {read: true, write: false, type: "string", role: "state", name: devTree["devices"][iDev].label + " oid", def: ""}); setState(dpRoot + "." + iDev + ".oid", devTree["devices"][iDev].oid, true); createState(dpRoot + "." + iDev + ".url", devTree["devices"][iDev].deviceURL, {read: true, write: false, type: "string", role: "state", name: devTree["devices"][iDev].label + " URL", def: ""}); setState(dpRoot + "." + iDev + ".url", devTree["devices"][iDev].deviceURL, true); createState(dpRoot + "." + iDev + ".uiClass", devTree["devices"][iDev].uiClass, {read: true, write: false, type: "string", role: "state", name: devTree["devices"][iDev].label + " uiClass", def: ""}); setState(dpRoot + "." + iDev + ".uiClass", devTree["devices"][iDev].uiClass, true); if(devTree["devices"][iDev].uiClass=="WaterHeatingSystem") { DHWP_URL = devTree["devices"][iDev].deviceURL; } if (typeof devTree["devices"][iDev].states != "undefined") { createState(dpRoot + "." + iDev + ".states", {type: "channel"}); for(var iDevState = 0; iDevState < devTree["devices"][iDev].states.length; iDevState++) { if((devTree["devices"][iDev].states[iDevState].type == "1") || (devTree["devices"][iDev].states[iDevState].type == "2") || (devTree["devices"][iDev].states[iDevState].type == "3")) { createDHWPstate(dpRoot + "." + iDev + ".states." + devTree["devices"][iDev].states[iDevState].name, devTree["devices"][iDev].states[iDevState].value, devTree["devices"][iDev].states[iDevState].type); setState(dpRoot + "." + iDev + ".states." + devTree["devices"][iDev].states[iDevState].name, devTree["devices"][iDev].states[iDevState].value, true); } } } } setState(dpRoot + ".info.connection", true, true); } function getJWTOverkiz() { axios.post(overkiz_url + "enduser/jwt/createToken", null, { headers: { 'Cookie': "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { jwt_overkiz = response.data.jwt; if(jwt_overkiz!="") { //log("jwt overkiz ok"); getWaterConsumption(); // --------> } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getJWTOverkiz(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getJWTOverkiz(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function getWaterConsumption() { axios.post(atlantic_url + "/gam/wcfservice/devicedhwrest/GetWaterConsumption", { 'frequency': 1, 'deviceURL': DHWP_URL.replace("/", "\/"), 'jwtToken': jwt_overkiz }, { headers: { "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0", "Authorization" : "Bearer " + access_token_api, "Locale": "de_DE", //"UniqId": "648C91F2-CA6E-4870-AB47-40FF4A3C1D12", "UniqId": CreateGuid(), "Gfcuid": 3005, "Userid": username, "Platform": "ios 3.5.1 (3)" } }) .then(function (response) { if(response.status==200) { createState(dpRoot + ".consumption.current", response.data.waterConsumptionDetail[response.data.waterConsumptionDetail.length-1].litersConsumed, {read: true, write: false, type: "number", role: "state", name: " Water consumption today", unit: "l", def: 0}); setState(dpRoot + ".consumption.current", response.data.waterConsumptionDetail[response.data.waterConsumptionDetail.length-1].litersConsumed, true); createState(dpRoot + ".consumption.previous", response.data.waterConsumptionDetail[response.data.waterConsumptionDetail.length-2].litersConsumed, {read: true, write: false, type: "number", role: "state", name: " Water consumption yesterday", unit: "l", def: 0}); setState(dpRoot + ".consumption.previous", response.data.waterConsumptionDetail[response.data.waterConsumptionDetail.length-2].litersConsumed, true); if(!getState(dpSetTemp).ack) { setTemperature(getState(dpSetTemp).val); } if(!getState(dpRoot + ".DHWMode").ack) { setDHWMode(); } if(!getState(dpRoot + ".DHWSchedule").ack) { setDHWSchedule(); } if(getState(dpRoot + ".fetchHistory").val) { getHistory(); } } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getWaterConsumption(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getWaterConsumption(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function setTemperature(setTemp) { axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "setTargetTemperature", "parameters" : [ setTemp ] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { setState(dpSetTemp, setTemp, true); } else { // Error! log("Fehler bei setTemperature()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei setTemperature()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei setTemperature()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function setDHWMode() { /* "autoMode", "manualEcoActive", "manualEcoInactive" */ axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "setDHWMode", "parameters" : [ getState(dpRoot + ".DHWMode").val ] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { setState(dpRoot + ".DHWMode", getState(dpRoot + ".DHWMode").val, true); } else { // Error! log("Fehler bei setDHWMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei setDHWMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { log("Fehler bei setDHWMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function setDHWSchedule() { /* "pac24h_elec24h", "pacProg_elecProg" */ axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "setOperatingRange", "parameters" : [ getState(dpRoot + ".DHWSchedule").val ] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { setState(dpRoot + ".DHWSchedule", getState(dpRoot + ".DHWSchedule").val, true); } else { // Error! log("Fehler bei setDHWSchedule()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei setDHWSchedule()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei setDHWSchedule()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function setDHWBooster() { var boostDuration = 0; if(getState(dpRoot + ".DHWBoostFull").val) { boostDuration = 2; } else { setOperatingMode(false, false); return; } axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "setBoostModeDuration", "parameters" : [ boostDuration ] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { sleep(3000); setOperatingMode(true, false); sleep(3000); refreshBooster(); // --------> } else { // Error! log("Fehler bei setDHWBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei setDHWBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei setDHWBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function refreshBooster() { axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "refreshBoostModeDuration", "parameters" : [] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { // --------> } else { // Error! log("Fehler bei refreshBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei refreshBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei refreshBooster()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function setOperatingMode(relaunch, absence) { var sRelaunch; var sAbsence; if(relaunch) { sRelaunch = "on"; } else { sRelaunch = "off"; } if(absence) { sAbsence = "on"; } else { sAbsence = "off"; } axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : "setCurrentOperatingMode", "parameters" : [ { "relaunch": sRelaunch, "absence": sAbsence } ] } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { setState(dpRoot + ".DHWBoostFull", getState(dpRoot + ".DHWBoostFull").val, true); sleep(3000); refreshBooster(); // --------> } else { // Error! log("Fehler bei setOperatingMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei setOperatingMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei setOperatingMode()"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function execOverkizCmd(cmd) { axios.post(overkiz_url + "exec/apply", { "label" : "Cozytouch iOS: 3.5.1 (3)", "actions" : [ { "commands" : [ { "name" : cmd } ], "deviceURL" : DHWP_URL.replace("/", "\/") } ] }, { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" } }) .then(function (response) { if(response.status==200) { if(response.data.execId!="") { if(cmd=="refreshWaterConsumption") getWaterConsumption(); // ------> } else { // Error! log("Fehler bei execOverkizCmd(" + cmd + ")"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } } else { // Error! log("Fehler bei execOverkizCmd(" + cmd + ")"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; } }) .catch(function (error) { // Error! log("Fehler bei execOverkizCmd(" + cmd + ")"); access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; jwt_overkiz = ""; }); } function getHistory() { axios.get(overkiz_url + "history", { headers: { "Cookie" : "JSESSIONID=" + session_cookie, "Content-Type": "application/json", "User-Agent": "Cozytouch/3 CFNetwork/1335.0.3 Darwin/21.6.0" }, }) .then(function (response) { if(response.status==200) { setState(dpRoot + ".HistoryJson", response.data, true); setState(dpRoot + ".fetchHistory", false, true); } else { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getHistory(): " + response.status); setState(dpRoot + ".info.connection", false, true); } }) .catch(function (error) { // Error! access_token = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; session_cookie = ""; log("Fehler bei getHistory(): " + error); setState(dpRoot + ".info.connection", false, true); }); } function CreateGuid() { function _p8(s) { var p = (Math.random().toString(16)+"000000000").substr(2,8); return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ; } return _p8() + _p8(true) + _p8(true) + _p8(); } function createDHWPstate(name, value, valType) { var stateSuffix = ""; // bekannte Attribute behandeln: if(name.endsWith("RSSILevelState")) { stateSuffix = "db"; } else if (name.endsWith("TemperatureState")) { stateSuffix = "°C"; } else if (name.endsWith("PowerHeatElectricalState")) { stateSuffix = "W"; } else if (name.endsWith("PowerHeatPumpState")) { stateSuffix = "W"; } else if (name.endsWith("V40WaterVolumeEstimationState")) { // Wasserbrauch insgesamt -> Überlauf bei 65536! stateSuffix = "l"; } else if (name.endsWith("ElectricEnergyConsumptionState")) { // Stromverbrauch insgesamt stateSuffix = "Wh"; } switch (valType) { case 1: //console.log("1 " + name); if(existsObject(name)) { } else { createState(name, value, {read: true, write: false, type: "number", role: "state", name: name, unit: stateSuffix, def: 0}); } break; case 2: //console.log("2 " + name); if(existsObject(name)) { } else { createState(name, value, {read: true, write: false, type: "number", role: "state", name: name, unit: stateSuffix, def: 0}); } break; case 3: //console.log("3 " + name); if(existsObject(name)) { } else { createState(name, value, {read: true, write: false, type: "string", role: "state", name: name, unit: stateSuffix, def: ""}); } break; } } // -------------------------------------------------------------- createState(dpRoot + ".fetchHistory", false, { name: dpRoot + ".fetchHistory", type: 'boolean', role: 'state', desc: 'Befehlsverlauf einmalig abrufen' }); createState(dpRoot + ".forceUpdate", false, { name: dpRoot + ".forceUpdate", type: 'boolean', role: 'state', desc: 'erzwungenes einmaliges Aktualisieren der Werte' }); createState(dpRoot + ".HistoryJson", "", { name: "History (JSON)", type: 'string', role: 'state', desc: 'Befehlsverlauf' }); createState(dpRoot + ".DHWMode", "", { name: "DHW Operating mode", type: 'string', role: 'state', "states": { "autoMode": "Auto", "manualEcoActive": "ECO aktiv", "manualEcoInactive": "ECO inaktiv" }, desc: 'Betriebsmodus' }); createState(dpRoot + ".DHWSchedule", "", { name: "DHW Schedule", type: 'string', role: 'state', "states": { "pacProg_elecProg": "Zeitplanung", "pac24h_elec24h": "dauerhaft" }, desc: 'Zeitplanung' }); createState(dpRoot + ".DHWBoostFull", "", { name: "DHW Boost", type: 'boolean', role: 'state', desc: 'Heizstab zuschalten' }); createState(dpRoot + ".debug", "", { name: "debug", type: 'boolean', role: 'state', desc: 'Serverantwort protokollieren' }); createState(dpRoot + ".rawJSON", "", { name: "rawJSON", type: 'string', role: 'state', desc: 'Serverantwort' }); createState(dpSetTemp, "", { name: "WW-Solltemperatur", type: 'number', role: 'state', unit: '°C', desc: 'Solltemperatur der Wärmepumpe' }); setState(dpSetTemp, getState(dpSetTemp), true); getToken(); tokenRefreshTimer = setInterval(async function () { // Token verfällt nach 60min access_token = ""; access_token_api = ""; refresh_token = ""; id_token = ""; expires_in = -1; jwt = ""; jwt_overkiz = ""; session_cookie = ""; //log("Token nach Intervall verworfen.") getToken(); }, 600000); schedule('*/' + interval + ' * * * * *', function () { // regelmäßig Token und Zustand abfragen // access_token = ""; // Workaround... if(access_token != "") { getJWT(); } else { getToken(); } }); on({id: dpRoot + ".fetchHistory", change: 'ne'}, function(obj) { if(getState(dpRoot + ".fetchHistory").val) { if(session_cookie != "") { getHistory(); } } }); on({id: dpRoot + ".forceUpdate", change: 'ne'}, function(obj) { if(getState(dpRoot + ".forceUpdate").val) { if(session_cookie != "") { execOverkizCmd("refreshMiddleWaterTemperature"); execOverkizCmd("refreshDHWCapacity"); execOverkizCmd("refreshWaterConsumption"); setState(dpRoot + ".forceUpdate", false); } } }); on({id: dpRoot + ".DHWMode", change: 'ne', ack: false}, function(obj) { if(session_cookie != "") { setDHWMode(); } }); on({id: dpRoot + ".DHWSchedule", change: 'ne', ack: false}, function(obj) { if(session_cookie != "") { setDHWSchedule(); } }); on({id: dpRoot + ".DHWBoostFull", change: 'ne', ack: false}, function(obj) { if(session_cookie != "") { setDHWBooster(); } });
-
@oxident :
Hallo oxident!
Hat sich an deinem Skript noch etwas getan? Wie sind deine Erfahrungen?
Ich habe seit 2 Tagen auch eine Austria Email-WP im Betrieb und würde diese gerne an meinen io.broker anbinden...Wird für die Anbindung unbedingt eine Cozytouch-Bridge benötigt?
Oder reicht auch ein COZYTOUCH THERMOR-INTERFACE?Viele Grüße
hansmann24 -
@hansmann2401 Hi!
Ich werde in den nächsten Tagen nochmal einen Abgleich mit meiner "Produktivversion" machen, ein paar kleine Features habe ich noch eingebaut.Mir ist nur die Cozybridge bekannt. Hatte erst eine (optisch gleiche) Somfy-Bridge geholt und bin nicht weitergekommen.
Dann wurde es die Atlantic-Variante und die klappt winderbar mit der Austria Email.
Von einer Interface-Version ist mir nix bekannt. Ist das auch "Funk/Cloud" oder etwa was Lokales?
-
@oxident :
Hallöle,
das mit dem Thermor-Interface kann man doch vergessen: ich habe jetzt etwas darüber gefunden, es ist ein "verkabeltes" Interface für irgendwelche Heizkörper...
Ich scheue nur etwas die Kosten für eine "echte" Cozytouch Bridge (ca. 150,- Euro) und habe nach Alternativen gesucht...aber scheinbar gibt es nichts anderes...
Jetzt zu der AE-Wärmepumpe:
ich habe eine PV-Anlage, die aktuell viel Strom liefert und ich möchte aus dem iobroker heraus zum einen die Wassertemperatur auslesen und auch den Boost-Modus der Pumpe aktivieren können. Über den "normalen" PV-Kontakt der Pumpe wird ja nur der "PV-Modus" aktiviert, nicht aber gezielt der Heizstab eingeschaltet.
Wäre das über dein Skript möglich? Was geht da noch?
Und die Frage ist:
muss die Bridge am Internet hängen und "nach Hause telefonieren", oder greift das Skript lokal drauf zu?
Soweit ich das Skript deuten kann, wird hier nach extern zugegriffen.VG vom Niederrhein
hansmann24 -
Ja, bisher ist die teure Bridge mit Abfrage über das Internet wohl die einzige Zugriffsmöglichkeit.
Das "Überheizen", also längerer Betrieb der WP bei PV-Ertrag, geht in der Tat auch darüber nicht. Hier habe ich mir einen Shelly an den SGREADY-Kontakt gehangen.
Über die Cozybridge und mein Skript kannst Du jedoch folgendes machen:
Soll-Temperatur setzen
Ist-Temperatur (in der Mitte) auslesen
Eco-Mode an/aus
Heizstab an/aus
Wasserverbrauch auslesen (misst aber nur, wieviel Wasser erwärmt wurde)Das na klar nur über die Cloud...
Aber ich denke, das ist es trotzdem wert! -
@oxident said in [Skript] Atlantic Wärmepumpe über Cozytouch abfragen:
Heizstab an/aus
Hallo,
danke dir für die schnelle Antwort!
Du schreibst, dass man den Heizstab per Skript an/ausmachen kann: das wäre genau das, was ich brauche.
Bedeutet das aber, dass der Boost aktiviert/deaktiviert wird, oder tatsächlich der Heizstab direkt angesprochen wird?
Ich würde es tatsächlich gerne ausprobieren und mir die Bridge dafür holen.
Falls ich Fragen zum Skript habe, melde ich mich. Aber erst nach dem Urlaub...;-) -
@hansmann2401 Jein, also technisch schaltet das Skript den Boost-Modus an und aus.
Dieser aber steuert meiner Erfahrung nach lediglich den Heizstab. Das Übersteuern des Soll-Wertes rein mit der Wärmepumpe kann meiner Meinung nach nur mit der SGr-Schnittstelle stattfinden.
Und die kann halt nur physisch per Relais geschaltet werden.
-
Wir haben uns diese BWWP (von Panasonic, ist aber baugleich) und wollen uns die Cozytouch kaufen.
Könnte man über das Script (durch Erweiterung des Funktionsumfang) auch den Abwesenheitsmodus schalten, also gibt das die App her? Wir wollen möglichst viel mit PV Überschuss heizen und wollen nicht, dass er morgens nach dem Duschen direkt hochheizt, sondern es automatisiert auf später steuern.
-
@sputnik24 Hmm, das kann das Skript noch nicht, aber dürfte sicherlich machbar sein.
Ich mache das jedoch im Moment anders: Ich stelle die Solltemperatur recht gering ein (45°) und die Zeitsteuerung auf 11-20 Uhr.
PV-Überschuss signalisiere ich dann via Shelly am SG-Ready-Eingang.
Wie würdest Du das machen?
-
@oxident BWWP ist noch nicht in Betrieb und Bridge noch nicht da. Zeitsteuerung kannte ich nicht, klingt aber nach einem Plan. Ich hätte es abends in die Abwesenheit geschickt und morgens irgendwann (2 h nach Sonnenaufgang z.B.) wieder in den Eco Mode. Ausnahme, wenn man abends badet und morgens warmes Wasser will, dann ist das eben der Luxus, den man sich gönnt.
PV Modus wollte ich über Homematic und dem potentialfreien Schaltkontakt machen, da wir da noch einen ungenutzt da haben. Shelly für Hutschiene nutze ich zur Leistungsmessung.
Wie funktioniert die Zeitsteuerung?
-
@sputnik24 Klingt gut.
Die Zeitsteuerung ist in der BWWP integriert und dort kannst du halt sagen, in welchen Zeiträumen er arbeiten darf.
Die PV-Funktion via HM/Shelly ist jedoch 24h verfüg- und nutzbar.
Boost ist dann noch zusätzlich der Heizstab. Das geht mit dem Skript.
Abwesenheit würde halt lediglich die Zeitsteuerung deaktivieren. Kannste aber vielleicht auch einfach via schaltbarer Steckdose lösen.
-
@oxident Und die API hast du Reverse engineered, indem du den Traffic der App inklusive TLS Handshake mitgeschnitten hast oder denke ich da zu kompliziert?
-
@sputnik24 Genau so. Proxy auf dem Rechner installiert und dem iPad eine Fake-Zertifilat untergeschoben.
Ist aber leider alles ganz schön "verwurschtelt" und ich hoffe, die ändern nix.
-
@oxident bin Mal gespannt. Installateur war heute da. Wir haben die Panasonic gekauft, die baugleich zur Austria sein soll. Einen Zirkulationsanschluss hat sie schon Mal nicht, obwohl der Shop das gesagt hat. Bin Mal gespannt, ob die Bridge überhaupt tut. Gerade sehr frustriert deswegen.
-
@sputnik24 Mich wundert es ein wenig, dass die baugleich sein sollen. Panasonic baut doch eigene Systeme und müsste nicht das Atlantic/Austria/Thermor-Modell kaufen.
Vielleicht meinte Dein Händler nur, dass die Leistungswerte vergleichbar sind?
-
@oxident nein. Wir haben die Aussage sogar direkt von Panasonic. Es ist die PAW-DHW200F. Das 270er Modell gibt es mit Zirku, die 200 nur ohne. Aber brauchen wir nicht, wird stillgelegt.
-
@sputnik24 Alles klar. Die sieht wirklich exakt wie meine Austria aus. Dann sollte es klappen!
Interessant wird nur, ob die bei der Bridge auch die gleichen Server nutzen. Hatte erst eine (baugleiche) Bridge von Somfy. Musste ich aber gegen die Variante von Atlantic tauschen um die BWWP koppeln zu können.
Viel Erfolg!
-
@oxident Ich hab dir eine PN geschrieben.
-
Hallo, ich melde mich hier nun auch mal zu Wort. Ich habe ebenfalls eine Austria Email BWWP die per Cozytouch steuerbar sein soll. Sie läuft seit einem Jahr bei uns. Seit diesem Sommer haben wir ebenfalls eine PV Anlage. Nun würde ich das Zusammenspiel gerne optimieren.
Bezüglich des PV Betriebes bietet die WP ja über einen einfachen Schalter die Möglichkeit in den PV Betrieb zu gehen. Hat das schonmal jemand ausprobiert?
Ungünstig finde ich nur das der Heizstab dabei nicht eingeschaltet wird wenn man nicht möchte das er auch im normalen Betrieb aktiviert wird.
Dazu bräuchte man dann das Skript. Ich finde dieses wirklich sinnvoll. Wobei man sich auch den Schalter an der WP sparen könnte wenn man den Boost über das Skript aktivieren kann.
Erstmal noch eine grundsätzliche Frage.
Wird hier von der Cozytouch Bridge Version 2 (
002449) geredet oder von der "alten" (Austria Teilenummer: 001231)? -
@pvoptimist Also meiner Erfahrung nach klappt nur die "alte" Bridge, da nur diese mit dem Server von Atlantic redet.
Die PV-Funktion kann man ja leider nur über den Schaltkontakt (SGready) nutzen. Mache ich seit Beginn mit einem Shelly.
Boost geht ja in der Tat mit dem Skript wunderbar und man beides prima in iobroker via Blockly automatisieren. Bei mir folgt es der Logik "wenn Netzeinspeisung/Akkuladung >600W dann PV-Boost" und "wenn >2000W dann Boost"
Ich denke, mit Skript, Shelly und Kreativität wirst Du viel machen können