4654 lines
230 KiB
Perl
4654 lines
230 KiB
Perl
#########################################################################
|
||
# $Id$
|
||
# fhem Modul für Viessmann API. Based on investigation of "thetrueavatar"
|
||
# (https://github.com/thetrueavatar/Viessmann-Api)
|
||
#
|
||
# This file is part of fhem.
|
||
#
|
||
# Fhem is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 2 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# Fhem is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
||
#
|
||
|
||
# https://wiki.fhem.de/wiki/DevelopmentModuleAPI
|
||
# https://forum.fhem.de/index.php/topic,93664.0.html
|
||
# https://www.viessmann-community.com/t5/Announcements/Important-adjustment-in-IoT-features-Split-heating-circuits-and/td-p/281527
|
||
# https://forum.fhem.de/index.php/topic,93664.msg1257651.html#msg1257651
|
||
# https://www.viessmann-community.com/t5/Getting-started-programming-with/Syntax-for-setting-a-value/td-p/374222
|
||
# https://forum.fhem.de/index.php?msg=1326376
|
||
|
||
sub vitoconnect_Initialize; # Modul initialisieren und Namen zusätzlicher Funktionen bekannt geben
|
||
sub vitoconnect_Define; # wird beim 'define' eines Gerätes aufgerufen
|
||
sub vitoconnect_Undef; # wird beim Löschen einer Geräteinstanz aufgerufen
|
||
sub vitoconnect_Get; # bisher kein 'get' implementiert
|
||
sub vitoconnect_Set; # Implementierung set-Befehle
|
||
sub vitoconnect_Set_New; # Implementierung set-Befehle New dynamisch auf raw readings
|
||
sub vitoconnect_Set_SVN; # Implementierung set-Befehle SVN
|
||
sub vitoconnect_Set_Roger; # Implementierung set-Befehle Roger
|
||
sub vitoconnect_Attr; # Attribute setzen/ändern/löschen
|
||
|
||
sub vitoconnect_GetUpdate; # Abfrage aller Werte starten
|
||
|
||
sub vitoconnect_getCode; # Werte für: Access-Token, Install-ID, Gateway anfragen
|
||
sub vitoconnect_getCodeCallback; # Rückgabe: Access-Token, Install-ID, Gateway von vitoconnect_getCode Anfrage
|
||
|
||
sub vitoconnect_getAccessToken; # Access & Refresh-Token holen
|
||
sub vitoconnect_getAccessTokenCallback; # Access & Refresh-Token speichern, Antwort auf: vitoconnect_getAccessToken
|
||
|
||
sub vitoconnect_getRefresh; # neuen Access-Token anfragen
|
||
sub vitoconnect_getRefreshCallback; # neuen Access-Token speichern
|
||
|
||
sub vitoconnect_getGw; # Abfrage Gateway-Serial
|
||
sub vitoconnect_getGwCallback; # Gateway-Serial speichern, Anwort von Abfrage Gateway-Serial
|
||
|
||
sub vitoconnect_getInstallation; # Abfrage Install-ID
|
||
sub vitoconnect_getInstallationCallback;# Install-ID speichern, Antwort von Abfrage Install-ID
|
||
|
||
sub vitoconnect_getDevice; # Abfrage Device-ID
|
||
sub vitoconnect_getDeviceCallback; # Device-ID speichern, Anwort von Abfrage Device-ID
|
||
|
||
sub vitoconnect_getFeatures; # Abruf GW Features
|
||
sub vitoconnect_getFeaturesCallback; # gw_features speichern
|
||
|
||
sub vitoconnect_errorHandling; # Errors bearbeiten für alle Calls
|
||
sub vitoconnect_getResource; # API call for all Gateways
|
||
sub vitoconnect_getResourceCallback; # Get all API readings
|
||
sub vitoconnect_getPowerLast; # Write the power reading of the full last day to the DB
|
||
|
||
sub vitoconnect_actionTimerWrapper; # Send call to API with timer
|
||
sub vitoconnect_action; # Send call to API
|
||
|
||
sub vitoconnect_getErrorCode; # Resolve Error code
|
||
|
||
sub vitoconnect_StoreKeyValue; # Werte verschlüsselt speichern
|
||
sub vitoconnect_ReadKeyValue; # verschlüsselte Werte auslesen
|
||
sub vitoconnect_DeleteKeyValue; # verschlüsselte Werte löschen
|
||
|
||
|
||
package main;
|
||
use strict;
|
||
use warnings;
|
||
use Time::HiRes qw(gettimeofday);
|
||
use JSON;
|
||
#use JSON::XS qw( decode_json ); #Could be faster, but caused error for Schlimbo PERL WARNING: Prototype mismatch: sub main::decode_json ($;$$) vs ($) at /usr/local/lib/perl5/5.36.3/Exporter.pm line 63.
|
||
use HttpUtils;
|
||
use Encode qw(decode encode);
|
||
use Data::Dumper;
|
||
use Path::Tiny;
|
||
use DateTime;
|
||
use Time::Piece;
|
||
use Time::Seconds;
|
||
|
||
eval "use FHEM::Meta;1" or my $modMetaAbsent = 1; ## no critic 'eval'
|
||
use FHEM::SynoModules::SMUtils qw (
|
||
moduleVersion
|
||
); # Hilfsroutinen Modul
|
||
|
||
my %vNotesIntern = (
|
||
"0.9.5" => "15.10.2025 Fix duplicate timer in case of password update (getCode)",
|
||
"0.9.4" => "15.10.2025 More logging for timers",
|
||
"0.9.3" => "15.10.2025 URL to dev portal updated",
|
||
"0.9.2" => "15.09.2025 Fix Not a HASH reference at ./FHEM/98_vitoconnect.pm line 3818 when set action error",
|
||
"0.9.1" => "11.09.2025 In case of set action when token is expired get new token and try again",
|
||
"0.9.0" => "09.03.2025 New api and iam URL (viessmann-climatesolutions.com)",
|
||
"0.8.7" => "09.03.2025 Fix return value when using SVN or Roger",
|
||
"0.8.6" => "24.02.2025 Adapt schedule data before sending",
|
||
"0.8.5" => "24.02.2025 fix error when calling setter from FHEMWEB",
|
||
"0.8.4" => "24.02.2025 also order mode, start, end, position in schedule",
|
||
"0.8.3" => "23.02.2025 fix order of days for type schedule readings",
|
||
"0.8.2" => "22.02.2025 improved State reading in case of unknown error",
|
||
"0.8.1" => "20.02.2025 replace U+FFFD (unknown character with [VUC] see https://forum.fhem.de/index.php?msg=1334504, also fill reason in error case from extended payload",
|
||
"0.8.0" => "18.02.2025 enhanced error mapping now also language dependent, closing of file_handles, removed JSON::XS",
|
||
"0.7.8" => "17.02.2025 fixed undef warning thanks cnkru",
|
||
"0.7.7" => "17.02.2025 introduced clearMappedErrors",
|
||
"0.7.6" => "17.02.2025 removed usage of html libraries",
|
||
"0.7.5" => "16.02.2025 Get mapped error codes and store them in readings",
|
||
"0.7.4" => "16.02.2025 Removed Unknow attr vitoconnect, small bugfix DeleteKeyValue",
|
||
"0.7.3" => "16.02.2025 Write *.err file in case of error. Fixed DeleteKeyValue thanks Schlimbo",
|
||
"0.7.2" => "07.02.2025 Attr logging improved",
|
||
"0.7.1" => "07.02.2025 Code cleanups",
|
||
"0.7.0" => "06.02.2025 vitoconnect_installationID checked now for at least length 2, see https://forum.fhem.de/index.php?msg=1333072, error handling when setting attributs automatic introduced",
|
||
"0.6.3" => "04.02.2025 Small bug fixes, removed warnings",
|
||
"0.6.2" => "28.01.2025 Very small bugfixes ",
|
||
"0.6.1" => "28.01.2025 Rework of module documentation",
|
||
"0.6.0" => "23.01.2025 Total rebuild of initialization and gw handling. In case of more than one installation or gw you have to set it via".
|
||
"selectDevice in the set of the device. The attributes vitoconnect_serial and vitoconnect_installationID will be populated".
|
||
"handling of getting installation and serial changed. StoredValues are now deleted. Other fixes and developments",
|
||
"0.5.0" => "02.01.2025 Added attribute installationID, in case you use two installations, see https://forum.fhem.de/index.php?msg=1329165",
|
||
"0.4.2" => "31.12.2024 Small fix for Vitoladens 300C, heating.circuits.0.operating.programs.comfort",
|
||
"0.4.1" => "30.12.2024 Bug fixes, fixed Releasenotes, changed debugging texts and messages in Set_New",
|
||
"0.4.0" => "28.12.2024 Fixed setNew to work again automatically in case of one serial in gateways,".
|
||
"for more than one serial you have to define the serial you want to use",
|
||
"0.3.2" => "27.12.2024 Set in case of activate and deactivate request the active value of the reading",
|
||
"0.3.1" => "19.12.2024 New attribute vitoconnect_disable_raw_readings",
|
||
"0.3.0" => "18.12.2024 Fix setter new for cases where more than one gateway is actively pulled in 2 devices.",
|
||
"0.2.1" => "16.12.2024 German and English texts in UI",
|
||
"0.2.0" => "14.12.2024 FVersion introduced, a bit of code beautifying".
|
||
"sort keys per reading to ensure power readings are in the right order, day before dayvalue",
|
||
"0.1.1" => "12.12.2024 In case of more than one Gateway only allow Set_New if serial is provided. ".
|
||
"Get Object and Hash in Array readings. E.g. device.messages.errors.raw. ".
|
||
"In case of expired token (every hour) do not do uncessary gateway calls, just get the new token. ".
|
||
"This will safe API calls and reduce the API overhead. ",
|
||
"0.1.0" => "12.12.2024 first release with Version. "
|
||
);
|
||
|
||
my $client_secret = "2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c";
|
||
my $callback_uri = "http://localhost:4200/";
|
||
my $apiBaseURL = "https://api.viessmann-climatesolutions.com";
|
||
my $iamBaseURL = "https://iam.viessmann-climatesolutions.com";
|
||
my $iotURL_V1 = "$apiBaseURL/iot/v1/equipment/";
|
||
my $iotURL_V2 = "$apiBaseURL/iot/v2/features/";
|
||
my $authorizeURL = "$iamBaseURL/idp/v2/authorize";
|
||
my $tokenURL = "$iamBaseURL/idp/v2/token";
|
||
my $errorURL_V3 = "$apiBaseURL/service-documents/v3/error-database";
|
||
|
||
my $RequestListMapping; # Über das Attribut Mapping definierte Readings zum überschreiben der RequestList
|
||
my %translations; # Über das Attribut translations definierte Readings zum überschreiben der RequestList
|
||
|
||
|
||
# Feste Readings, orignal Verhalten des Moduls, können über RequestListMapping oder translations überschrieben werden.
|
||
# letzte SVN Version vor meinen Änderungen am 2024-11-16 oder letzte Version von Roger vom 8. November (https://forum.fhem.de/index.php?msg=1292441)
|
||
my $RequestListSvn = {
|
||
"heating.boiler.serial.value" => "Kessel_Seriennummer",
|
||
"heating.boiler.temperature.value" => "Kessel_Solltemperatur",
|
||
"heating.boiler.sensors.temperature.commonSupply.status" =>
|
||
"Kessel_Common_Supply",
|
||
"heating.boiler.sensors.temperature.commonSupply.unit" =>
|
||
"Kessel_Common_Supply_Temperatur/Einheit",
|
||
"heating.boiler.sensors.temperature.commonSupply.value" =>
|
||
"Kessel_Common_Supply_Temperatur",
|
||
"heating.boiler.sensors.temperature.main.status" => "Kessel_Status",
|
||
"heating.boiler.sensors.temperature.main.unit" =>
|
||
"Kesseltemperatur/Einheit",
|
||
"heating.boiler.sensors.temperature.main.value" => "Kesseltemperatur",
|
||
"heating.boiler.temperature.unit" => "Kesseltemperatur/Einheit",
|
||
|
||
"heating.burner.active" => "Brenner_aktiv",
|
||
"heating.burner.automatic.status" => "Brenner_Status",
|
||
"heating.burner.automatic.errorCode" => "Brenner_Fehlercode",
|
||
"heating.burner.current.power.value" => "Brenner_Leistung",
|
||
"heating.burner.modulation.value" => "Brenner_Modulation",
|
||
"heating.burner.statistics.hours" => "Brenner_Betriebsstunden",
|
||
"heating.burner.statistics.starts" => "Brenner_Starts",
|
||
|
||
"heating.burners.0.active" => "Brenner_1_aktiv",
|
||
"heating.burners.0.modulation.unit" => "Brenner_1_Modulation/Einheit",
|
||
"heating.burners.0.modulation.value" => "Brenner_1_Modulation",
|
||
"heating.burners.0.statistics.hours" => "Brenner_1_Betriebsstunden",
|
||
"heating.burners.0.statistics.starts" => "Brenner_1_Starts",
|
||
|
||
"heating.circuits.enabled" => "Aktive_Heizkreise",
|
||
"heating.circuits.0.active" => "HK1-aktiv",
|
||
"heating.circuits.0.type" => "HK1-Typ",
|
||
"heating.circuits.0.circulation.pump.status" => "HK1-Zirkulationspumpe",
|
||
"heating.circuits.0.circulation.schedule.active" =>
|
||
"HK1-Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.0.circulation.schedule.entries" =>
|
||
"HK1-Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.0.frostprotection.status" => "HK1-Frostschutz_Status",
|
||
"heating.circuits.0.geofencing.active" => "HK1-Geofencing",
|
||
"heating.circuits.0.geofencing.status" => "HK1-Geofencing_Status",
|
||
"heating.circuits.0.heating.curve.shift" => "HK1-Heizkurve-Niveau",
|
||
"heating.circuits.0.heating.curve.slope" => "HK1-Heizkurve-Steigung",
|
||
"heating.circuits.0.heating.schedule.active" =>
|
||
"HK1-Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.0.heating.schedule.entries" =>
|
||
"HK1-Zeitsteuerung_Heizung",
|
||
"heating.circuits.0.name" => "HK1-Name",
|
||
"heating.circuits.0.operating.modes.active.value" => "HK1-Betriebsart",
|
||
"heating.circuits.0.operating.modes.dhw.active" => "HK1-WW_aktiv",
|
||
"heating.circuits.0.operating.modes.dhwAndHeating.active" =>
|
||
"HK1-WW_und_Heizen_aktiv",
|
||
"heating.circuits.0.operating.modes.dhwAndHeatingCooling.active" =>
|
||
"HK1-WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.0.operating.modes.forcedNormal.active" =>
|
||
"HK1-Solltemperatur_erzwungen",
|
||
"heating.circuits.0.operating.modes.forcedReduced.active" =>
|
||
"HK1-Reduzierte_Temperatur_erzwungen",
|
||
"heating.circuits.0.operating.modes.heating.active" => "HK1-heizen_aktiv",
|
||
"heating.circuits.0.operating.modes.normalStandby.active" =>
|
||
"HK1-Normal_Standby_aktiv",
|
||
"heating.circuits.0.operating.modes.standby.active" => "HK1-Standby_aktiv",
|
||
"heating.circuits.0.operating.programs.active.value" =>
|
||
"HK1-Programmstatus",
|
||
"heating.circuits.0.operating.programs.comfort.active" =>
|
||
"HK1-Solltemperatur_comfort_aktiv",
|
||
"heating.circuits.0.operating.programs.comfort.demand" =>
|
||
"HK1-Solltemperatur_comfort_Anforderung",
|
||
"heating.circuits.0.operating.programs.comfort.temperature" =>
|
||
"HK1-Solltemperatur_comfort",
|
||
"heating.circuits.0.operating.programs.eco.active" =>
|
||
"HK1-Solltemperatur_eco_aktiv",
|
||
"heating.circuits.0.operating.programs.eco.temperature" =>
|
||
"HK1-Solltemperatur_eco",
|
||
"heating.circuits.0.operating.programs.external.active" =>
|
||
"HK1-External_aktiv",
|
||
"heating.circuits.0.operating.programs.external.temperature" =>
|
||
"HK1-External_Temperatur",
|
||
"heating.circuits.0.operating.programs.fixed.active" => "HK1-Fixed_aktiv",
|
||
"heating.circuits.0.operating.programs.forcedLastFromSchedule.active" =>
|
||
"HK1-forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.active" =>
|
||
"HK1-HolidayAtHome_aktiv",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.end" =>
|
||
"HK1-HolidayAtHome_Ende",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.start" =>
|
||
"HK1-HolidayAtHome_Start",
|
||
"heating.circuits.0.operating.programs.holiday.active" =>
|
||
"HK1-Urlaub_aktiv",
|
||
"heating.circuits.0.operating.programs.holiday.start" => "HK1-Urlaub_Start",
|
||
"heating.circuits.0.operating.programs.holiday.end" => "HK1-Urlaub_Ende",
|
||
"heating.circuits.0.operating.programs.normal.active" =>
|
||
"HK1-Solltemperatur_aktiv",
|
||
"heating.circuits.0.operating.programs.normal.demand" =>
|
||
"HK1-Solltemperatur_Anforderung",
|
||
"heating.circuits.0.operating.programs.normal.temperature" =>
|
||
"HK1-Solltemperatur_normal",
|
||
"heating.circuits.0.operating.programs.reduced.active" =>
|
||
"HK1-Solltemperatur_reduziert_aktiv",
|
||
"heating.circuits.0.operating.programs.reduced.demand" =>
|
||
"HK1-Solltemperatur_reduziert_Anforderung",
|
||
"heating.circuits.0.operating.programs.reduced.temperature" =>
|
||
"HK1-Solltemperatur_reduziert",
|
||
"heating.circuits.0.operating.programs.summerEco.active" =>
|
||
"HK1-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.0.operating.programs.standby.active" =>
|
||
"HK1-Standby_aktiv",
|
||
"heating.circuits.0.zone.mode.active" => "HK1-ZoneMode_aktive",
|
||
"heating.circuits.0.sensors.temperature.room.status" => "HK1-Raum_Status",
|
||
"heating.circuits.0.sensors.temperature.room.value" =>
|
||
"HK1-Raum_Temperatur",
|
||
"heating.circuits.0.sensors.temperature.supply.status" =>
|
||
"HK1-Vorlauftemperatur_aktiv",
|
||
"heating.circuits.0.sensors.temperature.supply.unit" =>
|
||
"HK1-Vorlauftemperatur/Einheit",
|
||
"heating.circuits.0.sensors.temperature.supply.value" =>
|
||
"HK1-Vorlauftemperatur",
|
||
"heating.circuits.0.zone.mode.active" => "HK1-ZoneMode_aktive",
|
||
|
||
"heating.circuits.1.active" => "HK2-aktiv",
|
||
"heating.circuits.1.type" => "HK2-Typ",
|
||
"heating.circuits.1.circulation.pump.status" => "HK2-Zirkulationspumpe",
|
||
"heating.circuits.1.circulation.schedule.active" =>
|
||
"HK2-Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.1.circulation.schedule.entries" =>
|
||
"HK2-Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.1.frostprotection.status" => "HK2-Frostschutz_Status",
|
||
"heating.circuits.1.geofencing.active" => "HK2-Geofencing",
|
||
"heating.circuits.1.geofencing.status" => "HK2-Geofencing_Status",
|
||
"heating.circuits.1.heating.curve.shift" => "HK2-Heizkurve-Niveau",
|
||
"heating.circuits.1.heating.curve.slope" => "HK2-Heizkurve-Steigung",
|
||
"heating.circuits.1.heating.schedule.active" =>
|
||
"HK2-Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.1.heating.schedule.entries" =>
|
||
"HK2-Zeitsteuerung_Heizung",
|
||
"heating.circuits.1.name" => "HK2-Name",
|
||
"heating.circuits.1.operating.modes.active.value" => "HK2-Betriebsart",
|
||
"heating.circuits.1.operating.modes.dhw.active" => "HK2-WW_aktiv",
|
||
"heating.circuits.1.operating.modes.dhwAndHeating.active" =>
|
||
"HK2-WW_und_Heizen_aktiv",
|
||
"heating.circuits.1.operating.modes.dhwAndHeatingCooling.active" =>
|
||
"HK2-WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.1.operating.modes.forcedNormal.active" =>
|
||
"HK2-Solltemperatur_erzwungen",
|
||
"heating.circuits.1.operating.modes.forcedReduced.active" =>
|
||
"HK2-Reduzierte_Temperatur_erzwungen",
|
||
"heating.circuits.1.operating.modes.heating.active" => "HK2-heizen_aktiv",
|
||
"heating.circuits.1.operating.modes.normalStandby.active" =>
|
||
"HK2-Normal_Standby_aktiv",
|
||
"heating.circuits.1.operating.modes.standby.active" => "HK2-Standby_aktiv",
|
||
"heating.circuits.1.operating.programs.active.value" =>
|
||
"HK2-Programmstatus",
|
||
"heating.circuits.1.operating.programs.comfort.active" =>
|
||
"HK2-Solltemperatur_comfort_aktiv",
|
||
"heating.circuits.1.operating.programs.comfort.demand" =>
|
||
"HK2-Solltemperatur_comfort_Anforderung",
|
||
"heating.circuits.1.operating.programs.comfort.temperature" =>
|
||
"HK2-Solltemperatur_comfort",
|
||
"heating.circuits.1.operating.programs.eco.active" =>
|
||
"HK2-Solltemperatur_eco_aktiv",
|
||
"heating.circuits.1.operating.programs.eco.temperature" =>
|
||
"HK2-Solltemperatur_eco",
|
||
"heating.circuits.1.operating.programs.external.active" =>
|
||
"HK2-External_aktiv",
|
||
"heating.circuits.1.operating.programs.external.temperature" =>
|
||
"HK2-External_Temperatur",
|
||
"heating.circuits.1.operating.programs.fixed.active" => "HK2-Fixed_aktiv",
|
||
"heating.circuits.1.operating.programs.forcedLastFromSchedule.active" =>
|
||
"HK2-forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.active" =>
|
||
"HK2-HolidayAtHome_aktiv",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.end" =>
|
||
"HK2-HolidayAtHome_Ende",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.start" =>
|
||
"HK2-HolidayAtHome_Start",
|
||
"heating.circuits.1.operating.programs.holiday.active" =>
|
||
"HK2-Urlaub_aktiv",
|
||
"heating.circuits.1.operating.programs.holiday.start" => "HK2-Urlaub_Start",
|
||
"heating.circuits.1.operating.programs.holiday.end" => "HK2-Urlaub_Ende",
|
||
"heating.circuits.1.operating.programs.normal.active" =>
|
||
"HK2-Solltemperatur_aktiv",
|
||
"heating.circuits.1.operating.programs.normal.demand" =>
|
||
"HK2-Solltemperatur_Anforderung",
|
||
"heating.circuits.1.operating.programs.normal.temperature" =>
|
||
"HK2-Solltemperatur_normal",
|
||
"heating.circuits.1.operating.programs.reduced.active" =>
|
||
"HK2-Solltemperatur_reduziert_aktiv",
|
||
"heating.circuits.1.operating.programs.reduced.demand" =>
|
||
"HK2-Solltemperatur_reduziert_Anforderung",
|
||
"heating.circuits.1.operating.programs.reduced.temperature" =>
|
||
"HK2-Solltemperatur_reduziert",
|
||
"heating.circuits.1.operating.programs.summerEco.active" =>
|
||
"HK2-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.1.operating.programs.standby.active" =>
|
||
"HK2-Standby_aktiv",
|
||
"heating.circuits.1.sensors.temperature.room.status" => "HK2-Raum_Status",
|
||
"heating.circuits.1.sensors.temperature.room.value" =>
|
||
"HK2-Raum_Temperatur",
|
||
"heating.circuits.1.sensors.temperature.supply.status" =>
|
||
"HK2-Vorlauftemperatur_aktiv",
|
||
"heating.circuits.1.sensors.temperature.supply.unit" =>
|
||
"HK2-Vorlauftemperatur/Einheit",
|
||
"heating.circuits.1.sensors.temperature.supply.value" =>
|
||
"HK2-Vorlauftemperatur",
|
||
"heating.circuits.1.zone.mode.active" => "HK2-ZoneMode_aktive",
|
||
|
||
"heating.circuits.2.active" => "HK3-aktiv",
|
||
"heating.circuits.2.type" => "HK3-Typ",
|
||
"heating.circuits.2.circulation.pump.status" => "HK3-Zirkulationspumpe",
|
||
"heating.circuits.2.circulation.schedule.active" =>
|
||
"HK3-Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.2.circulation.schedule.entries" =>
|
||
"HK3-Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.2.frostprotection.status" => "HK3-Frostschutz_Status",
|
||
"heating.circuits.2.geofencing.active" => "HK3-Geofencing",
|
||
"heating.circuits.2.geofencing.status" => "HK3-Geofencing_Status",
|
||
"heating.circuits.2.heating.curve.shift" => "HK3-Heizkurve-Niveau",
|
||
"heating.circuits.2.heating.curve.slope" => "HK3-Heizkurve-Steigung",
|
||
"heating.circuits.2.heating.schedule.active" =>
|
||
"HK3-Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.2.heating.schedule.entries" =>
|
||
"HK3-Zeitsteuerung_Heizung",
|
||
"heating.circuits.2.name" => "HK3-Name",
|
||
"heating.circuits.2.operating.modes.active.value" => "HK3-Betriebsart",
|
||
"heating.circuits.2.operating.modes.dhw.active" => "HK3-WW_aktiv",
|
||
"heating.circuits.2.operating.modes.dhwAndHeating.active" =>
|
||
"HK3-WW_und_Heizen_aktiv",
|
||
"heating.circuits.2.operating.modes.dhwAndHeatingCooling.active" =>
|
||
"HK3-WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.2.operating.modes.forcedNormal.active" =>
|
||
"HK3-Solltemperatur_erzwungen",
|
||
"heating.circuits.2.operating.modes.forcedReduced.active" =>
|
||
"HK3-Reduzierte_Temperatur_erzwungen",
|
||
"heating.circuits.2.operating.modes.heating.active" => "HK3-heizen_aktiv",
|
||
"heating.circuits.2.operating.modes.normalStandby.active" =>
|
||
"HK3-Normal_Standby_aktiv",
|
||
"heating.circuits.2.operating.modes.standby.active" => "HK3-Standby_aktiv",
|
||
"heating.circuits.2.operating.programs.active.value" =>
|
||
"HK3-Programmstatus",
|
||
"heating.circuits.2.operating.programs.comfort.active" =>
|
||
"HK3-Solltemperatur_comfort_aktiv",
|
||
"heating.circuits.2.operating.programs.comfort.demand" =>
|
||
"HK3-Solltemperatur_comfort_Anforderung",
|
||
"heating.circuits.2.operating.programs.comfort.temperature" =>
|
||
"HK3-Solltemperatur_comfort",
|
||
"heating.circuits.2.operating.programs.eco.active" =>
|
||
"HK3-Solltemperatur_eco_aktiv",
|
||
"heating.circuits.2.operating.programs.eco.temperature" =>
|
||
"HK3-Solltemperatur_eco",
|
||
"heating.circuits.2.operating.programs.external.active" =>
|
||
"HK3-External_aktiv",
|
||
"heating.circuits.2.operating.programs.external.temperature" =>
|
||
"HK3-External_Temperatur",
|
||
"heating.circuits.2.operating.programs.fixed.active" => "HK3-Fixed_aktiv",
|
||
"heating.circuits.2.operating.programs.forcedLastFromSchedule.active" =>
|
||
"HK3-forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.active" =>
|
||
"HK3-HolidayAtHome_aktiv",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.end" =>
|
||
"HK3-HolidayAtHome_Ende",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.start" =>
|
||
"HK3-HolidayAtHome_Start",
|
||
"heating.circuits.2.operating.programs.holiday.active" =>
|
||
"HK3-Urlaub_aktiv",
|
||
"heating.circuits.2.operating.programs.holiday.start" => "HK3-Urlaub_Start",
|
||
"heating.circuits.2.operating.programs.holiday.end" => "HK3-Urlaub_Ende",
|
||
"heating.circuits.2.operating.programs.normal.active" =>
|
||
"HK3-Solltemperatur_aktiv",
|
||
"heating.circuits.2.operating.programs.normal.demand" =>
|
||
"HK3-Solltemperatur_Anforderung",
|
||
"heating.circuits.2.operating.programs.normal.temperature" =>
|
||
"HK3-Solltemperatur_normal",
|
||
"heating.circuits.2.operating.programs.reduced.active" =>
|
||
"HK3-Solltemperatur_reduziert_aktiv",
|
||
"heating.circuits.2.operating.programs.reduced.demand" =>
|
||
"HK3-Solltemperatur_reduziert_Anforderung",
|
||
"heating.circuits.2.operating.programs.reduced.temperature" =>
|
||
"HK3-Solltemperatur_reduziert",
|
||
"heating.circuits.2.operating.programs.summerEco.active" =>
|
||
"HK3-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.2.operating.programs.standby.active" =>
|
||
"HK3-Standby_aktiv",
|
||
"heating.circuits.2.sensors.temperature.room.status" => "HK3-Raum_Status",
|
||
"heating.circuits.2.sensors.temperature.room.value" =>
|
||
"HK3-Raum_Temperatur",
|
||
"heating.circuits.2.sensors.temperature.supply.status" =>
|
||
"HK3-Vorlauftemperatur_aktiv",
|
||
"heating.circuits.2.sensors.temperature.supply.unit" =>
|
||
"HK3-Vorlauftemperatur/Einheit",
|
||
"heating.circuits.2.sensors.temperature.supply.value" =>
|
||
"HK3-Vorlauftemperatur",
|
||
"heating.circuits.2.zone.mode.active" => "HK2-ZoneMode_aktive",
|
||
|
||
"heating.circuits.3.geofencing.active" => "HK4-Geofencing",
|
||
"heating.circuits.3.geofencing.status" => "HK4-Geofencing_Status",
|
||
"heating.circuits.3.operating.programs.summerEco.active" =>
|
||
"HK4-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.3.zone.mode.active" => "HK4-ZoneMode_aktive",
|
||
|
||
"heating.compressor.active" => "Kompressor_aktiv",
|
||
"heating.configuration.multiFamilyHouse.active" => "Mehrfamilenhaus_aktiv",
|
||
"heating.configuration.regulation.mode" => "Regulationmode",
|
||
"heating.controller.serial.value" => "Controller_Seriennummer",
|
||
"heating.device.time.offset.value" => "Device_Time_Offset",
|
||
"heating.dhw.active" => "WW-aktiv",
|
||
"heating.dhw.status" => "WW-Status",
|
||
"heating.dhw.charging.active" => "WW-Aufladung",
|
||
|
||
"heating.dhw.charging.level.bottom" => "WW-Speichertemperatur_unten",
|
||
"heating.dhw.charging.level.middle" => "WW-Speichertemperatur_mitte",
|
||
"heating.dhw.charging.level.top" => "WW-Speichertemperatur_oben",
|
||
"heating.dhw.charging.level.value" => "WW-Speicherladung",
|
||
|
||
"heating.dhw.oneTimeCharge.active" => "WW-einmaliges_Aufladen",
|
||
"heating.dhw.pumps.circulation.schedule.active" =>
|
||
"WW-Zirkulationspumpe_Zeitsteuerung_aktiv",
|
||
"heating.dhw.pumps.circulation.schedule.entries" =>
|
||
"WW-Zirkulationspumpe_Zeitplan",
|
||
"heating.dhw.pumps.circulation.status" => "WW-Zirkulationspumpe_Status",
|
||
"heating.dhw.pumps.primary.status" => "WW-Zirkulationspumpe_primaer",
|
||
"heating.dhw.sensors.temperature.outlet.status" =>
|
||
"WW-Sensoren_Auslauf_Status",
|
||
"heating.dhw.sensors.temperature.outlet.unit" =>
|
||
"WW-Sensoren_Auslauf_Wert/Einheit",
|
||
"heating.dhw.sensors.temperature.outlet.value" =>
|
||
"WW-Sensoren_Auslauf_Wert",
|
||
"heating.dhw.temperature.main.value" => "WW-Haupttemperatur",
|
||
"heating.dhw.temperature.hysteresis.value" => "WW-Hysterese",
|
||
"heating.dhw.temperature.temp2.value" => "WW-Temperatur_2",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.status" =>
|
||
"WW-Temperatur_aktiv",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.unit" =>
|
||
"WW-Isttemperatur/Einheit",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.value" =>
|
||
"WW-Isttemperatur",
|
||
"heating.dhw.temperature.value" => "WW-Solltemperatur",
|
||
"heating.dhw.schedule.active" => "WW-zeitgesteuert_aktiv",
|
||
"heating.dhw.schedule.entries" => "WW-Zeitplan",
|
||
|
||
"heating.errors.active.entries" => "Fehlereintraege_aktive",
|
||
"heating.errors.history.entries" => "Fehlereintraege_Historie",
|
||
|
||
"heating.flue.sensors.temperature.main.status" => "Abgassensor_Status",
|
||
"heating.flue.sensors.temperature.main.unit" =>
|
||
"Abgassensor_Temperatur/Einheit",
|
||
"heating.flue.sensors.temperature.main.value" => "Abgassensor_Temperatur",
|
||
|
||
"heating.fuelCell.operating.modes.active.value" => "Brennstoffzelle_Mode",
|
||
"heating.fuelCell.operating.modes.ecological.active" =>
|
||
"Brennstoffzelle_Mode_Ecological",
|
||
"heating.fuelCell.operating.modes.economical.active" =>
|
||
"Brennstoffzelle_Mode_Economical",
|
||
"heating.fuelCell.operating.modes.heatControlled.active" =>
|
||
"Brennstoffzelle_wärmegesteuert",
|
||
"heating.fuelCell.operating.modes.maintenance.active" =>
|
||
"Brennstoffzelle_Wartung",
|
||
"heating.fuelCell.operating.modes.standby.active" =>
|
||
"Brennstoffzelle_Standby",
|
||
"heating.fuelCell.operating.phase.value" => "Brennstoffzelle_Phase",
|
||
"heating.fuelCell.power.production.day" =>
|
||
"Brennstoffzelle_Stromproduktion/Tag",
|
||
"heating.fuelCell.power.production.month" =>
|
||
"Brennstoffzelle_Stromproduktion/Monat",
|
||
"heating.fuelCell.power.production.unit" =>
|
||
"Brennstoffzelle_Stromproduktion/Einheit",
|
||
"heating.fuelCell.power.production.week" =>
|
||
"Brennstoffzelle_Stromproduktion/Woche",
|
||
"heating.fuelCell.power.production.year" =>
|
||
"Brennstoffzelle_Stromproduktion/Jahr",
|
||
"heating.fuelCell.sensors.temperature.return.status" =>
|
||
"Brennstoffzelle_Temperatur_Ruecklauf_Status",
|
||
"heating.fuelCell.sensors.temperature.return.unit" =>
|
||
"Brennstoffzelle_Temperatur_Ruecklauf/Einheit",
|
||
"heating.fuelCell.sensors.temperature.return.value" =>
|
||
"Brennstoffzelle_Temperatur_Ruecklauf",
|
||
"heating.fuelCell.sensors.temperature.supply.status" =>
|
||
"Brennstoffzelle_Temperatur_Vorlauf_Status",
|
||
"heating.fuelCell.sensors.temperature.supply.unit" =>
|
||
"Brennstoffzelle_Temperatur_Vorlauf/Einheit",
|
||
"heating.fuelCell.sensors.temperature.supply.value" =>
|
||
"Brennstoffzelle_Temperatur_Vorlauf",
|
||
"heating.fuelCell.statistics.availabilityRate" =>
|
||
"Brennstoffzelle_Statistic_Verfügbarkeit",
|
||
"heating.fuelCell.statistics.insertions" =>
|
||
"Brennstoffzelle_Statistic_Einschub",
|
||
"heating.fuelCell.statistics.operationHours" =>
|
||
"Brennstoffzelle_Statistic_Bestriebsstunden",
|
||
"heating.fuelCell.statistics.productionHours" =>
|
||
"Brennstoffzelle_Statistic_Produktionsstunden",
|
||
"heating.fuelCell.statistics.productionStarts" =>
|
||
"Brennstoffzelle_Statistic_Produktionsstarts",
|
||
|
||
"heating.gas.consumption.dhw.day" => "Gasverbrauch_WW/Tag",
|
||
"heating.gas.consumption.dhw.week" => "Gasverbrauch_WW/Woche",
|
||
"heating.gas.consumption.dhw.month" => "Gasverbrauch_WW/Monat",
|
||
"heating.gas.consumption.dhw.year" => "Gasverbrauch_WW/Jahr",
|
||
"heating.gas.consumption.dhw.dayValueReadAt" =>
|
||
"Gasverbrauch_WW/Tag_gelesen_am",
|
||
"heating.gas.consumption.dhw.weekValueReadAt" =>
|
||
"Gasverbrauch_WW/Woche_gelesen_am",
|
||
"heating.gas.consumption.dhw.monthValueReadAt" =>
|
||
"Gasverbrauch_WW/Monat_gelesen_am",
|
||
"heating.gas.consumption.dhw.yearValueReadAt" =>
|
||
"Gasverbrauch_WW/Jahr_gelesen_am",
|
||
"heating.gas.consumption.dhw.unit" => "Gasverbrauch_WW/Einheit",
|
||
|
||
"heating.gas.consumption.heating.day" => "Gasverbrauch_Heizung/Tag",
|
||
"heating.gas.consumption.heating.week" => "Gasverbrauch_Heizung/Woche",
|
||
"heating.gas.consumption.heating.month" => "Gasverbrauch_Heizung/Monat",
|
||
"heating.gas.consumption.heating.year" => "Gasverbrauch_Heizung/Jahr",
|
||
"heating.gas.consumption.heating.dayValueReadAt" =>
|
||
"Gasverbrauch_Heizung/Tag_gelesen_am",
|
||
"heating.gas.consumption.heating.weekValueReadAt" =>
|
||
"Gasverbrauch_Heizung/Woche_gelesen_am",
|
||
"heating.gas.consumption.heating.monthValueReadAt" =>
|
||
"Gasverbrauch_Heizung/Monat_gelesen_am",
|
||
"heating.gas.consumption.heating.yearValueReadAt" =>
|
||
"Gasverbrauch_Heizung/Jahr_gelesen_am",
|
||
"heating.gas.consumption.heating.unit" => "Gasverbrauch_Heizung/Einheit",
|
||
"heating.gas.consumption.total.day" => "Gasverbrauch_Total/Tag",
|
||
"heating.gas.consumption.total.month" => "Gasverbrauch_Total/Monat",
|
||
"heating.gas.consumption.total.unit" => "Gasverbrauch_Total/Einheit",
|
||
"heating.gas.consumption.total.week" => "Gasverbrauch_Total/Woche",
|
||
"heating.gas.consumption.total.year" => "Gasverbrauch_Total/Jahr",
|
||
"heating.gas.consumption.total.dayValueReadAt" =>
|
||
"Gasverbrauch_Total/Tag_gelesen_am",
|
||
"heating.gas.consumption.total.monthValueReadAt" =>
|
||
"Gasverbrauch_Total/Woche_gelesen_am",
|
||
"heating.gas.consumption.total.weekValueReadAt" =>
|
||
"Gasverbrauch_Total/Woche_gelesen_am",
|
||
"heating.gas.consumption.total.yearValueReadAt" =>
|
||
"Gasverbrauch_Total/Jahr_gelesen_am",
|
||
|
||
"heating.gas.consumption.fuelCell.day" =>
|
||
"Gasverbrauch_Brennstoffzelle/Tag",
|
||
"heating.gas.consumption.fuelCell.week" =>
|
||
"Gasverbrauch_Brennstoffzelle/Woche",
|
||
"heating.gas.consumption.fuelCell.month" =>
|
||
"Gasverbrauch_Brennstoffzelle/Monat",
|
||
"heating.gas.consumption.fuelCell.year" =>
|
||
"Gasverbrauch_Brennstoffzelle/Jahr",
|
||
"heating.gas.consumption.fuelCell.unit" =>
|
||
"Gasverbrauch_Brennstoffzelle/Einheit",
|
||
|
||
"heating.heat.production.day" => "Wärmeproduktion/Tag",
|
||
"heating.heat.production.month" => "Wärmeproduktion/Woche",
|
||
"heating.heat.production.unit" => "Wärmeproduktion/Einheit",
|
||
"heating.heat.production.week" => "Wärmeproduktion/Woche",
|
||
"heating.heat.production.year" => "Wärmeproduktion/Jahr",
|
||
|
||
"heating.operating.programs.holiday.active" => "Urlaub_aktiv",
|
||
"heating.operating.programs.holiday.end" => "Urlaub_Ende",
|
||
"heating.operating.programs.holiday.start" => "Urlaub_Start",
|
||
|
||
"heating.operating.programs.holidayAtHome.active" => "holidayAtHome_aktiv",
|
||
"heating.operating.programs.holidayAtHome.end" => "holidayAtHome_Ende",
|
||
"heating.operating.programs.holidayAtHome.start" => "holidayAtHome_Start",
|
||
|
||
"heating.power.consumption.day" => "Stromverbrauch/Tag",
|
||
"heating.power.consumption.month" => "Stromverbrauch/Monat",
|
||
"heating.power.consumption.week" => "Stromverbrauch/Woche",
|
||
"heating.power.consumption.year" => "Stromverbrauch/Jahr",
|
||
"heating.power.consumption.unit" => "Stromverbrauch/Einheit",
|
||
|
||
"heating.power.consumption.dhw.day" => "Stromverbrauch_WW/Tag",
|
||
"heating.power.consumption.dhw.month" => "Stromverbrauch_WW/Monat",
|
||
"heating.power.consumption.dhw.week" => "Stromverbrauch_WW/Woche",
|
||
"heating.power.consumption.dhw.year" => "Stromverbrauch_WW/Jahr",
|
||
"heating.power.consumption.dhw.unit" => "Stromverbrauch_WW/Einheit",
|
||
|
||
"heating.power.consumption.heating.day" => "Stromverbrauch_Heizung/Tag",
|
||
"heating.power.consumption.heating.month" => "Stromverbrauch_Heizung/Monat",
|
||
"heating.power.consumption.heating.week" => "Stromverbrauch_Heizung/Woche",
|
||
"heating.power.consumption.heating.year" => "Stromverbrauch_Heizung/Jahr",
|
||
"heating.power.consumption.heating.unit" =>
|
||
"Stromverbrauch_Heizung/Einheit",
|
||
|
||
"heating.power.consumption.total.day" => "Stromverbrauch_Total/Tag",
|
||
"heating.power.consumption.total.month" => "Stromverbrauch_Total/Monat",
|
||
"heating.power.consumption.total.week" => "Stromverbrauch_Total/Woche",
|
||
"heating.power.consumption.total.year" => "Stromverbrauch_Total/Jahr",
|
||
"heating.power.consumption.total.dayValueReadAt" =>
|
||
"Stromverbrauch_Total/Tag_gelesen_am",
|
||
"heating.power.consumption.total.monthValueReadAt" =>
|
||
"Stromverbrauch_Total/Monat_gelesen_am",
|
||
"heating.power.consumption.total.weekValueReadAt" =>
|
||
"Stromverbrauch_Total/Woche_gelesen_am",
|
||
"heating.power.consumption.total.yearValueReadAt" =>
|
||
"Stromverbrauch_Total/Jahr_gelesen_am",
|
||
"heating.power.consumption.total.unit" => "Stromverbrauch_Total/Einheit",
|
||
|
||
"heating.power.production.current.status" =>
|
||
"Stromproduktion_aktueller_Status",
|
||
"heating.power.production.current.value" => "Stromproduktion",
|
||
|
||
"heating.power.production.demandCoverage.current.unit" =>
|
||
"Stromproduktion_Bedarfsabdeckung/Einheit",
|
||
"heating.power.production.demandCoverage.current.value" =>
|
||
"Stromproduktion_Bedarfsabdeckung",
|
||
"heating.power.production.demandCoverage.total.day" =>
|
||
"Stromproduktion_Bedarfsabdeckung_total/Tag",
|
||
"heating.power.production.demandCoverage.total.month" =>
|
||
"Stromproduktion_Bedarfsabdeckung_total/Monat",
|
||
"heating.power.production.demandCoverage.total.unit" =>
|
||
"Stromproduktion_Bedarfsabdeckung_total/Einheit",
|
||
"heating.power.production.demandCoverage.total.week" =>
|
||
"Stromproduktion_Bedarfsabdeckung_total/Woche",
|
||
"heating.power.production.demandCoverage.total.year" =>
|
||
"Stromproduktion_Bedarfsabdeckung_total/Jahr",
|
||
|
||
"heating.power.production.day" => "Stromproduktion_Total/Tag",
|
||
"heating.power.production.month" => "Stromproduktion_Total/Monat",
|
||
"heating.power.production.productionCoverage.current.unit" =>
|
||
"Stromproduktion_Produktionsabdeckung/Einheit",
|
||
"heating.power.production.productionCoverage.current.value" =>
|
||
"Stromproduktion_Produktionsabdeckung",
|
||
"heating.power.production.productionCoverage.total.day" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Tag",
|
||
"heating.power.production.productionCoverage.total.month" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Monat",
|
||
"heating.power.production.productionCoverage.total.unit" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Einheit",
|
||
"heating.power.production.productionCoverage.total.week" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Woche",
|
||
"heating.power.production.productionCoverage.total.year" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Jahr",
|
||
"heating.power.production.unit" => "Stromproduktion_Total/Einheit",
|
||
"heating.power.production.week" => "Stromproduktion_Total/Woche",
|
||
"heating.power.production.year" => "Stromproduktion_Total/Jahr",
|
||
|
||
"heating.power.purchase.current.unit" => "Stromkauf/Einheit",
|
||
"heating.power.purchase.current.value" => "Stromkauf",
|
||
"heating.power.sold.current.unit" => "Stromverkauf/Einheit",
|
||
"heating.power.sold.current.value" => "Stromverkauf",
|
||
"heating.power.sold.day" => "Stromverkauf/Tag",
|
||
"heating.power.sold.month" => "Stromverkauf/Monat",
|
||
"heating.power.sold.unit" => "Stromverkauf/Einheit",
|
||
"heating.power.sold.week" => "Stromverkauf/Woche",
|
||
"heating.power.sold.year" => "Stromverkauf/Jahr",
|
||
|
||
"heating.sensors.pressure.supply.status" => "Drucksensor_Vorlauf_Status",
|
||
"heating.sensors.pressure.supply.unit" => "Drucksensor_Vorlauf/Einheit",
|
||
"heating.sensors.pressure.supply.value" => "Drucksensor_Vorlauf",
|
||
|
||
"heating.sensors.power.output.status" => "Sensor_Stromproduktion_Status",
|
||
"heating.sensors.power.output.value" => "Sensor_Stromproduktion",
|
||
|
||
"heating.sensors.temperature.outside.status" => "Aussen_Status",
|
||
"heating.sensors.temperature.outside.statusWired" => "Aussen_StatusWired",
|
||
"heating.sensors.temperature.outside.statusWireless" =>
|
||
"Aussen_StatusWireless",
|
||
"heating.sensors.temperature.outside.unit" => "Aussentemperatur/Einheit",
|
||
"heating.sensors.temperature.outside.value" => "Aussentemperatur",
|
||
|
||
"heating.service.timeBased.serviceDue" => "Service_faellig",
|
||
"heating.service.timeBased.serviceIntervalMonths" =>
|
||
"Service_Intervall_Monate",
|
||
"heating.service.timeBased.activeMonthSinceLastService" =>
|
||
"Service_Monate_aktiv_seit_letzten_Service",
|
||
"heating.service.timeBased.lastService" => "Service_Letzter",
|
||
"heating.service.burnerBased.serviceDue" =>
|
||
"Service_fällig_brennerbasiert",
|
||
"heating.service.burnerBased.serviceIntervalBurnerHours" =>
|
||
"Service_Intervall_Betriebsstunden",
|
||
"heating.service.burnerBased.activeBurnerHoursSinceLastService" =>
|
||
"Service_Betriebsstunden_seit_letzten",
|
||
"heating.service.burnerBased.lastService" =>
|
||
"Service_Letzter_brennerbasiert",
|
||
|
||
"heating.solar.active" => "Solar_aktiv",
|
||
"heating.solar.pumps.circuit.status" => "Solar_Pumpe_Status",
|
||
"heating.solar.rechargeSuppression.status" =>
|
||
"Solar_Aufladeunterdrueckung_Status",
|
||
"heating.solar.sensors.power.status" => "Solar_Sensor_Power_Status",
|
||
"heating.solar.sensors.power.value" => "Solar_Sensor_Power",
|
||
"heating.solar.sensors.temperature.collector.status" =>
|
||
"Solar_Sensor_Temperatur_Kollektor_Status",
|
||
"heating.solar.sensors.temperature.collector.value" =>
|
||
"Solar_Sensor_Temperatur_Kollektor",
|
||
"heating.solar.sensors.temperature.dhw.status" =>
|
||
"Solar_Sensor_Temperatur_WW_Status",
|
||
"heating.solar.sensors.temperature.dhw.value" =>
|
||
"Solar_Sensor_Temperatur_WW",
|
||
"heating.solar.statistics.hours" => "Solar_Sensor_Statistik_Stunden",
|
||
|
||
"heating.solar.power.cumulativeProduced.value" =>
|
||
"Solarproduktion_Gesamtertrag",
|
||
"heating.solar.power.production.month" => "Solarproduktion/Monat",
|
||
"heating.solar.power.production.day" => "Solarproduktion/Tag",
|
||
"heating.solar.power.production.unit" => "Solarproduktion/Einheit",
|
||
"heating.solar.power.production.week" => "Solarproduktion/Woche",
|
||
"heating.solar.power.production.year" => "Solarproduktion/Jahr"
|
||
};
|
||
|
||
my $RequestListRoger = {
|
||
"device.serial.value" => "Seriennummer",
|
||
"device.messages.errors.raw.entries" => "Fehlermeldungen",
|
||
|
||
"heating.boiler.serial.value" => "Kessel_Seriennummer",
|
||
"heating.boiler.temperature.value" => "Kessel_Solltemp__C",
|
||
"heating.boiler.sensors.temperature.commonSupply.status" => "Kessel_Common_Supply",
|
||
"heating.boiler.sensors.temperature.commonSupply.unit" => "Kessel_Common_Supply_Temp_Einheit",
|
||
"heating.boiler.sensors.temperature.commonSupply.value" => "Kessel_Common_Supply_Temp__C",
|
||
"heating.boiler.sensors.temperature.main.status" => "Kessel_Status",
|
||
"heating.boiler.sensors.temperature.main.value" => "Kessel_Temp__C",
|
||
"heating.boiler.sensors.temperature.main.unit" => "Kessel_Temp_Einheit",
|
||
"heating.boiler.temperature.unit" => "Kesseltemp_Einheit",
|
||
|
||
"heating.device.time.offset.value" => "Device_Time_Offset",
|
||
"heating.sensors.temperature.outside.status" => "Aussen_Status",
|
||
"heating.sensors.temperature.outside.unit" => "Temp_aussen_Einheit",
|
||
"heating.sensors.temperature.outside.value" => "Temp_aussen__C",
|
||
|
||
"heating.burners.0.active" => "Brenner_1_aktiv",
|
||
"heating.burners.0.statistics.starts" => "Brenner_1_Starts",
|
||
"heating.burners.0.statistics.hours" => "Brenner_1_Betriebsstunden__h",
|
||
"heating.burners.0.modulation.value" => "Brenner_1_Modulation__Prz",
|
||
"heating.burners.0.modulation.unit" => "Brenner_1_Modulation_Einheit",
|
||
|
||
|
||
|
||
"heating.burner.active" => "Brenner_aktiv",
|
||
"heating.burner.automatic.status" => "Brenner_Status",
|
||
"heating.burner.automatic.errorCode" => "Brenner_Fehlercode",
|
||
"heating.burner.current.power.value" => "Brenner_Leistung",
|
||
"heating.burner.modulation.value" => "Brenner_Modulation",
|
||
"heating.burner.statistics.hours" => "Brenner_Betriebsstunden__h",
|
||
"heating.burner.statistics.starts" => "Brenner_Starts",
|
||
|
||
"heating.sensors.volumetricFlow.allengra.status" => "Heiz_Volumenstrom_Status",
|
||
"heating.sensors.volumetricFlow.allengra.value" => "Heiz_Volumenstrom__l/h",
|
||
|
||
"heating.circuits.enabled" => "aktive_Heizkreise",
|
||
"heating.circuits.0.name" => "HK1_Name",
|
||
"heating.circuits.0.operating.modes.active.value" => "HK1_Betriebsart",
|
||
"heating.circuits.0.active" => "HK1_aktiv",
|
||
"heating.circuits.0.type" => "HK1_Typ",
|
||
"heating.circuits.0.circulation.pump.status" => "HK1_Zirkulationspumpe",
|
||
"heating.circuits.0.circulation.schedule.active" => "HK1_Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.0.circulation.schedule.entries" => "HK1_Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.0.frostprotection.status" => "HK1_Frostschutz_Status",
|
||
"heating.circuits.0.geofencing.active" => "HK1_Geofencing",
|
||
"heating.circuits.0.geofencing.status" => "HK1_Geofencing_Status",
|
||
"heating.circuits.0.heating.curve.shift" => "HK1_Heizkurve_Niveau",
|
||
"heating.circuits.0.heating.curve.slope" => "HK1_Heizkurve_Steigung",
|
||
"heating.circuits.0.heating.schedule.active" => "HK1_Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.0.heating.schedule.entries" => "HK1_Zeitsteuerung_Heizung",
|
||
|
||
"heating.circuits.0.operating.modes.dhwAndHeatingCooling.active" => "HK1_WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.0.operating.modes.forcedNormal.active" => "HK1_Soll_Temp_erzwungen",
|
||
"heating.circuits.0.operating.modes.forcedReduced.active" => "HK1_Reduzierte_Temp_erzwungen",
|
||
"heating.circuits.0.operating.modes.heating.active" => "HK1_heizen_aktiv",
|
||
"heating.circuits.0.operating.modes.normalStandby.active" => "HK1_Normal_Standby_aktiv",
|
||
"heating.circuits.0.operating.modes.standby.active" => "HK1_Standby_aktiv",
|
||
"heating.circuits.0.operating.programs.active.value" => "HK1_Programmstatus",
|
||
"heating.circuits.0.operating.programs.comfort.active" => "HK1_Soll_Temp_comfort_aktiv",
|
||
"heating.circuits.0.operating.programs.comfort.demand" => "HK1_Soll_Temp_comfort_Anforderung",
|
||
"heating.circuits.0.operating.programs.comfort.temperature" => "HK1_Soll_Temp_comfort__C",
|
||
"heating.circuits.0.operating.programs.eco.active" => "HK1_Soll_Temp_eco_aktiv",
|
||
"heating.circuits.0.operating.programs.eco.temperature" => "HK1_Soll_Temp_eco__C",
|
||
"heating.circuits.0.operating.programs.external.active" => "HK1_External_aktiv",
|
||
"heating.circuits.0.operating.programs.external.temperature" => "HK1_External_Temp",
|
||
"heating.circuits.0.operating.programs.fixed.active" => "HK1_Fixed_aktiv",
|
||
"heating.circuits.0.operating.programs.forcedLastFromSchedule.active" => "HK1_forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.active" => "HK1_HolidayAtHome_aktiv",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.end" => "HK1_HolidayAtHome_Ende",
|
||
"heating.circuits.0.operating.programs.holidayAtHome.start" => "HK1_HolidayAtHome_Start",
|
||
"heating.circuits.0.operating.programs.holiday.active" => "HK1_Urlaub_aktiv",
|
||
"heating.circuits.0.operating.programs.holiday.start" => "HK1_Urlaub_Start_Zeit",
|
||
"heating.circuits.0.operating.programs.holiday.end" => "HK1_Urlaub_Ende_Zeit",
|
||
"heating.circuits.0.operating.programs.normal.active" => "HK1_Soll_Temp_aktiv",
|
||
"heating.circuits.0.operating.programs.normal.demand" => "HK1_Soll_Temp_Anforderung",
|
||
"heating.circuits.0.operating.programs.normal.temperature" => "HK1_Soll_Temp_normal",
|
||
"heating.circuits.0.operating.programs.reduced.active" => "HK1_Soll_Temp_reduziert_aktiv",
|
||
"heating.circuits.0.operating.programs.reduced.demand" => "HK1_Soll_Temp_reduziert_Anforderung",
|
||
"heating.circuits.0.operating.programs.reduced.temperature" => "HK1_Soll_Temp_reduziert",
|
||
"heating.circuits.0.operating.programs.summerEco.active" => "HK1_Soll_Temp_SummerEco_aktiv",
|
||
"heating.circuits.0.operating.programs.standby.active" => "HK1_Standby_aktiv",
|
||
"heating.circuits.0.zone.mode.active" => "HK1_ZoneMode_aktive",
|
||
"heating.circuits.0.sensors.temperature.room.status" => "HK1_Raum_Status",
|
||
"heating.circuits.0.sensors.temperature.room.value" => "HK1_Raum_Temp",
|
||
"heating.circuits.0.sensors.temperature.supply.status" => "HK1_Vorlauf_Temp_Status",
|
||
"heating.circuits.0.sensors.temperature.supply.unit" => "HK1_Vorlauf_Temp_Einheit",
|
||
"heating.circuits.0.sensors.temperature.supply.value" => "HK1_Vorlauf_Temp__C",
|
||
"heating.circuits.0.zone.mode.active" => "HK1_ZoneMode_aktive",
|
||
|
||
"heating.dhw.operating.modes.active.value" => "WW_Betriebsart",
|
||
"heating.dhw.operating.modes.balanced.active" => "WW_Betriebsart_balanced",
|
||
"heating.dhw.operating.modes.off.active" => "WW_Betriebsart_off",
|
||
"heating.dhw.temperature.main.value" => "WW_Temp_Soll__C",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.value" => "WW_Temp_Ist__C",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.unit" => "WW_Temp_Ist_Einheit",
|
||
"heating.dhw.oneTimeCharge.active" => "WW_einmaliges_Aufladen",
|
||
"heating.dhw.sensors.temperature.dhwCylinder.value" => "WW_Temp__C",
|
||
"heating.dhw.sensors.temperature.dhwCylinder.status" => "WW_Temp_Status",
|
||
"heating.dhw.hygiene.active" => "WW_Hygiene_laeft",
|
||
"heating.dhw.hygiene.enabled" => "WW_Hygiene_enabled",
|
||
"heating.dhw.hygiene.trigger.startHour" => "WW_Hygiene_Start__hh",
|
||
"heating.dhw.hygiene.trigger.startMinute" => "WW_Hygiene_Start__mm",
|
||
"heating.dhw.hygiene.trigger.weekdays" => "WW_Hygiene_Start__dd",
|
||
"heating.dhw.temperature.hygiene.value" => "WW_Hygiene_Temp__C",
|
||
|
||
"heating.dhw.pumps.circulation.schedule.active" => "WW_Zirkulationspumpe_Zeitsteuerung_aktiv",
|
||
"heating.dhw.pumps.circulation.schedule.entries" => "WW_Zirkulationspumpe_Zeitplan",
|
||
"heating.dhw.pumps.circulation.status" => "WW_Zirkulationspumpe_Status",
|
||
"heating.dhw.pumps.primary.status" => "WW_Zirkulationspumpe_primaer",
|
||
"heating.dhw.sensors.temperature.outlet.status" => "WW_Sensoren_Auslauf_Status",
|
||
"heating.dhw.sensors.temperature.outlet.unit" => "WW_Sensoren_Auslauf_Wert_Einheit",
|
||
"heating.dhw.sensors.temperature.outlet.value" => "WW_Sensoren_Auslauf_Wert",
|
||
"heating.dhw.temperature.hysteresis.value" => "WW_Hysterese",
|
||
"heating.dhw.sensors.temperature.hotWaterStorage.status" => "WW_Temp_aktiv",
|
||
# "heating.dhw.temperature.value" => "WW_Solltemp__C",
|
||
"heating.dhw.schedule.active" => "WW_zeitgesteuert_aktiv",
|
||
"heating.dhw.schedule.entries" => "WW_Zeitplan",
|
||
"heating.dhw.temperature.temp2.value" => "WW_Temp2__C",
|
||
|
||
"heating.gas.consumption.summary.dhw.currentDay" => "Gas_WW_Day__m3",
|
||
"heating.gas.consumption.summary.dhw.lastSevenDays" => "Gas_WW_7dLast__m3",
|
||
"heating.gas.consumption.summary.dhw.currentMonth" => "Gas_WW_Month__m3",
|
||
"heating.gas.consumption.summary.dhw.lastMonth" => "Gas_WW_MonthLast__m3",
|
||
"heating.gas.consumption.summary.dhw.currentYear" => "Gas_WW_Year__m3",
|
||
"heating.gas.consumption.summary.dhw.lastYear" => "Gas_WW_YearLast__m3",
|
||
|
||
"heating.gas.consumption.summary.heating.currentDay" => "Gas_Day__m3",
|
||
"heating.gas.consumption.summary.heating.lastSevenDays" => "Gas_7dLast__m3",
|
||
"heating.gas.consumption.summary.heating.currentMonth" => "Gas_Month__m3",
|
||
"heating.gas.consumption.summary.heating.lastMonth" => "Gas_MonthLast__m3",
|
||
"heating.gas.consumption.summary.heating.currentYear" => "Gas_Year__m3",
|
||
"heating.gas.consumption.summary.heating.lastYear" => "Gas_YearLast__m3",
|
||
|
||
"heating.gas.consumption.dhw.day" => "Gas_WW_Tage__m3",
|
||
"heating.gas.consumption.dhw.dayValueReadAt" => "Gas_WW_Tage_Zeit",
|
||
"heating.gas.consumption.dhw.week" => "Gas_WW_Wochen__m3",
|
||
"heating.gas.consumption.dhw.weekValueReadAt" => "Gas_WW_Wochen_Zeit",
|
||
"heating.gas.consumption.dhw.month" => "Gas_WW_Monate__m3",
|
||
"heating.gas.consumption.dhw.monthValueReadAt" => "Gas_WW_Monate_Zeit",
|
||
"heating.gas.consumption.dhw.year" => "Gas_WW_Jahre__m3",
|
||
"heating.gas.consumption.dhw.yearValueReadAt" => "Gas_WW_Jahre_Zeit",
|
||
"heating.gas.consumption.dhw.unit" => "Gas_WW_Einheit",
|
||
|
||
"heating.gas.consumption.heating.day" => "Gas_Heiz_Tage__m3",
|
||
"heating.gas.consumption.heating.dayValueReadAt" => "Gas_Heiz_Tage_Zeit",
|
||
"heating.gas.consumption.heating.week" => "Gas_Heiz_Wochen__m3",
|
||
"heating.gas.consumption.heating.weekValueReadAt" => "Gas_Heiz_Wochen_Zeit",
|
||
"heating.gas.consumption.heating.month" => "Gas_Heiz_Monate__m3",
|
||
"heating.gas.consumption.heating.monthValueReadAt" => "Gas_Heiz_Monate_Zeit",
|
||
"heating.gas.consumption.heating.year" => "Gas_Heiz_Jahre__m3",
|
||
"heating.gas.consumption.heating.yearValueReadAt" => "Gas_Heiz_Jahre_Zeit",
|
||
"heating.gas.consumption.heating.unit" => "Gas_Heiz_Einheit",
|
||
|
||
"heating.gas.consumption.total.day" => "Gas_Total_Tage__m3",
|
||
"heating.gas.consumption.total.dayValueReadAt" => "Gas_Total_Tage_Zeit",
|
||
"heating.gas.consumption.total.week" => "Gas_Total_Wochen__m3",
|
||
"heating.gas.consumption.total.weekValueReadAt" => "Gas_Total_Wochen_Zeit",
|
||
"heating.gas.consumption.total.month" => "Gas_Total_Monate__m3",
|
||
"heating.gas.consumption.total.monthValueReadAt" => "Gas_Total_Monate_Zeit",
|
||
"heating.gas.consumption.total.year" => "Gas_Total_Jahre__m3",
|
||
"heating.gas.consumption.total.yearValueReadAt" => "Gas_Total_Jahre_Zeit",
|
||
"heating.gas.consumption.total.unit" => "Gas_Total_Einheit",
|
||
|
||
"heating.power.consumption.summary.dhw.currentDay" => "Strom_WW_Day__kWh",
|
||
"heating.power.consumption.summary.dhw.lastSevenDays" => "Strom_WW_7dLast__kWh",
|
||
"heating.power.consumption.summary.dhw.currentMonth" => "Strom_WW_Month__kWh",
|
||
"heating.power.consumption.summary.dhw.lastMonth" => "Strom_WW_MonthLast__kWh",
|
||
"heating.power.consumption.summary.dhw.currentYear" => "Strom_WW_Year__kWh",
|
||
"heating.power.consumption.summary.dhw.lastYear" => "Strom_WW_YearLast__kWh",
|
||
|
||
"heating.power.consumption.summary.heating.currentDay" => "Strom_Heiz_Day__kWh",
|
||
"heating.power.consumption.summary.heating.lastSevenDays" => "Strom_Heiz_7dLast__kWh",
|
||
"heating.power.consumption.summary.heating.currentMonth" => "Strom_Heiz_Month__kWh",
|
||
"heating.power.consumption.summary.heating.lastMonth" => "Strom_Heiz_MonthLast__kWh",
|
||
"heating.power.consumption.summary.heating.currentYear" => "Strom_Heiz_Year__kWh",
|
||
"heating.power.consumption.summary.heating.lastYear" => "Strom_Heiz_YearLast__kWh",
|
||
|
||
"heating.circuits.3.heating.curve.shift" => "HK4_Heizkurve_Niveau",
|
||
"heating.circuits.3.heating.curve.slope" => "HK4_Heizkurve_Steigung",
|
||
"heating.circuits.3.geofencing.active" => "HK4_Geofencing",
|
||
"heating.circuits.3.geofencing.status" => "HK4_Geofencing_Status",
|
||
"heating.circuits.3.operating.programs.summerEco.active" => "HK4_Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.3.zone.mode.active" => "HK4_ZoneMode_aktive",
|
||
|
||
|
||
"heating.circuits.1.active" => "HK2_aktiv",
|
||
"heating.circuits.1.type" => "HK2_Typ",
|
||
"heating.circuits.1.circulation.pump.status" => "HK2_Zirkulationspumpe",
|
||
"heating.circuits.1.circulation.schedule.active" => "HK2_Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.1.circulation.schedule.entries" => "HK2_Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.1.frostprotection.status" => "HK2_Frostschutz_Status",
|
||
"heating.circuits.1.geofencing.active" => "HK2_Geofencing",
|
||
"heating.circuits.1.geofencing.status" => "HK2_Geofencing_Status",
|
||
"heating.circuits.1.heating.curve.shift" => "HK2_Heizkurve_Niveau",
|
||
"heating.circuits.1.heating.curve.slope" => "HK2_Heizkurve_Steigung",
|
||
"heating.circuits.1.heating.schedule.active" => "HK2_Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.1.heating.schedule.entries" => "HK2_Zeitsteuerung_Heizung",
|
||
"heating.circuits.1.name" => "HK2_Name",
|
||
"heating.circuits.1.operating.modes.active.value" => "HK2_Betriebsart",
|
||
"heating.circuits.1.operating.modes.dhw.active" => "HK2_WW_aktiv",
|
||
"heating.circuits.1.operating.modes.dhwAndHeating.active" => "HK2_WW_und_Heizen_aktiv",
|
||
"heating.circuits.1.operating.modes.dhwAndHeatingCooling.active" => "HK2_WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.1.operating.modes.forcedNormal.active" => "HK2_Solltemperatur_erzwungen",
|
||
"heating.circuits.1.operating.modes.forcedReduced.active" => "HK2_Reduzierte_Temperatur_erzwungen",
|
||
"heating.circuits.1.operating.modes.heating.active" => "HK2_heizen_aktiv",
|
||
"heating.circuits.1.operating.modes.normalStandby.active" => "HK2_Normal_Standby_aktiv",
|
||
"heating.circuits.1.operating.modes.standby.active" => "HK2_Standby_aktiv",
|
||
"heating.circuits.1.operating.programs.active.value" => "HK2_Programmstatus",
|
||
"heating.circuits.1.operating.programs.comfort.active" => "HK2_Solltemperatur_comfort_aktiv",
|
||
"heating.circuits.1.operating.programs.comfort.demand" =>
|
||
"HK2-Solltemperatur_comfort_Anforderung",
|
||
"heating.circuits.1.operating.programs.comfort.temperature" =>
|
||
"HK2-Solltemperatur_comfort",
|
||
"heating.circuits.1.operating.programs.eco.active" =>
|
||
"HK2-Solltemperatur_eco_aktiv",
|
||
"heating.circuits.1.operating.programs.eco.temperature" =>
|
||
"HK2-Solltemperatur_eco",
|
||
"heating.circuits.1.operating.programs.external.active" =>
|
||
"HK2-External_aktiv",
|
||
"heating.circuits.1.operating.programs.external.temperature" =>
|
||
"HK2-External_Temperatur",
|
||
"heating.circuits.1.operating.programs.fixed.active" => "HK2-Fixed_aktiv",
|
||
"heating.circuits.1.operating.programs.forcedLastFromSchedule.active" =>
|
||
"HK2-forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.active" =>
|
||
"HK2-HolidayAtHome_aktiv",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.end" => "HK2-HolidayAtHome_Ende",
|
||
"heating.circuits.1.operating.programs.holidayAtHome.start" => "HK2-HolidayAtHome_Start",
|
||
"heating.circuits.1.operating.programs.holiday.active" => "HK2_Urlaub_aktiv",
|
||
"heating.circuits.1.operating.programs.holiday.start" => "HK2_Urlaub_Start_Zeit",
|
||
"heating.circuits.1.operating.programs.holiday.end" => "HK2_Urlaub_Ende_Zeit",
|
||
"heating.circuits.1.operating.programs.normal.active" =>
|
||
"HK2-Solltemperatur_aktiv",
|
||
"heating.circuits.1.operating.programs.normal.demand" =>
|
||
"HK2-Solltemperatur_Anforderung",
|
||
"heating.circuits.1.operating.programs.normal.temperature" =>
|
||
"HK2-Solltemperatur_normal",
|
||
"heating.circuits.1.operating.programs.reduced.active" =>
|
||
"HK2-Solltemperatur_reduziert_aktiv",
|
||
"heating.circuits.1.operating.programs.reduced.demand" =>
|
||
"HK2-Solltemperatur_reduziert_Anforderung",
|
||
"heating.circuits.1.operating.programs.reduced.temperature" =>
|
||
"HK2-Solltemperatur_reduziert",
|
||
"heating.circuits.1.operating.programs.summerEco.active" =>
|
||
"HK2-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.1.operating.programs.standby.active" =>
|
||
"HK2-Standby_aktiv",
|
||
"heating.circuits.1.sensors.temperature.room.status" => "HK2-Raum_Status",
|
||
"heating.circuits.1.sensors.temperature.room.value" =>
|
||
"HK2-Raum_Temperatur",
|
||
"heating.circuits.1.sensors.temperature.supply.status" =>
|
||
"HK2-Vorlauftemperatur_aktiv",
|
||
"heating.circuits.1.sensors.temperature.supply.unit" =>
|
||
"HK2-Vorlauftemperatur_Einheit",
|
||
"heating.circuits.1.sensors.temperature.supply.value" =>
|
||
"HK2-Vorlauftemperatur",
|
||
"heating.circuits.1.zone.mode.active" => "HK2-ZoneMode_aktive",
|
||
|
||
"heating.circuits.2.active" => "HK3_aktiv",
|
||
"heating.circuits.2.type" => "HK3_Typ",
|
||
"heating.circuits.2.circulation.pump.status" => "HK3_Zirkulationspumpe",
|
||
"heating.circuits.2.circulation.schedule.active" =>"HK3_Zeitsteuerung_Zirkulation_aktiv",
|
||
"heating.circuits.2.circulation.schedule.entries" =>"HK3_Zeitsteuerung_Zirkulation",
|
||
"heating.circuits.2.frostprotection.status" => "HK3_Frostschutz_Status",
|
||
"heating.circuits.2.geofencing.active" => "HK3_Geofencing",
|
||
"heating.circuits.2.geofencing.status" => "HK3_Geofencing_Status",
|
||
"heating.circuits.2.heating.curve.shift" => "HK3_Heizkurve_Niveau",
|
||
"heating.circuits.2.heating.curve.slope" => "HK3_Heizkurve_Steigung",
|
||
"heating.circuits.2.heating.schedule.active" => "HK3-Zeitsteuerung_Heizung_aktiv",
|
||
"heating.circuits.2.heating.schedule.entries" => "HK3_Zeitsteuerung_Heizung",
|
||
"heating.circuits.2.name" => "HK3_Name",
|
||
"heating.circuits.2.operating.modes.active.value" => "HK3_Betriebsart",
|
||
"heating.circuits.2.operating.modes.dhw.active" => "HK3_WW_aktiv",
|
||
"heating.circuits.2.operating.modes.dhwAndHeating.active" => "HK3_WW_und_Heizen_aktiv",
|
||
"heating.circuits.2.operating.modes.dhwAndHeatingCooling.active" => "HK3-WW_und_Heizen_Kuehlen_aktiv",
|
||
"heating.circuits.2.operating.modes.forcedNormal.active" => "HK3-Solltemperatur_erzwungen",
|
||
"heating.circuits.2.operating.modes.forcedReduced.active" => "HK3-Reduzierte_Temperatur_erzwungen",
|
||
"heating.circuits.2.operating.modes.heating.active" => "HK3-heizen_aktiv",
|
||
"heating.circuits.2.operating.modes.normalStandby.active" => "HK3-Normal_Standby_aktiv",
|
||
"heating.circuits.2.operating.modes.standby.active" => "HK3-Standby_aktiv",
|
||
"heating.circuits.2.operating.programs.active.value" => "HK3-Programmstatus",
|
||
"heating.circuits.2.operating.programs.comfort.active" => "HK3-Solltemperatur_comfort_aktiv",
|
||
"heating.circuits.2.operating.programs.comfort.demand" => "HK3-Solltemperatur_comfort_Anforderung",
|
||
"heating.circuits.2.operating.programs.comfort.temperature" => "HK3-Solltemperatur_comfort",
|
||
"heating.circuits.2.operating.programs.eco.active" => "HK3-Solltemperatur_eco_aktiv",
|
||
"heating.circuits.2.operating.programs.eco.temperature" => "HK3-Solltemperatur_eco",
|
||
"heating.circuits.2.operating.programs.external.active" => "HK3-External_aktiv",
|
||
"heating.circuits.2.operating.programs.external.temperature" => "HK3-External_Temperatur",
|
||
"heating.circuits.2.operating.programs.fixed.active" => "HK3-Fixed_aktiv",
|
||
"heating.circuits.2.operating.programs.forcedLastFromSchedule.active" => "HK3-forcedLastFromSchedule_aktiv",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.active" => "HK3-HolidayAtHome_aktiv",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.end" => "HK3-HolidayAtHome_Ende",
|
||
"heating.circuits.2.operating.programs.holidayAtHome.start" => "HK3-HolidayAtHome_Start",
|
||
"heating.circuits.2.operating.programs.holiday.active" => "HK3_Urlaub_aktiv",
|
||
"heating.circuits.2.operating.programs.holiday.start" => "HK3_Urlaub_Start_Zeit",
|
||
"heating.circuits.2.operating.programs.holiday.end" => "HK3_Urlaub_Ende_Zeit",
|
||
"heating.circuits.2.operating.programs.normal.active" =>
|
||
"HK3-Solltemperatur_aktiv",
|
||
"heating.circuits.2.operating.programs.normal.demand" =>
|
||
"HK3-Solltemperatur_Anforderung",
|
||
"heating.circuits.2.operating.programs.normal.temperature" =>
|
||
"HK3-Solltemperatur_normal",
|
||
"heating.circuits.2.operating.programs.reduced.active" =>
|
||
"HK3-Solltemperatur_reduziert_aktiv",
|
||
"heating.circuits.2.operating.programs.reduced.demand" =>
|
||
"HK3-Solltemperatur_reduziert_Anforderung",
|
||
"heating.circuits.2.operating.programs.reduced.temperature" =>
|
||
"HK3-Solltemperatur_reduziert",
|
||
"heating.circuits.2.operating.programs.summerEco.active" =>
|
||
"HK3-Solltemperatur_SummerEco_aktiv",
|
||
"heating.circuits.2.operating.programs.standby.active" =>
|
||
"HK3-Standby_aktiv",
|
||
"heating.circuits.2.sensors.temperature.room.status" => "HK3-Raum_Status",
|
||
"heating.circuits.2.sensors.temperature.room.value" =>
|
||
"HK3-Raum_Temperatur",
|
||
"heating.circuits.2.sensors.temperature.supply.status" =>
|
||
"HK3-Vorlauftemperatur_aktiv",
|
||
"heating.circuits.2.sensors.temperature.supply.unit" =>
|
||
"HK3-Vorlauftemperatur_Einheit",
|
||
"heating.circuits.2.sensors.temperature.supply.value" => "HK3-Vorlauftemperatur",
|
||
"heating.circuits.2.zone.mode.active" => "HK2-ZoneMode_aktive",
|
||
|
||
"heating.compressor.active" => "Kompressor_aktiv",
|
||
"heating.configuration.multiFamilyHouse.active" => "Mehrfamilenhaus_aktiv",
|
||
"heating.configuration.regulation.mode" => "Regulationmode",
|
||
"heating.controller.serial.value" => "Controller_Seriennummer",
|
||
"heating.dhw.active" => "WW_aktiv",
|
||
"heating.dhw.status" => "WW_Status",
|
||
"heating.dhw.charging.active" => "WW_Aufladung",
|
||
|
||
"heating.dhw.charging.level.bottom" => "WW_Speichertemperatur_unten",
|
||
"heating.dhw.charging.level.middle" => "WW_Speichertemperatur_mitte",
|
||
"heating.dhw.charging.level.top" => "WW_Speichertemperatur_oben",
|
||
"heating.dhw.charging.level.value" => "WW_Speicherladung",
|
||
|
||
"heating.errors.active.entries" => "Fehlereintraege_aktive",
|
||
"heating.errors.history.entries" => "Fehlereintraege_Historie",
|
||
|
||
"heating.flue.sensors.temperature.main.status" => "Abgassensor_Status",
|
||
"heating.flue.sensors.temperature.main.unit" => "Abgassensor_Temperatur_Einheit",
|
||
"heating.flue.sensors.temperature.main.value" => "Abgassensor_Temperatur",
|
||
|
||
"heating.fuelCell.operating.modes.active.value" => "Brennstoffzelle_Mode",
|
||
"heating.fuelCell.operating.modes.ecological.active" => "Brennstoffzelle_Mode_Ecological",
|
||
"heating.fuelCell.operating.modes.economical.active" => "Brennstoffzelle_Mode_Economical",
|
||
"heating.fuelCell.operating.modes.heatControlled.active" => "Brennstoffzelle_wärmegesteuert",
|
||
"heating.fuelCell.operating.modes.maintenance.active" => "Brennstoffzelle_Wartung",
|
||
"heating.fuelCell.operating.modes.standby.active" => "Brennstoffzelle_Standby",
|
||
"heating.fuelCell.operating.phase.value" => "Brennstoffzelle_Phase",
|
||
"heating.fuelCell.power.production.day" => "Brennstoffzelle_Stromproduktion/Tag",
|
||
"heating.fuelCell.power.production.month" => "Brennstoffzelle_Stromproduktion/Monat",
|
||
"heating.fuelCell.power.production.unit" => "Brennstoffzelle_Stromproduktion_Einheit",
|
||
"heating.fuelCell.power.production.week" => "Brennstoffzelle_Stromproduktion/Woche",
|
||
"heating.fuelCell.power.production.year" => "Brennstoffzelle_Stromproduktion/Jahr",
|
||
"heating.fuelCell.sensors.temperature.return.status" => "Brennstoffzelle_Temperatur_Ruecklauf_Status",
|
||
"heating.fuelCell.sensors.temperature.return.unit" => "Brennstoffzelle_Temperatur_Ruecklauf_Einheit",
|
||
"heating.fuelCell.sensors.temperature.return.value" => "Brennstoffzelle_Temperatur_Ruecklauf",
|
||
"heating.fuelCell.sensors.temperature.supply.status" => "Brennstoffzelle_Temperatur_Vorlauf_Status",
|
||
"heating.fuelCell.sensors.temperature.supply.unit" => "Brennstoffzelle_Temperatur_Vorlauf_Einheit",
|
||
"heating.fuelCell.sensors.temperature.supply.value" => "Brennstoffzelle_Temperatur_Vorlauf",
|
||
"heating.fuelCell.statistics.availabilityRate" => "Brennstoffzelle_Statistic_Verfügbarkeit",
|
||
"heating.fuelCell.statistics.insertions" => "Brennstoffzelle_Statistic_Einschub",
|
||
"heating.fuelCell.statistics.operationHours" => "Brennstoffzelle_Statistic_Bestriebsstunden",
|
||
"heating.fuelCell.statistics.productionHours" => "Brennstoffzelle_Statistic_Produktionsstunden",
|
||
"heating.fuelCell.statistics.productionStarts" => "Brennstoffzelle_Statistic_Produktionsstarts",
|
||
|
||
"heating.gas.consumption.fuelCell.day" => "Gas_Brennstoffzelle/Tag",
|
||
"heating.gas.consumption.fuelCell.week" => "Gas_Brennstoffzelle/Woche",
|
||
"heating.gas.consumption.fuelCell.month" => "Gas_Brennstoffzelle/Monat",
|
||
"heating.gas.consumption.fuelCell.year" => "Gas_Brennstoffzelle/Jahr",
|
||
"heating.gas.consumption.fuelCell.unit" => "Gas_Brennstoffzelle/Einheit",
|
||
|
||
"heating.heat.production.day" => "Wärmeproduktion/Tag",
|
||
"heating.heat.production.month" => "Wärmeproduktion/Woche",
|
||
"heating.heat.production.unit" => "Wärmeproduktion/Einheit",
|
||
"heating.heat.production.week" => "Wärmeproduktion/Woche",
|
||
"heating.heat.production.year" => "Wärmeproduktion/Jahr",
|
||
|
||
"heating.operating.programs.holiday.active" => "Urlaub_aktiv",
|
||
"heating.operating.programs.holiday.end" => "Urlaub_Ende_Zeit",
|
||
"heating.operating.programs.holiday.start" => "Urlaub_Start_Zeit",
|
||
|
||
"heating.operating.programs.holidayAtHome.active" => "HolidayAtHome_aktiv",
|
||
"heating.operating.programs.holidayAtHome.end" => "HolidayAtHome_Ende",
|
||
"heating.operating.programs.holidayAtHome.start" => "HolidayAtHome_Start",
|
||
|
||
"heating.power.consumption.day" => "Stromverbrauch_Tag",
|
||
"heating.power.consumption.month" => "Stromverbrauch_Monat",
|
||
"heating.power.consumption.week" => "Stromverbrauch_Woche",
|
||
"heating.power.consumption.year" => "Stromverbrauch_Jahr",
|
||
"heating.power.consumption.unit" => "Stromverbrauch_Einheit",
|
||
|
||
"heating.power.consumption.dhw.day" => "Strom_WW_Tage",
|
||
"heating.power.consumption.dhw.dayValueReadAt" => "Strom_WW_Tage_Zeit",
|
||
"heating.power.consumption.dhw.week" => "Strom_WW_Wochen",
|
||
"heating.power.consumption.dhw.weekValueReadAt" => "Strom_WW_Wochen_Zeit",
|
||
"heating.power.consumption.dhw.month" => "Strom_WW_Monate",
|
||
"heating.power.consumption.dhw.monthValueReadAt" => "Strom_WW_Monate_Zeit",
|
||
"heating.power.consumption.dhw.year" => "Strom_WW_Jahre",
|
||
"heating.power.consumption.dhw.yearValueReadAt" => "Strom_WW_Jahre_Zeit",
|
||
"heating.power.consumption.dhw.unit" => "Strom_WW_Einheit",
|
||
|
||
"heating.power.consumption.heating.day" => "Strom_Heizung_Tage__kWh",
|
||
"heating.power.consumption.heating.dayValueReadAt" => "Strom_Heizung_Tage_Zeit",
|
||
"heating.power.consumption.heating.week" => "Strom_Heizung_Wochen__kWh",
|
||
"heating.power.consumption.heating.weekValueReadAt" => "Strom_Heizung_Wochen_Zeit",
|
||
"heating.power.consumption.heating.month" => "Strom_Heizung_Monate__kWh",
|
||
"heating.power.consumption.heating.monthValueReadAt"=> "Strom_Heizung_Monate_Zeit",
|
||
"heating.power.consumption.heating.year" => "Strom_Heizung_Jahre__kWh",
|
||
"heating.power.consumption.heating.yearValueReadAt" => "Strom_Heizung_Jahre_Zeit",
|
||
"heating.power.consumption.heating.unit" => "Strom_Heizung_Einheit",
|
||
|
||
"heating.power.consumption.total.day" => "Strom_Total_Tage__kWh",
|
||
"heating.power.consumption.total.dayValueReadAt" => "Strom_Total_Tage_Zeit",
|
||
"heating.power.consumption.total.week" => "Strom_Total_Wochen__kWh",
|
||
"heating.power.consumption.total.weekValueReadAt" => "Strom_Total_Wochen_Zeit",
|
||
"heating.power.consumption.total.month" => "Strom_Total_Monate__kWh",
|
||
"heating.power.consumption.total.monthValueReadAt" => "Strom_Total_Monate_Zeit",
|
||
"heating.power.consumption.total.year" => "Strom_Total_Jahre__kWh",
|
||
"heating.power.consumption.total.yearValueReadAt" => "Strom_Total_Jahre_Zeit",
|
||
"heating.power.consumption.total.unit" => "Strom_Total_Einheit",
|
||
|
||
"heating.power.production.current.status" => "Stromproduktion_aktueller_Status",
|
||
"heating.power.production.current.value" => "Stromproduktion",
|
||
|
||
"heating.power.production.demandCoverage.current.unit" => "Stromproduktion_Bedarfsabdeckung/Einheit",
|
||
"heating.power.production.demandCoverage.current.value" => "Stromproduktion_Bedarfsabdeckung",
|
||
"heating.power.production.demandCoverage.total.day" => "Stromproduktion_Bedarfsabdeckung_total/Tag",
|
||
"heating.power.production.demandCoverage.total.month" => "Stromproduktion_Bedarfsabdeckung_total/Monat",
|
||
"heating.power.production.demandCoverage.total.unit" => "Stromproduktion_Bedarfsabdeckung_total/Einheit",
|
||
"heating.power.production.demandCoverage.total.week" => "Stromproduktion_Bedarfsabdeckung_total/Woche",
|
||
"heating.power.production.demandCoverage.total.year" => "Stromproduktion_Bedarfsabdeckung_total/Jahr",
|
||
|
||
"heating.power.production.day" => "Stromproduktion_Total/Tag",
|
||
"heating.power.production.month" => "Stromproduktion_Total/Monat",
|
||
"heating.power.production.productionCoverage.current.unit" =>
|
||
"Stromproduktion_Produktionsabdeckung/Einheit",
|
||
"heating.power.production.productionCoverage.current.value" =>
|
||
"Stromproduktion_Produktionsabdeckung",
|
||
"heating.power.production.productionCoverage.total.day" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Tag",
|
||
"heating.power.production.productionCoverage.total.month" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Monat",
|
||
"heating.power.production.productionCoverage.total.unit" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Einheit",
|
||
"heating.power.production.productionCoverage.total.week" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Woche",
|
||
"heating.power.production.productionCoverage.total.year" =>
|
||
"Stromproduktion_Produktionsabdeckung_Total/Jahr",
|
||
"heating.power.production.unit" => "Stromproduktion_Total/Einheit",
|
||
"heating.power.production.week" => "Stromproduktion_Total/Woche",
|
||
"heating.power.production.year" => "Stromproduktion_Total/Jahr",
|
||
|
||
"heating.power.purchase.current.unit" => "Stromkauf/Einheit",
|
||
"heating.power.purchase.current.value" => "Stromkauf",
|
||
"heating.power.sold.current.unit" => "Stromverkauf/Einheit",
|
||
"heating.power.sold.current.value" => "Stromverkauf",
|
||
"heating.power.sold.day" => "Stromverkauf/Tag",
|
||
"heating.power.sold.month" => "Stromverkauf/Monat",
|
||
"heating.power.sold.unit" => "Stromverkauf/Einheit",
|
||
"heating.power.sold.week" => "Stromverkauf/Woche",
|
||
"heating.power.sold.year" => "Stromverkauf/Jahr",
|
||
|
||
"heating.sensors.pressure.supply.status" => "Drucksensor_Vorlauf_Status",
|
||
"heating.sensors.pressure.supply.unit" => "Drucksensor_Vorlauf/Einheit",
|
||
"heating.sensors.pressure.supply.value" => "Drucksensor_Vorlauf",
|
||
|
||
"heating.sensors.power.output.status" => "Sensor_Stromproduktion_Status",
|
||
"heating.sensors.power.output.value" => "Sensor_Stromproduktion",
|
||
|
||
"heating.sensors.temperature.outside.statusWired" => "Aussen_StatusWired",
|
||
"heating.sensors.temperature.outside.statusWireless" =>
|
||
"Aussen_StatusWireless",
|
||
|
||
"heating.service.timeBased.serviceDue" => "Service_faellig",
|
||
"heating.service.timeBased.serviceIntervalMonths" =>
|
||
"Service_Intervall_Monate",
|
||
"heating.service.timeBased.activeMonthSinceLastService" =>
|
||
"Service_Monate_aktiv_seit_letzten_Service",
|
||
"heating.service.timeBased.lastService" => "Service_Letzter",
|
||
"heating.service.burnerBased.serviceDue" =>
|
||
"Service_fällig_brennerbasiert",
|
||
"heating.service.burnerBased.serviceIntervalBurnerHours" =>
|
||
"Service_Intervall_Betriebsstunden",
|
||
"heating.service.burnerBased.activeBurnerHoursSinceLastService" =>
|
||
"Service_Betriebsstunden_seit_letzten",
|
||
"heating.service.burnerBased.lastService" =>
|
||
"Service_Letzter_brennerbasiert",
|
||
|
||
"heating.solar.active" => "Solar_aktiv",
|
||
"heating.solar.pumps.circuit.status" => "Solar_Pumpe_Status",
|
||
"heating.solar.rechargeSuppression.status" =>
|
||
"Solar_Aufladeunterdrueckung_Status",
|
||
"heating.solar.sensors.power.status" => "Solar_Sensor_Power_Status",
|
||
"heating.solar.sensors.power.value" => "Solar_Sensor_Power",
|
||
"heating.solar.sensors.temperature.collector.status" =>
|
||
"Solar_Sensor_Temperatur_Kollektor_Status",
|
||
"heating.solar.sensors.temperature.collector.value" =>
|
||
"Solar_Sensor_Temperatur_Kollektor",
|
||
"heating.solar.sensors.temperature.dhw.status" =>
|
||
"Solar_Sensor_Temperatur_WW_Status",
|
||
"heating.solar.sensors.temperature.dhw.value" =>
|
||
"Solar_Sensor_Temperatur_WW",
|
||
"heating.solar.statistics.hours" => "Solar_Sensor_Statistik_Stunden",
|
||
|
||
"heating.solar.power.cumulativeProduced.value" =>
|
||
"Solarproduktion_Gesamtertrag",
|
||
"heating.solar.power.production.month" => "Solarproduktion/Monat",
|
||
"heating.solar.power.production.day" => "Solarproduktion/Tag",
|
||
"heating.solar.power.production.unit" => "Solarproduktion/Einheit",
|
||
"heating.solar.power.production.week" => "Solarproduktion/Woche",
|
||
"heating.solar.power.production.year" => "Solarproduktion/Jahr"
|
||
};
|
||
|
||
|
||
#####################################################################################################################
|
||
# Modul initialisieren und Namen zusätzlicher Funktionen bekannt geben
|
||
#####################################################################################################################
|
||
sub vitoconnect_Initialize {
|
||
my ($hash) = @_;
|
||
$hash->{DefFn} = \&vitoconnect_Define; # wird beim 'define' eines Gerätes aufgerufen
|
||
$hash->{UndefFn} = \&vitoconnect_Undef; # # wird beim Löschen einer Geräteinstanz aufgerufen
|
||
$hash->{DeleteFn} = \&vitoconnect_DeleteKeyValue;
|
||
$hash->{SetFn} = \&vitoconnect_Set; # set-Befehle
|
||
$hash->{GetFn} = \&vitoconnect_Get; # get-Befehle
|
||
$hash->{AttrFn} = \&vitoconnect_Attr; # Attribute setzen/ändern/löschen
|
||
$hash->{ReadFn} = \&vitoconnect_Read;
|
||
$hash->{AttrList} =
|
||
"disable:0,1 "
|
||
. "vitoconnect_mappings:textField-long "
|
||
. "vitoconnect_translations:textField-long "
|
||
. "vitoconnect_mapping_roger:0,1 "
|
||
. "vitoconnect_raw_readings:0,1 " # Liefert nur die raw readings und verhindert das mappen wenn gesetzt
|
||
. "vitoconnect_disable_raw_readings:0,1 " # Wird ein mapping verwendet können die weiteren RAW Readings ausgeblendet werden
|
||
. "vitoconnect_gw_readings:0,1 " # Schreibt die GW readings als Reading ins Device
|
||
. "vitoconnect_actions_active:0,1 "
|
||
. "vitoconnect_device:0,1 " # Hier kann Device 0 oder 1 angesprochen worden, default ist 0 und ich habe keinen GW mit Device 1
|
||
. "vitoconnect_serial:textField-long " # Legt fest welcher Gateway abgefragt werden soll, wenn nicht gesetzt werden alle abgefragt
|
||
. "vitoconnect_installationID:textField-long " # Legt fest welche Installation abgefragt werden soll, muss zur serial passen
|
||
. "vitoconnect_timeout:selectnumbers,10,1.0,30,0,lin "
|
||
. $readingFnAttributes;
|
||
|
||
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; ## no critic 'eval'
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# wird beim 'define' eines Gerätes aufgerufen
|
||
#####################################################################################################################
|
||
sub vitoconnect_Define {
|
||
my ( $hash, $def ) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $type = $hash->{TYPE};
|
||
|
||
my $params = {
|
||
hash => $hash,
|
||
name => $name,
|
||
type => $type,
|
||
notes => \%vNotesIntern,
|
||
useAPI => 0,
|
||
useSMUtils => 1,
|
||
useErrCodes => 0,
|
||
useCTZ => 0,
|
||
};
|
||
|
||
use version 0.77; our $VERSION = moduleVersion ($params); # Versionsinformationen setzen
|
||
delete $params->{hash};
|
||
|
||
|
||
my @param = split( '[ \t]+', $def );
|
||
|
||
if ( int(@param) < 5 ) {
|
||
return "too few parameters: "
|
||
. "define <name> vitoconnect <user> <passwd> <intervall>";
|
||
}
|
||
|
||
$hash->{user} = $param[2];
|
||
$hash->{intervall} = $param[4];
|
||
$hash->{counter} = 0;
|
||
$hash->{timeout} = 15;
|
||
$hash->{".access_token"} = "";
|
||
$hash->{devices} = [];
|
||
$hash->{"Redirect_URI"} = $callback_uri;
|
||
|
||
my $isiwebpasswd = vitoconnect_ReadKeyValue($hash,"passwd"); # verschlüsseltes Kennwort auslesen
|
||
if ($isiwebpasswd eq "") { # Kennwort (noch) nicht gespeichert
|
||
my $err = vitoconnect_StoreKeyValue($hash,"passwd",$param[3]); # Kennwort verschlüsselt speichern
|
||
return $err if ($err);
|
||
}
|
||
else { # Kennwort schon gespeichert
|
||
Log3($name,3,$name." - Passwort war bereits gespeichert");
|
||
}
|
||
$hash->{apiKey} = vitoconnect_ReadKeyValue($hash,"apiKey"); # verschlüsselten apiKey auslesen
|
||
RemoveInternalTimer($hash); # Timer löschen, z.b. bei intervall change
|
||
InternalTimer(gettimeofday() + 10,"vitoconnect_GetUpdate",$hash); # nach 10s
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# wird beim Löschen einer Geräteinstanz aufgerufen
|
||
#####################################################################################################################
|
||
sub vitoconnect_Undef {
|
||
my ($hash,$arg ) = @_; # Übergabe-Parameter
|
||
RemoveInternalTimer($hash); # Timer löschen
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# bisher kein 'get' implementiert
|
||
#####################################################################################################################
|
||
sub vitoconnect_Get {
|
||
my ($hash,$name,$opt,@args ) = @_; # Übergabe-Parameter
|
||
return "get ".$name." needs at least one argument" unless (defined($opt) );
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Implementierung set-Befehle
|
||
#####################################################################################################################
|
||
sub vitoconnect_Set {
|
||
my ($hash,$name,$opt,@args ) = @_; # Übergabe-Parameter
|
||
|
||
# Standard Parameter setzen
|
||
my $val = "unknown value $opt, choose one of update:noArg clearReadings:noArg password apiKey logResponseOnce:noArg clearMappedErrors:noArg ";
|
||
Log(5,$name.", -vitoconnect_Set started: ". $opt); #debug
|
||
|
||
# Setter für die Geräteauswahl dynamisch erstellen
|
||
Log3($name,5,$name." - Set devices: ".$hash->{devices});
|
||
if (defined $hash->{devices} && ref($hash->{devices}) eq 'HASH' && keys %{$hash->{devices}} > 0) {
|
||
my @device_serials = keys %{$hash->{devices}};
|
||
$val .= " selectDevice:" . join(",", @device_serials);
|
||
} else {
|
||
$val .= " selectDevice:noArg"
|
||
}
|
||
$val .= " ";
|
||
Log3($name,5,$name." - Set val: $val, Set Opt: $opt");
|
||
|
||
# Hier richtig?
|
||
return "set ".$name." needs at least one argument" unless (defined($opt) );
|
||
|
||
# Setter für Device Werte rufen
|
||
my $return;
|
||
if (AttrVal( $name, 'vitoconnect_raw_readings', 0 ) eq "1" ) {
|
||
#use new dynamic parsing of JSON to get raw setters
|
||
$return = vitoconnect_Set_New ($hash,$name,$opt,@args);
|
||
}
|
||
elsif (AttrVal( $name, 'vitoconnect_mapping_roger', 0 ) eq "1" ) {
|
||
#use roger setters
|
||
$return = vitoconnect_Set_Roger ($hash,$name,$opt,@args);
|
||
}
|
||
else {
|
||
#use svn setters
|
||
$return = vitoconnect_Set_SVN ($hash,$name,$opt,@args);
|
||
}
|
||
|
||
# Check if val was returned or action executed with return;
|
||
if (defined $return) {
|
||
$val .= $return;
|
||
} else {
|
||
return;
|
||
}
|
||
|
||
if ($opt eq "update") { # set <name> update: update readings immeadiatlely
|
||
RemoveInternalTimer($hash); # bisherigen Timer löschen
|
||
vitoconnect_GetUpdate($hash); # neue Abfrage starten
|
||
return;
|
||
}
|
||
elsif ($opt eq "logResponseOnce" ) { # set <name> logResponseOnce: dumps the json response of Viessmann server to entities.json, gw.json, actions.json in FHEM log directory
|
||
$hash->{".logResponseOnce"} = 1; # in 'Internals' merken
|
||
RemoveInternalTimer($hash); # bisherigen Timer löschen
|
||
vitoconnect_getCode($hash); # Werte für: Access-Token, Install-ID, Gateway anfragen
|
||
return;
|
||
}
|
||
elsif ($opt eq "clearReadings" ) { # set <name> clearReadings: clear all readings immeadiatlely
|
||
AnalyzeCommand($hash,"deletereading ".$name." .*");
|
||
return;
|
||
}
|
||
elsif ($opt eq "password" ) { # set <name> password: store password in key store
|
||
my $err = vitoconnect_StoreKeyValue($hash,"passwd",$args[0]); # Kennwort verschlüsselt speichern
|
||
return $err if ($err);
|
||
RemoveInternalTimer($hash);
|
||
vitoconnect_getCode($hash); # Werte für: Access-Token, Install-ID, Gateway anfragen
|
||
return;
|
||
}
|
||
elsif ($opt eq "apiKey" ) { # set <name> apiKey: bisher keine Beschreibung
|
||
$hash->{apiKey} = $args[0];
|
||
my $err = vitoconnect_StoreKeyValue($hash,"apiKey",$args[0]); # apiKey verschlüsselt speichern
|
||
return $err if ($err);
|
||
RemoveInternalTimer($hash);
|
||
vitoconnect_getCode($hash); # Werte für: Access-Token, Install-ID, Gateway anfragen
|
||
return;
|
||
}
|
||
elsif ($opt eq "selectDevice" ) { # set <name> selectDevice: Bei mehreren Devices eines auswählen
|
||
Log3($name,4,$name." - Set selectedDevice serial: ".$args[0]);
|
||
if (defined $args[0] && $args[0] ne '') {
|
||
my $serial = $args[0];
|
||
my %devices = %{ $hash->{devices} };
|
||
if (exists $devices{$serial}) {
|
||
my $installationId = $devices{$serial}{installationId};
|
||
Log3($name,5,$name." - Set selectedDevice: instID: $installationId, serial $serial");
|
||
CommandAttr (undef, "$name vitoconnect_installationID $installationId");
|
||
CommandAttr (undef, "$name vitoconnect_serial $serial");
|
||
}
|
||
$hash->{selectedDevice} = $serial;
|
||
RemoveInternalTimer($hash); # bisherigen Timer löschen
|
||
vitoconnect_GetUpdate($hash); # neue Abfrage starten
|
||
} else {
|
||
readingsSingleUpdate($hash,"state","Kein Gateway/Device gefunden, bitte Setup überprüfen",1);
|
||
}
|
||
return;
|
||
}
|
||
elsif ($opt eq "clearMappedErrors" ){
|
||
AnalyzeCommand($hash,"deletereading ".$name." device.messages.errors.mapped.*");
|
||
return;
|
||
}
|
||
|
||
return $val;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Implementierung set-Befehle neue logik aus raw readings
|
||
#####################################################################################################################
|
||
sub vitoconnect_Set_New {
|
||
my ($hash, $name, $opt, @args) = @_;
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
my $val = "";
|
||
|
||
my $Response = $hash->{".response_$gw"};
|
||
if ($Response) { # Überprüfen, ob $Response Daten enthält
|
||
my $data;
|
||
eval { $data = decode_json($Response); };
|
||
if ($@) {
|
||
# JSON-Dekodierung fehlgeschlagen, nur Standardoptionen zurückgeben
|
||
return $val;
|
||
}
|
||
|
||
foreach my $item (@{$data->{'data'}}) {
|
||
|
||
if (exists $item->{commands}) {
|
||
my $feature = $item->{feature};
|
||
Log(5,$name.",vitoconnect_Set_New feature: ". $feature);
|
||
|
||
foreach my $commandName (sort keys %{$item->{commands}}) { #<====== Loop Commands, sort necessary for activate temperature for burners, see below
|
||
my $commandNr = keys %{$item->{commands}};
|
||
my @propertyKeys = keys %{$item->{properties}};
|
||
my $propertyKeysNr = keys %{$item->{properties}};
|
||
my $paramNr = keys %{$item->{commands}{$commandName}{params}};
|
||
|
||
Log(5,$name.", -vitoconnect_Set_New isExecutable: ". $item->{commands}{$commandName}{isExecutable});
|
||
if ($item->{commands}{$commandName}{isExecutable} == 0) {
|
||
Log(5,$name.", -vitoconnect_Set_New $commandName nicht ausführbar");
|
||
next; #diser Befehl ist nicht ausführbar, nächster
|
||
}
|
||
|
||
Log(5,$name.", -vitoconnect_Set_New feature: ". $feature);
|
||
Log(5,$name.", -vitoconnect_Set_New commandNr: ". $commandNr);
|
||
Log(5,$name.", -vitoconnect_Set_New commandname: ". $commandName);
|
||
my $readingNamePrep;
|
||
if ($commandNr == 1 and $propertyKeysNr == 1) { # Ein command value = property z.B. heating.circuits.0.operating.modes.active
|
||
$readingNamePrep .= $feature.".". $propertyKeys[0];
|
||
} elsif ( $commandName eq "setTemperature" ) {
|
||
$readingNamePrep .= $feature.".temperature"; #<------- setTemperature only 1 param, so it can be defined here,
|
||
# for burner Vitoladens 300C, heating.circuits.0.operating.programs.comfort
|
||
# activate (temperature), deactivate(noArg), setTemperature (targetTemperature) only one can work with value provided
|
||
# Activate should work, and is, since commands are sorted
|
||
} elsif ( $commandName eq "setHysteresis" ) { #<------- setHysteresis very special mapping, must be predefined
|
||
$readingNamePrep .= $feature.".value";
|
||
} elsif ( $commandName eq "setHysteresisSwitchOnValue" ) { #<------- setHysteresis very special mapping, must be predefined
|
||
$readingNamePrep .= $feature.".switchOnValue";
|
||
} elsif ( $commandName eq "setHysteresisSwitchOffValue" ) { #<------- setHysteresis very special mapping, must be predefined
|
||
$readingNamePrep .= $feature.".switchOffValue";
|
||
} elsif ( $commandName eq "setMin" ) {
|
||
$readingNamePrep .= $feature.".min"; #<------- setMin/setMax very special mapping, must be predefined
|
||
} elsif ( $commandName eq "setMax" ) {
|
||
$readingNamePrep .= $feature.".max";
|
||
} elsif ( $commandName eq "setSchedule" ) { #<------- setSchedule very special mapping, must be predefined
|
||
$readingNamePrep .= $feature.".entries";
|
||
} elsif ( $commandName eq "setLevels" ) {
|
||
# duplicate, setMin, setMax can do this https://api.viessmann.com/iot/v2/features/installations/2772216/gateways/7736172146035226/devices/0/features/heating.circuits.0.temperature.levels/commands/setLevels
|
||
next;
|
||
}
|
||
else {
|
||
# all other cases, will be defined in param loop
|
||
}
|
||
if(defined($readingNamePrep))
|
||
{
|
||
Log(5,$name.", -vitoconnect_Set_New readingNamePrep: ". $readingNamePrep);
|
||
}
|
||
|
||
if ($paramNr > 2) { #<------- more then 2 parameters, with unsorted JSON can not be handled, but also do not exist at the moment
|
||
Log(5,$name.", -vitoconnect_Set_New mehr als 2 Parameter in Command $commandName, kann nicht berechnet werden");
|
||
next;
|
||
} elsif ($paramNr == 0){ #<------- no parameters, create here, param loop will not be executed
|
||
$readingNamePrep .= $feature.".".$commandName;
|
||
$val .= "$readingNamePrep:noArg ";
|
||
|
||
# Set execution
|
||
if ($opt eq $readingNamePrep) {
|
||
my $uri = $item->{commands}->{$commandName}->{'uri'};
|
||
my ($shortUri) = $uri =~ m|.*features/(.*)|; #<=== URI ohne gateway zeug
|
||
Log(4,$name.", -vitoconnect_Set_New, 0 param, short uri: ".$shortUri);
|
||
vitoconnect_action($hash,
|
||
$shortUri,
|
||
"{}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
|
||
# 1 oder 2 Params, all other cases see above
|
||
my @params = keys %{$item->{commands}{$commandName}{params}};
|
||
foreach my $paramName (@params) { #<==== Loop params
|
||
|
||
my $otherParam;
|
||
my $otherReadingName;
|
||
if ($paramNr == 2) {
|
||
$otherParam = $params[0] eq $paramName ? $params[1] : $params[0];
|
||
}
|
||
|
||
my $readingName = $readingNamePrep;
|
||
if (!defined($readingName)) { #<==== Bisher noch kein Reading gefunden, z.B. setCurve
|
||
$readingName = $feature.".".$paramName;
|
||
if (defined($otherParam)) {
|
||
$otherReadingName = $feature.".".$otherParam;
|
||
}
|
||
}
|
||
|
||
my $param = $item->{commands}{$commandName}{params}{$paramName};
|
||
|
||
# fill $val
|
||
if ($param->{type} eq 'number') {
|
||
$val .= $readingName.":slider," . ($param->{constraints}{min}) . "," . ($param->{constraints}{stepping}) . "," . ($param->{constraints}{max});
|
||
# Schauen ob float für slider
|
||
if ($param->{constraints}{stepping} =~ m/\./) {
|
||
$val .= ",1 ";
|
||
} else {
|
||
$val .= " ";
|
||
}
|
||
}
|
||
elsif ($param->{'type'} eq 'string') {
|
||
if ($commandName eq "setMode") {
|
||
my $enum = $param->{constraints}->{'enum'};
|
||
Log(5,$name.", -vitoconnect_Set_New enum: ". $enum);
|
||
my $enumNr = scalar @$enum;
|
||
Log(5,$name.", -vitoconnect_Set_New enumNr: ". $enumNr);
|
||
|
||
my $i = 1;
|
||
$val .= $readingName.":";
|
||
foreach my $value (@$enum) {
|
||
if ($i < $enumNr) {
|
||
$val .= $value.",";
|
||
} else {
|
||
$val .= $value." ";
|
||
}
|
||
$i++;
|
||
}
|
||
} else {
|
||
$val .= $readingName.":textField-long ";
|
||
}
|
||
|
||
} elsif ($param->{'type'} eq 'Schedule') {
|
||
$val .= $readingName.":textField-long ";
|
||
} elsif ($param->{'type'} eq 'boolean') {
|
||
$val .= "$readingName ";
|
||
} else {
|
||
# Ohne type direkter befehl ohne args
|
||
$val .= "$readingName:noArg ";
|
||
Log(5,$name.", -vitoconnect_Set_New unknown type: ".$readingName);
|
||
}
|
||
|
||
Log(5,$name.", -vitoconnect_Set_New exec, opt:".$opt.", readingName:".$readingName);
|
||
# Set execution
|
||
if ($opt eq $readingName) {
|
||
|
||
my $data;
|
||
my $otherData = '';
|
||
if ($param->{type} eq 'number') {
|
||
$data = "{\"$paramName\":@args";
|
||
}
|
||
elsif ($param->{type} eq 'Schedule') {
|
||
my $decoded_args = decode_json($args[0]);
|
||
|
||
# Transformieren der Datenstruktur
|
||
my %schedule;
|
||
foreach my $day (@$decoded_args) {
|
||
foreach my $key (keys %$day) {
|
||
push @{$schedule{$key}}, $day->{$key};
|
||
}
|
||
}
|
||
|
||
# Konvertieren der transformierten Datenstruktur in JSON
|
||
my $schedule_data = encode_json(\%schedule);
|
||
$data = "{\"$paramName\":$schedule_data";
|
||
}
|
||
else {
|
||
$data = "{\"$paramName\":\"@args\"";
|
||
}
|
||
Log(5,$name.", -vitoconnect_Set_New, paramName:".$paramName.", args:".Dumper(\@args));
|
||
|
||
# 2 params, one can be set the other must just be read and handed overload
|
||
# This logic ensures that we get the correct names in an unsortet JSON
|
||
if (defined($otherReadingName)) {
|
||
my $otherValue = ReadingsVal($name,$otherReadingName,"");
|
||
if ($param->{type} eq 'number') {
|
||
$otherData = ",\"$otherParam\":$otherValue";
|
||
} else {
|
||
$otherData = ",\"$otherParam\":\"$otherValue\"";
|
||
}
|
||
}
|
||
$data .= $otherData . '}';
|
||
my $uri = $item->{commands}->{$commandName}->{'uri'};
|
||
my ($shortUri) = $uri =~ m|.*features/(.*)|; #<=== URI ohne gateway zeug
|
||
Log(4,$name.", -vitoconnect_Set_New, short uri:".$shortUri.", data:".$data);
|
||
vitoconnect_action($hash,
|
||
$shortUri,
|
||
$data,
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
# Rückgabe der dynamisch erstellten $val Variable
|
||
Log(5,$name.", -vitoconnect_Set_New val: ". $val);
|
||
Log(5,$name.", -vitoconnect_Set_New ended ");
|
||
|
||
return $val;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Implementierung set-Befehle alte logik fixes mapping letzte SVN Version
|
||
#####################################################################################################################
|
||
sub vitoconnect_Set_SVN {
|
||
my ($hash,$name,$opt,@args ) = @_; # Übergabe-Parameter
|
||
# SVN mapping original handling of modul
|
||
|
||
if ( $opt eq "HK1-Heizkurve-Niveau" ) {
|
||
my $slope = ReadingsVal( $name, "HK1-Heizkurve-Steigung", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.0.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Heizkurve-Niveau" ) {
|
||
my $slope = ReadingsVal( $name, "HK2-Heizkurve-Steigung", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.1.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Heizkurve-Niveau" ) {
|
||
my $slope = ReadingsVal( $name, "HK3-Heizkurve-Steigung", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.2.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Heizkurve-Steigung" ) {
|
||
my $shift = ReadingsVal( $name, "HK1-Heizkurve-Niveau", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.0.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Heizkurve-Steigung" ) {
|
||
my $shift = ReadingsVal( $name, "HK2-Heizkurve-Niveau", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.1.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Heizkurve-Steigung" ) {
|
||
my $shift = ReadingsVal( $name, "HK3-Heizkurve-Niveau", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.2.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Urlaub_Start" ) {
|
||
my $end = ReadingsVal( $name, "HK1-Urlaub_Ende", "" );
|
||
if ( $end eq "" ) {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Urlaub_Start" ) {
|
||
my $end = ReadingsVal( $name, "HK2-Urlaub_Ende", "" );
|
||
if ( $end eq "" ) {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Urlaub_Start" ) {
|
||
my $end = ReadingsVal( $name, "HK3-Urlaub_Ende", "" );
|
||
if ( $end eq "" ) {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Urlaub_Ende" ) {
|
||
my $start = ReadingsVal( $name, "HK1-Urlaub_Start", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Urlaub_Ende" ) {
|
||
my $start = ReadingsVal( $name, "HK2-Urlaub_Start", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Urlaub_Ende" ) {
|
||
my $start = ReadingsVal( $name, "HK3-Urlaub_Start", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Urlaub_unschedule" ) {
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Urlaub_unschedule" ) {
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Urlaub_unschedule" ) {
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Zeitsteuerung_Heizung" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.0.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Zeitsteuerung_Heizung" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.1.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Zeitsteuerung_Heizung" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.2.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Betriebsart" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.0.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Betriebsart" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.1.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Betriebsart" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.2.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Solltemperatur_comfort_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.0.operating.programs.comfort/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Solltemperatur_comfort_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.1.operating.programs.comfort/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Solltemperatur_comfort_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.2.operating.programs.comfort/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Solltemperatur_comfort" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Solltemperatur_comfort" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Solltemperatur_comfort" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Solltemperatur_eco_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.0.operating.programs.eco/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
|
||
}
|
||
elsif ( $opt eq "HK2-Solltemperatur_eco_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.1.operating.programs.eco/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Solltemperatur_eco_aktiv" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.circuits.2.operating.programs.eco/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Solltemperatur_normal" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Solltemperatur_normal" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Solltemperatur_normal" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Solltemperatur_reduziert" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Solltemperatur_reduziert" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Solltemperatur_reduziert" ) {
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,
|
||
$opt,
|
||
@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK1-Name" ) {
|
||
vitoconnect_action( $hash, "heating.circuits.0/commands/setName",
|
||
"{\"name\":\"@args\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK2-Name" ) {
|
||
vitoconnect_action( $hash, "heating.circuits.1/commands/setName",
|
||
"{\"name\":\"@args\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "HK3-Name" ) {
|
||
vitoconnect_action( $hash, "heating.circuits.2/commands/setName",
|
||
"{\"name\":\"@args\"}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-einmaliges_Aufladen" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.dhw.oneTimeCharge/commands/$args[0]",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-Zirkulationspumpe_Zeitplan" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.dhw.pumps.circulation.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-Zeitplan" ) {
|
||
vitoconnect_action( $hash, "heating.dhw.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-Haupttemperatur" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.dhw.temperature.main/commands/setTargetTemperature",
|
||
"{\"temperature\":$args[0]}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-Solltemperatur" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.dhw.temperature/commands/commands/setTargetTemperature",
|
||
"{\"temperature\":$args[0]}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "WW-Temperatur_2" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.dhw.temperature.temp2/commands/setTargetTemperature",
|
||
"{\"temperature\":$args[0]}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
elsif ( $opt eq "Urlaub_Start" ) {
|
||
my $end = ReadingsVal( $name, "Urlaub_Ende", "" );
|
||
if ( $end eq "" ) {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "Urlaub_Ende" ) {
|
||
my $start = ReadingsVal( $name, "Urlaub_Start", "" );
|
||
vitoconnect_action(
|
||
$hash,
|
||
"heating.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name, $opt, @args
|
||
);
|
||
return;
|
||
}
|
||
elsif ( $opt eq "Urlaub_unschedule" ) {
|
||
vitoconnect_action( $hash,
|
||
"heating.operating.programs.holiday/commands/unschedule",
|
||
"{}", $name, $opt, @args );
|
||
return;
|
||
}
|
||
|
||
my $val = "WW-einmaliges_Aufladen:activate,deactivate "
|
||
. "WW-Zirkulationspumpe_Zeitplan:textField-long "
|
||
. "WW-Zeitplan:textField-long "
|
||
. "WW-Haupttemperatur:slider,10,1,60 "
|
||
. "WW-Solltemperatur:slider,10,1,60 "
|
||
. "WW-Temperatur_2:slider,10,1,60 "
|
||
. "Urlaub_Start "
|
||
. "Urlaub_Ende "
|
||
. "Urlaub_unschedule:noArg ";
|
||
|
||
if ( ReadingsVal( $name, "HK1-aktiv", "0" ) eq "1" ) {
|
||
$val .=
|
||
"HK1-Heizkurve-Niveau:slider,-13,1,40 "
|
||
. "HK1-Heizkurve-Steigung:slider,0.2,0.1,3.5,1 "
|
||
. "HK1-Zeitsteuerung_Heizung:textField-long "
|
||
. "HK1-Urlaub_Start "
|
||
. "HK1-Urlaub_Ende "
|
||
. "HK1-Urlaub_unschedule:noArg "
|
||
. "HK1-Betriebsart:active,standby,heating,dhw,dhwAndHeating,forcedReduced,forcedNormal "
|
||
. "HK1-Solltemperatur_comfort_aktiv:activate,deactivate "
|
||
. "HK1-Solltemperatur_comfort:slider,4,1,37 "
|
||
. "HK1-Solltemperatur_eco_aktiv:activate,deactivate "
|
||
. "HK1-Solltemperatur_normal:slider,3,1,37 "
|
||
. "HK1-Solltemperatur_reduziert:slider,3,1,37 "
|
||
. "HK1-Name ";
|
||
}
|
||
if ( ReadingsVal( $name, "HK2-aktiv", "0" ) eq "1" ) {
|
||
$val .=
|
||
"HK2-Heizkurve-Niveau:slider,-13,1,40 "
|
||
. "HK2-Heizkurve-Steigung:slider,0.2,0.1,3.5,1 "
|
||
. "HK2-Zeitsteuerung_Heizung:textField-long "
|
||
. "HK2-Urlaub_Start "
|
||
. "HK2-Urlaub_Ende "
|
||
. "HK2-Urlaub_unschedule:noArg "
|
||
. "HK2-Betriebsart:active,standby,heating,dhw,dhwAndHeating,forcedReduced,forcedNormal "
|
||
. "HK2-Solltemperatur_comfort_aktiv:activate,deactivate "
|
||
. "HK2-Solltemperatur_comfort:slider,4,1,37 "
|
||
. "HK2-Solltemperatur_eco_aktiv:activate,deactivate "
|
||
. "HK2-Solltemperatur_normal:slider,3,1,37 "
|
||
. "HK2-Solltemperatur_reduziert:slider,3,1,37 "
|
||
. "HK2-Name ";
|
||
}
|
||
if ( ReadingsVal( $name, "HK3-aktiv", "0" ) eq "1" ) {
|
||
$val .=
|
||
"HK3-Heizkurve-Niveau:slider,-13,1,40 "
|
||
. "HK3-Heizkurve-Steigung:slider,0.2,0.1,3.5,1 "
|
||
. "HK3-Zeitsteuerung_Heizung:textField-long "
|
||
. "HK3-Urlaub_Start "
|
||
. "HK3-Urlaub_Ende "
|
||
. "HK3-Urlaub_unschedule:noArg "
|
||
. "HK3-Betriebsart:active,standby,heating,dhw,dhwAndHeating,forcedReduced,forcedNormal "
|
||
. "HK3-Solltemperatur_comfort_aktiv:activate,deactivate "
|
||
. "HK3-Solltemperatur_comfort:slider,4,1,37 "
|
||
. "HK3-Solltemperatur_eco_aktiv:activate,deactivate "
|
||
. "HK3-Solltemperatur_normal:slider,3,1,37 "
|
||
. "HK3-Solltemperatur_reduziert:slider,3,1,37 "
|
||
. "HK3-Name ";
|
||
}
|
||
|
||
return $val;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Implementierung set-Befehle alte logik fixes mapping von Roger letzte Version
|
||
#####################################################################################################################
|
||
sub vitoconnect_Set_Roger {
|
||
my ($hash,$name,$opt,@args ) = @_; # Übergabe-Parameter
|
||
|
||
if ($opt eq "HK1_Betriebsart" ) { # set <name> HKn_Betriebsart: sets HKn_Betriebsart to heating,standby
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Soll_Temp_normal" ) { # set <name> HK1_Soll_Temp_normal: sets the normale target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Soll_Temp_reduziert" ) { # set <name> HK1_Soll_Temp_reduziert: sets the reduced target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Soll_Temp_comfort" ) { # set <name> HK1_Soll_Temp_comfort: set comfort target temperatur for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Soll_Temp_comfort_aktiv" ) { # set <name> HK1_Soll_Temp_comfort_aktiv: activate/deactivate comfort temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.comfort/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Soll_Temp_eco_aktiv" ) { # set <name> HK1_Soll_Temp_eco_aktiv: activate/deactivate eco temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.eco/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "WW_Betriebsart" ) { # set <name> HKn_Betriebsart: sets WW_Betriebsart to balanced,off
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "WW_einmaliges_Aufladen" ) { # set <name> WW_einmaliges_Aufladen: activate or deactivate one time charge for hot water
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.oneTimeCharge/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "WW_Solltemperatur" ) { # set <name> WW_Solltemperatur: sets hot water main temperature to targetTemperature, targetTemperature is an integer between 10 and 60
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.temperature.main/commands/setTargetTemperature",
|
||
"{\"temperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "WW_Zirkulationspumpe_Zeitplan" ) { # set <name> WW_Zirkulationspumpe_Zeitplan: sets the schedule in JSON format for hot water circulation pump
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.pumps.circulation.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "WW_Zeitplan" ) { # set <name> WW_Zeitplan: sets the schedule in JSON format for hot water
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
# elsif ($opt eq "WW_Solltemperatur" ) { # set <name> WW_Solltemperatur: sets hot water temperature to targetTemperature, targetTemperature is an integer between 10 and 60
|
||
# vitoconnect_action($hash,
|
||
# "heating.dhw.temperature/commands/commands/setTargetTemperature",
|
||
# "{\"temperature\":$args[0]}",
|
||
# $name,$opt,@args
|
||
# );
|
||
# return;
|
||
# }
|
||
elsif ($opt eq "WW_Temperatur_2" ) { # set <name> WW_Temperatur_2: sets hot water 2 temperature to targetTemperature, targetTemperature is an integer between 10 and 60
|
||
vitoconnect_action($hash,
|
||
"heating.dhw.temperature.temp2/commands/setTargetTemperature",
|
||
"{\"temperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "Urlaub_Start_Zeit" ) { # set <name> Urlaub_Start_Zeit: set holiday start time, start has to look like this: 2019-02-02
|
||
my $end = ReadingsVal($name,"Urlaub_Ende_Zeit","");
|
||
if ($end eq "") {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action($hash,
|
||
"heating.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "Urlaub_Ende_Zeit" ) { # set <name> Urlaub_Ende_Zeit: set holiday end time, end has to look like this: 2019-02-16
|
||
my $start = ReadingsVal($name,"Urlaub_Start_Zeit","");
|
||
vitoconnect_action($hash,
|
||
"heating.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "Urlaub_stop" ) { # set <name> Urlaub_stop: remove holiday start and end time
|
||
vitoconnect_action($hash,
|
||
"heating.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Name" ) { # set <name> HK1_Name: sets the name of the circuit for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0/commands/setName",
|
||
"{\"name\":\"@args\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Name" ) { # set <name> HK2_Name: sets the name of the circuit for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1/commands/setName",
|
||
"{\"name\":\"@args\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Name" ) { # set <name> HK3_Name: sets the name of the circuit for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2/commands/setName",
|
||
"{\"name\":\"@args\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Heizkurve_Niveau" ) { # set <name> HK1_Heizkurve_Niveau: set shift of heating curve for HKn
|
||
my $slope = ReadingsVal($name,"HK1_Heizkurve_Steigung","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Heizkurve_Niveau" ) { # set <name> HK2_Heizkurve_Niveau: set shift of heating curve for HKn
|
||
my $slope = ReadingsVal($name,"HK2_Heizkurve_Steigung","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Heizkurve_Niveau" ) { # set <name> HK3_Heizkurve_Niveau: set shift of heating curve for HKn
|
||
my $slope = ReadingsVal($name,"HK3_Heizkurve_Steigung","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.heating.curve/commands/setCurve",
|
||
"{\"shift\":$args[0],\"slope\":$slope}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Heizkurve_Steigung" ) { # set <name> HK1_Heizkurve_Steigung: set slope of heating curve for HKn
|
||
my $shift = ReadingsVal($name,"HK1_Heizkurve_Niveau","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Heizkurve_Steigung" ) { # set <name> HK2_Heizkurve_Steigung: set slope of heating curve for HKn
|
||
my $shift = ReadingsVal($name,"HK2-Heizkurve-Niveau","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Heizkurve_Steigung" ) { # set <name> HK3_Heizkurve_Steigung: set slope of heating curve for HKn
|
||
my $shift = ReadingsVal($name,"HK3-Heizkurve-Niveau","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.heating.curve/commands/setCurve",
|
||
"{\"shift\":$shift,\"slope\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Urlaub_Start_Zeit" ) { # set <name> HK1_Urlaub_Start_Zeit: set holiday start time for HKn, start has to look like this: 2019-02-16
|
||
my $end = ReadingsVal($name,"HK1_Urlaub_Ende_Zeit","");
|
||
if ($end eq "") {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Urlaub_Start_Zeit" ) { # set <name> HK2_Urlaub_Start_Zeit: set holiday start time for HKn, start has to look like this: 2019-02-16
|
||
my $end = ReadingsVal($name,"HK2_Urlaub_Ende_Zeit","");
|
||
if ($end eq "") {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Urlaub_Start_Zeit" ) { # set <name> HK3-HK3_Urlaub_Start_Zeit: set holiday start time for HKn, start has to look like this: 2019-02-16
|
||
my $end = ReadingsVal($name,"HK3_Urlaub_Ende_Zeit","");
|
||
if ($end eq "") {
|
||
my $t = Time::Piece->strptime( $args[0], "%Y-%m-%d" );
|
||
$t += ONE_DAY;
|
||
$end = $t->strftime("%Y-%m-%d");
|
||
}
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$args[0]\",\"end\":\"$end\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Urlaub_Ende_Zeit" ) { # set <name> HK1_Urlaub_Ende_Zeit: set holiday end time for HKn, end has to look like this: 2019-02-16
|
||
my $start = ReadingsVal($name,"HK1_Urlaub_Start_Zeit","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Urlaub_Ende_Zeit" ) { # set <name> HK2_Urlaub_Ende_Zeit: set holiday end time for HKn, end has to look like this: 2019-02-16
|
||
my $start = ReadingsVal($name,"HK2_Urlaub_Start_Zeit","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Urlaub_Ende_Zeit" ) { # set <name> HK3_Urlaub_Ende_Zeit: set holiday end time for HKn, end has to look like this: 2019-02-16
|
||
my $start = ReadingsVal($name,"HK3_Urlaub_Start_Zeit","");
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/schedule",
|
||
"{\"start\":\"$start\",\"end\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Urlaub_stop" ) { # set <name> HK1_Urlaub_stop: remove holiday start and end time for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Urlaub_stop" ) { # set <name> HK2_Urlaub_stop: remove holiday start and end time for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Urlaub_stop" ) { # set <name> HK3_Urlaub_stop: remove holiday start and end time for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.holiday/commands/unschedule",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK1_Zeitsteuerung_Heizung" ) { # set <name> HK1_Zeitsteuerung_Heizung: sets the heating schedule in JSON format for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.0.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2-Zeitsteuerung_Heizung" ) { # set <name> HK2-Zeitsteuerung_Heizung: sets the heating schedule in JSON format for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3-Zeitsteuerung_Heizung" ) { # set <name> HK3-Zeitsteuerung_Heizung: sets the heating schedule in JSON format for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.heating.schedule/commands/setSchedule",
|
||
"{\"newSchedule\":@args}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Betriebsart" ) { # set <name> HK2-Betriebsart: sets HKn_Betriebsart to heating,standby
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Betriebsart" ) { # set <name> HK3-Betriebsart: sets HKn_Betriebsart to heating,standby
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.modes.active/commands/setMode",
|
||
"{\"mode\":\"$args[0]\"}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2-Solltemperatur_comfort_aktiv" ) { # set <name> HK2-Solltemperatur_comfort_aktiv: activate/deactivate comfort temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.comfort/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3-Solltemperatur_comfort_aktiv" ) { # set <name> HK3-Solltemperatur_comfort_aktiv: activate/deactivate comfort temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.comfort/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2-Solltemperatur_comfort" ) { # set <name> HK2-Solltemperatur_comfort: set comfort target temperatur for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3-Solltemperatur_comfort" ) { # set <name> HK3-Solltemperatur_comfort: set comfort target temperatur for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.comfort/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Solltemperatur_eco_aktiv" ) { # set <name> HK2_Solltemperatur_eco_aktiv: activate/deactivate eco temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.eco/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Solltemperatur_eco_aktiv" ) { # set <name> HK3_Solltemperatur_eco_aktiv: activate/deactivate eco temperature for HKn
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.eco/commands/$args[0]",
|
||
"{}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Solltemperatur_normal" ) { # set <name> HK2_Solltemperatur_normal: sets the normale target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Solltemperatur_normal" ) { # set <name> HK3_Solltemperatur_normal: sets the normale target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.normal/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK2_Solltemperatur_reduziert" ) { # set <name> HK2_Solltemperatur_reduziert: sets the reduced target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.1.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}",
|
||
$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
elsif ($opt eq "HK3_Solltemperatur_reduziert" ) { # set <name> HK3_Solltemperatur_reduziert: sets the reduced target temperature for HKn, where targetTemperature is an integer between 3 and 37
|
||
vitoconnect_action($hash,
|
||
"heating.circuits.2.operating.programs.reduced/commands/setTemperature",
|
||
"{\"targetTemperature\":$args[0]}"
|
||
,$name,$opt,@args
|
||
);
|
||
return;
|
||
}
|
||
|
||
my $val = "WW_einmaliges_Aufladen:activate,deactivate "
|
||
."WW_Zirkulationspumpe_Zeitplan:textField-long "
|
||
."WW_Zeitplan:textField-long "
|
||
# ."WW_Haupttemperatur:slider,10,1,60 "
|
||
."WW_Solltemperatur:slider,10,1,60 "
|
||
."WW_Temperatur_2:slider,10,1,60 "
|
||
."WW_Betriebsart:balanced,off "
|
||
."Urlaub_Start_Zeit "
|
||
."Urlaub_Ende_Zeit "
|
||
."Urlaub_stop:noArg ";
|
||
|
||
if (ReadingsVal($name,"HK1_aktiv","0") eq "1") {
|
||
$val .=
|
||
"HK1_Heizkurve_Niveau:slider,-13,1,40 "
|
||
."HK1_Heizkurve_Steigung:slider,0.2,0.1,3.5,1 "
|
||
."HK1_Zeitsteuerung_Heizung:textField-long "
|
||
."HK1_Urlaub_Start_Zeit "
|
||
."HK1_Urlaub_Ende_Zeit "
|
||
."HK1_Urlaub_stop:noArg "
|
||
."HK1_Betriebsart:active,standby "
|
||
."HK1_Soll_Temp_comfort_aktiv:activate,deactivate "
|
||
."HK1_Soll_Temp_comfort:slider,4,1,37 "
|
||
."HK1_Soll_Temp_eco_aktiv:activate,deactivate "
|
||
."HK1_Soll_Temp_normal:slider,3,1,37 "
|
||
."HK1_Soll_Temp_reduziert:slider,3,1,37 "
|
||
."HK1_Name ";
|
||
}
|
||
if (ReadingsVal($name,"HK2_aktiv","0") eq "1") {
|
||
$val .=
|
||
"HK2_Heizkurve_Niveau:slider,-13,1,40 "
|
||
. "HK2_Heizkurve_Steigung:slider,0.2,0.1,3.5,1 "
|
||
. "HK2_Zeitsteuerung_Heizung:textField-long "
|
||
. "HK2_Urlaub_Start_Zeit "
|
||
. "HK2_Urlaub_Ende_Zeit "
|
||
. "HK2_Urlaub_stop:noArg "
|
||
. "HK2_Betriebsart:active,standby,heating,dhw,dhwAndHeating,forcedReduced,forcedNormal "
|
||
. "HK2_Solltemperatur_comfort_aktiv:activate,deactivate "
|
||
. "HK2_Solltemperatur_comfort:slider,4,1,37 "
|
||
. "HK2_Solltemperatur_eco_aktiv:activate,deactivate "
|
||
. "HK2_Solltemperatur_normal:slider,3,1,37 "
|
||
. "HK2_Solltemperatur_reduziert:slider,3,1,37 "
|
||
. "HK2_Name ";
|
||
}
|
||
if (ReadingsVal($name,"HK3_aktiv","0") eq "1") {
|
||
$val .=
|
||
"HK3_Heizkurve_Niveau:slider,-13,1,40 "
|
||
. "HK3_Heizkurve_Steigung:slider,0.2,0.1,3.5,1 "
|
||
. "HK3_Zeitsteuerung_Heizung:textField-long "
|
||
. "HK3_Urlaub_Start_Zeit "
|
||
. "HK3_Urlaub_Ende_Zeit "
|
||
. "HK3_Urlaub_stop:noArg "
|
||
. "HK3_Betriebsart:active,standby,heating,dhw,dhwAndHeating,forcedReduced,forcedNormal "
|
||
. "HK3_Solltemperatur_comfort_aktiv:activate,deactivate "
|
||
. "HK3_Solltemperatur_comfort:slider,4,1,37 "
|
||
. "HK3_Solltemperatur_eco_aktiv:activate,deactivate "
|
||
. "HK3_Solltemperatur_normal:slider,3,1,37 "
|
||
. "HK3_Solltemperatur_reduziert:slider,3,1,37 "
|
||
. "HK3_Name ";
|
||
}
|
||
|
||
return $val;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Attribute setzen/ändern/löschen
|
||
#####################################################################################################################
|
||
sub vitoconnect_Attr {
|
||
my ($cmd,$name,$attr_name,$attr_value ) = @_;
|
||
|
||
Log(5,$name.", ".$cmd ." vitoconnect_: ".($attr_name // 'undef')." value: ".($attr_value // 'undef'));
|
||
if ($cmd eq "set") {
|
||
if ($attr_name eq "vitoconnect_raw_readings" ) {
|
||
if ($attr_value !~ /^0|1$/) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 0 or 1.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_disable_raw_readings") {
|
||
if ( $attr_value !~ /^0|1$/ ) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 0 or 1.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_gw_readings") {
|
||
if ( $attr_value !~ /^0|1$/ ) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 0 or 1.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_actions_active") {
|
||
if ($attr_value !~ /^0|1$/) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 0 or 1.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_mappings") {
|
||
$RequestListMapping = eval $attr_value;
|
||
if ($@) {
|
||
# Fehlerbehandlung
|
||
my $err = "Invalid argument: $@\n";
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_translations") {
|
||
%translations = eval $attr_value;
|
||
if ($@) {
|
||
# Fehlerbehandlung
|
||
my $err = "Invalid argument: $@\n";
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_mapping_roger") {
|
||
if ($attr_value !~ /^0|1$/) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 0 or 1.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_serial") {
|
||
if (length($attr_value) != 16) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be 16 characters long.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_installationID") {
|
||
if (length($attr_value) < 2) {
|
||
my $err = "Invalid argument ".$attr_value." to ".$attr_name.". Must be at least 2 characters long.";
|
||
Log(1,$name.", vitoconnect_Attr: ".$err);
|
||
return $err;
|
||
}
|
||
}
|
||
elsif ($attr_name eq "disable") {
|
||
}
|
||
elsif ($attr_name eq "verbose") {
|
||
}
|
||
else {
|
||
# return "Unknown attr $attr_name";
|
||
# This will return all attr, e.g. room. We do not want to see messages here.
|
||
# Log(1,$name.", ".$cmd ." Unknow attr vitoconnect_: ".($attr_name // 'undef')." value: ".($attr_value // 'undef'));
|
||
}
|
||
}
|
||
elsif ($cmd eq "del") {
|
||
if ($attr_name eq "vitoconnect_mappings") {
|
||
undef $RequestListMapping;
|
||
}
|
||
elsif ($attr_name eq "vitoconnect_translations") {
|
||
undef %translations;
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# # Abfrage aller Werte starten
|
||
#####################################################################################################################
|
||
sub vitoconnect_GetUpdate {
|
||
my ($hash) = @_;# Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
Log3($name,4,$name." GetUpdate called by caller name: $name, memoryadress: $hash");
|
||
if (IsDisabled($name)) { # Device disabled
|
||
Log3($name,4,$name." - device disabled");
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash); # nach Intervall erneut versuchen
|
||
return;
|
||
}
|
||
else { # Device nicht disabled
|
||
vitoconnect_getResource($hash);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Werte für: Access-Token, Install-ID, Gateway anfragen
|
||
#####################################################################################################################
|
||
sub vitoconnect_getCode {
|
||
my ($hash) = @_; # Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
my $isiwebpasswd = vitoconnect_ReadKeyValue($hash,"passwd"); # verschlüsseltes Kennwort auslesen
|
||
my $client_id = $hash->{apiKey};
|
||
if (!defined($client_id)) { # $client_id/apiKey nicht definiert
|
||
Log3($name,1,$name." - set apiKey first"); # Fehlermeldung ins Log
|
||
readingsSingleUpdate($hash,"state","Set apiKey to continue",1); # Reading 'state' setzen
|
||
return;
|
||
}
|
||
|
||
my $param = {
|
||
url => $authorizeURL
|
||
."?client_id=".$client_id
|
||
."&redirect_uri=".$callback_uri."&"
|
||
."code_challenge=2e21faa1-db2c-4d0b-a10f-575fd372bc8c-575fd372bc8c&"
|
||
."&scope=IoT%20User%20offline_access"
|
||
."&response_type=code",
|
||
hash => $hash,
|
||
header => "Content-Type: application/x-www-form-urlencoded",
|
||
ignoreredirects => 1,
|
||
user => $hash->{user},
|
||
pwd => $isiwebpasswd,
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
timeout => $hash->{timeout},
|
||
method => "POST",
|
||
callback => \&vitoconnect_getCodeCallback
|
||
};
|
||
|
||
#Log3 $name, 4, "$name - user=$param->{user} passwd=$param->{pwd}";
|
||
#Log3 $name, 5, Dumper($hash);
|
||
HttpUtils_NonblockingGet($param); # Anwort an: vitoconnect_getCodeCallback()
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Rückgabe: Access-Token, Install-ID, Gateway von vitoconnect_getCode Anfrage
|
||
#####################################################################################################################
|
||
sub vitoconnect_getCodeCallback {
|
||
my ($param,$err,$response_body ) = @_; # Übergabe-Parameter
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
|
||
if ($err eq "") { # Antwort kein Fehler
|
||
Log3($name,4,$name." - getCodeCallback went ok");
|
||
Log3($name,5,$name." - Received response: ".$response_body);
|
||
$response_body =~ /code=(.*)"/;
|
||
$hash->{".code"} = $1; # in Internal '.code' speichern
|
||
Log3($name,4,$name." - code: ".$hash->{".code"});
|
||
if ( $hash->{".code"} && $hash->{".code"} ne "4" ) {
|
||
$hash->{login} = "ok"; # Internal 'login'
|
||
}
|
||
else {
|
||
$hash->{login} = "failure"; # Internal 'login'
|
||
}
|
||
}
|
||
else { # Fehler als Antwort
|
||
Log3($name,1,$name.", vitoconnect_getCodeCallback - An error occured: ".$err);
|
||
$hash->{login} = "failure";
|
||
}
|
||
|
||
if ( $hash->{login} eq "ok" ) { # Login hat geklappt
|
||
readingsSingleUpdate($hash,"state","login ok",1); # Reading 'state' setzen
|
||
vitoconnect_getAccessToken($hash); # Access & Refresh-Token holen
|
||
}
|
||
else { # Fehler beim Login
|
||
readingsSingleUpdate($hash,"state","Login failure. Check password and apiKey",1); # Reading 'state' setzen
|
||
Log3($name,1,$name." - Login failure. Check password and apiKey");
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash); # Forum: #880
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Access & Refresh-Token holen
|
||
#####################################################################################################################
|
||
sub vitoconnect_getAccessToken {
|
||
my ($hash) = @_; # Übergabe-Parameter
|
||
my $name = $hash->{NAME}; # Device-Name
|
||
my $client_id = $hash->{apiKey}; # Internal: apiKey
|
||
my $param = {
|
||
url => $tokenURL,
|
||
hash => $hash,
|
||
header => "Content-Type: application/x-www-form-urlencoded",
|
||
data => "grant_type=authorization_code"
|
||
. "&code_verifier="
|
||
. $client_secret
|
||
. "&client_id=$client_id"
|
||
. "&redirect_uri=$callback_uri"
|
||
. "&code="
|
||
. $hash->{".code"},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
method => "POST",
|
||
timeout => $hash->{timeout},
|
||
callback => \&vitoconnect_getAccessTokenCallback
|
||
};
|
||
|
||
#Log3 $name, 1, "$name - " . $param->{"data"};
|
||
HttpUtils_NonblockingGet($param); # Anwort an: vitoconnect_getAccessTokenCallback()
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Access & Refresh-Token speichern, Antwort auf: vitoconnect_getAccessToken
|
||
#####################################################################################################################
|
||
sub vitoconnect_getAccessTokenCallback {
|
||
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME}; # Device-Name
|
||
|
||
if ($err eq "") { # kein Fehler bei Antwort
|
||
Log3($name,4,$name." - getAccessTokenCallback went ok");
|
||
Log3($name,5,$name." - Received response: ".$response_body."\n");
|
||
my $decode_json = eval {decode_json($response_body)};
|
||
if ($@) {
|
||
Log3($name,1,$name.", vitoconnect_getAccessTokenCallback: JSON error while request: ".$@);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
my $access_token = $decode_json->{"access_token"}; # aus JSON dekodieren
|
||
if ($access_token ne "") {
|
||
$hash->{".access_token"} = $access_token; # in Internals speichern
|
||
$hash->{"refresh_token"} = $decode_json->{"refresh_token"}; # in Internals speichern
|
||
|
||
Log3($name,4,$name." - Access Token: ".substr($access_token,0,20)."...");
|
||
vitoconnect_getGw($hash); # Abfrage Gateway-Serial
|
||
}
|
||
else {
|
||
Log3($name,1,$name." - Access Token: nicht definiert");
|
||
Log3($name,5,$name." - Received response: ".$response_body."\n");
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
}
|
||
else { # Fehler bei Antwort
|
||
Log3($name,1,$name.",vitoconnect_getAccessTokenCallback - getAccessToken: An error occured: ".$err);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# neuen Access-Token anfragen
|
||
#####################################################################################################################
|
||
sub vitoconnect_getRefresh {
|
||
my ($hash, $caller) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $client_id = $hash->{apiKey};
|
||
my $param = {
|
||
url => $tokenURL,
|
||
hash => $hash,
|
||
header => "Content-Type: application/x-www-form-urlencoded",
|
||
data => "grant_type=refresh_token"
|
||
. "&client_id=$client_id"
|
||
. "&refresh_token="
|
||
. $hash->{"refresh_token"},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
method => "POST",
|
||
timeout => $hash->{timeout},
|
||
caller => $caller, # <–– Kontext hier speichern!
|
||
callback => \&vitoconnect_getRefreshCallback
|
||
};
|
||
|
||
#Log3 $name, 1, "$name - " . $param->{"data"};
|
||
HttpUtils_NonblockingGet($param);
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# neuen Access-Token speichern
|
||
#####################################################################################################################
|
||
sub vitoconnect_getRefreshCallback {
|
||
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $caller = $param->{caller} // 'update'; # Default: update
|
||
|
||
if ($err eq "") {
|
||
Log3($name,4,$name.". - getRefreshCallback went ok");
|
||
Log3($name,5,$name." - Received response: ".$response_body."\n");
|
||
my $decode_json = eval {decode_json($response_body)};
|
||
if ($@) { # Fehler aufgetreten
|
||
Log3($name,1,$name.", vitoconnect_getRefreshCallback: JSON error while request: ".$@);
|
||
if ($caller ne 'action') {
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
}
|
||
return;
|
||
}
|
||
my $access_token = $decode_json->{"access_token"};
|
||
if ($access_token ne "") { # kein Fehler
|
||
$hash->{".access_token"} = $access_token; # in Internal merken
|
||
Log3($name,4,$name." - Access Token: ".substr($access_token,0,20)."...");
|
||
#vitoconnect_getGw($hash); # Abfrage Gateway-Serial
|
||
# directly call get resource to save API calls
|
||
if ($caller eq 'action') {
|
||
vitoconnect_action(
|
||
$hash,
|
||
$hash->{".retry_feature"},
|
||
$hash->{".retry_data"},
|
||
$name,
|
||
$hash->{".retry_opt"},
|
||
@{ $hash->{".retry_args"} }
|
||
);
|
||
} else {
|
||
vitoconnect_getResource($hash);
|
||
}
|
||
}
|
||
else {
|
||
Log3 $name, 1, "$name - Access Token: nicht definiert";
|
||
Log3 $name, 5, "$name - Received response: $response_body\n";
|
||
# zurück zu getCode?
|
||
if ($caller ne 'action') {
|
||
InternalTimer(gettimeofday() + $hash->{intervall}, "vitoconnect_GetUpdate", $hash);
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
else {
|
||
Log3 $name, 1, "$name - getRefresh: An error occured: $err";
|
||
if ($caller ne 'action') {
|
||
InternalTimer(gettimeofday() + $hash->{intervall}, "vitoconnect_GetUpdate", $hash);
|
||
}
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Abfrage Gateway-Serial
|
||
# https://documentation.viessmann.com/static/iot/overview
|
||
#####################################################################################################################
|
||
sub vitoconnect_getGw {
|
||
my ($hash) = @_; # Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
my $access_token = $hash->{".access_token"};
|
||
my $param = {
|
||
url => $iotURL_V1
|
||
."gateways",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer ".$access_token,
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getGwCallback
|
||
};
|
||
HttpUtils_NonblockingGet($param);
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Gateway-Serial speichern, Anwort von Abfrage Gateway-Serial
|
||
#####################################################################################################################
|
||
sub vitoconnect_getGwCallback {
|
||
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
|
||
if ($err eq "") { # kein Fehler aufgetreten
|
||
Log3($name,4,$name." - getGwCallback went ok");
|
||
Log3($name,5,$name." - Received response: ".$response_body."\n");
|
||
my $items = eval {decode_json($response_body)};
|
||
if ($@) { # Fehler beim JSON dekodieren
|
||
readingsSingleUpdate($hash,"state","JSON error while request: ".$@,1); # Reading 'state'
|
||
Log3($name,1,$name.", vitoconnect_getGwCallback: JSON error while request: ".$@);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
$err = vitoconnect_errorHandling($hash,$items);
|
||
if ($err ==1){
|
||
return;
|
||
}
|
||
|
||
if ($hash->{".logResponseOnce"} ) {
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $file = $dir->child("gw.json");
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($items)); # Datei 'gw.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
}
|
||
|
||
# Alle Gateways holen und in hash schreiben, immer machen falls neue Geräte hinzu kommen
|
||
my %devices;
|
||
|
||
# Über jedes Gateway-Element in der JSON-Datenstruktur iterieren
|
||
foreach my $gateway (@{$items->{data}}) {
|
||
if (defined $gateway->{serial} && defined $gateway->{installationId}) {
|
||
$devices{$gateway->{serial}} = {
|
||
installationId => $gateway->{installationId},
|
||
gatewayType => $gateway->{gatewayType},
|
||
version => $gateway->{version}
|
||
};
|
||
}
|
||
}
|
||
|
||
$hash->{devices} = { %devices };
|
||
|
||
if ( defined(AttrVal( $name, 'vitoconnect_installationID', 0 ))
|
||
&& AttrVal( $name, 'vitoconnect_installationID', 0 ) ne ""
|
||
&& AttrVal( $name, 'vitoconnect_installationID', 0 ) != 0
|
||
&& defined(AttrVal( $name, 'vitoconnect_serial', 0 ))
|
||
&& AttrVal( $name, 'vitoconnect_serial', 0 ) ne ""
|
||
&& AttrVal( $name, 'vitoconnect_serial', 0 ) != 0 ) {
|
||
# Attribute sind gesetzt, nichts zu tun
|
||
Log3($name,5,$name." - getGW all atributes set already attr: instID: ".AttrVal( $name, 'vitoconnect_installationID', 0 ).
|
||
", serial: ".AttrVal( $name, 'vitoconnect_serial', 0 ));
|
||
} else
|
||
{
|
||
# Prüfungen der Gateways und weiteres vorgehen
|
||
my $num_devices = scalar keys %devices;
|
||
|
||
if ($num_devices == 0) {
|
||
readingsSingleUpdate($hash,"state","Keine Gateways/Devices gefunden, Account prüfen",1);
|
||
return;
|
||
} elsif ($num_devices == 1) {
|
||
readingsSingleUpdate($hash,"state","Genau ein Gateway/Device gefunden",1);
|
||
|
||
my ($serial) = keys %devices;
|
||
my $installationId = $devices{$serial}->{installationId};
|
||
Log3($name,4,$name." - getGW exactly one Device found set attr: instID: $installationId, serial $serial");
|
||
my $result;
|
||
$result = CommandAttr (undef, "$name vitoconnect_installationID $installationId");
|
||
if ($result) {
|
||
Log3($name, 1, "Error setting vitoconnect_installationID: $result");
|
||
return;
|
||
}
|
||
$result = CommandAttr (undef, "$name vitoconnect_serial $serial");
|
||
if ($result) {
|
||
Log3($name, 1, "Error setting vitoconnect_serial: $result");
|
||
return;
|
||
}
|
||
Log3($name, 4, "Successfully set vitoconnect_serial and vitoconnect_installationID attributes for $name");
|
||
} else {
|
||
readingsSingleUpdate($hash,"state","Mehrere Gateways/Devices gefunden, bitte eines auswählen über selectDevice",1);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (AttrVal( $name, 'vitoconnect_gw_readings', 0 ) eq "1") {
|
||
readingsSingleUpdate($hash,"gw",$response_body,1); # im Reading 'gw' merken
|
||
readingsSingleUpdate($hash,"number_of_gateways",scalar keys %devices,1);
|
||
}
|
||
|
||
# Alle Infos besorgt, rest nur für logResponceOnce
|
||
if ($hash->{".logResponseOnce"} ) {
|
||
vitoconnect_getInstallation($hash);
|
||
vitoconnect_getInstallationFeatures($hash);
|
||
} else {
|
||
vitoconnect_getResource($hash);
|
||
}
|
||
}
|
||
else { # Fehler aufgetreten
|
||
Log3($name,1,$name." - An error occured: ".$err);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Abfrage Install-ID
|
||
# https://documentation.viessmann.com/static/iot/overview
|
||
#####################################################################################################################
|
||
sub vitoconnect_getInstallation {
|
||
my ($hash) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $access_token = $hash->{".access_token"};
|
||
my $param = {
|
||
url => $iotURL_V1
|
||
."installations",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer ".$access_token,
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getInstallationCallback
|
||
};
|
||
HttpUtils_NonblockingGet($param);
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Install-ID speichern, Antwort von Abfrage Install-ID
|
||
#####################################################################################################################
|
||
sub vitoconnect_getInstallationCallback {
|
||
my ( $param, $err, $response_body ) = @_;
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
if ($err eq "") {
|
||
Log3 $name, 4, "$name - getInstallationCallback went ok";
|
||
Log3 $name, 5, "$name - Received response: $response_body";
|
||
my $items = eval { decode_json($response_body) };
|
||
if ($@) {
|
||
readingsSingleUpdate( $hash, "state","JSON error while request: ".$@,1);
|
||
Log3($name,1,$name.", vitoconnect_getInstallationCallback: JSON error while request: ".$@);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
if ($hash->{".logResponseOnce"}) {
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $file = $dir->child("installation_" . $gw . ".json");
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($items)); # Datei 'installation.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
}
|
||
|
||
if (AttrVal( $name, 'vitoconnect_gw_readings', 0 ) eq "1") {
|
||
readingsSingleUpdate( $hash, "installation", $response_body, 1 );
|
||
}
|
||
|
||
vitoconnect_getDevice($hash);
|
||
|
||
}
|
||
else {
|
||
Log3 $name, 1, "$name - An error occured: $err";
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Abfrage von Install-features speichern
|
||
#####################################################################################################################
|
||
sub vitoconnect_getInstallationFeatures {
|
||
my ($hash) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $access_token = $hash->{".access_token"};
|
||
my $installation = AttrVal( $name, 'vitoconnect_installationID', 0 );
|
||
|
||
|
||
# installation features #Fixme call only once
|
||
my $param = {
|
||
url => $iotURL_V2
|
||
."installations/".$installation."/features",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer ".$access_token,
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getInstallationFeaturesCallback
|
||
};
|
||
|
||
HttpUtils_NonblockingGet($param);
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
#Install-features speichern
|
||
#####################################################################################################################
|
||
sub vitoconnect_getInstallationFeaturesCallback {
|
||
my ( $param, $err, $response_body ) = @_;
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
my $decode_json = eval {decode_json($response_body)};
|
||
if ((defined($err) && $err ne "") || (defined($decode_json->{statusCode}) && $decode_json->{statusCode} ne "")) { # Fehler aufgetreten
|
||
Log3($name,1,$name.",vitoconnect_getFeatures: Fehler während installation features: ".$err." :: ".$response_body);
|
||
$err = vitoconnect_errorHandling($hash,$decode_json);
|
||
if ($err ==1){
|
||
return;
|
||
}
|
||
}
|
||
else { # kein Fehler aufgetreten
|
||
|
||
if ($hash->{".logResponseOnce"}) {
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $file = $dir->child("installation_features_" . $gw . ".json");
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($decode_json)); # Datei 'installation.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
}
|
||
|
||
if (AttrVal( $name, 'vitoconnect_gw_readings', 0 ) eq "1") {
|
||
readingsSingleUpdate($hash,"installation_features",$response_body,1); # im Reading 'installation_features' merken
|
||
}
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Abfrage Device-ID
|
||
#####################################################################################################################
|
||
sub vitoconnect_getDevice {
|
||
my ($hash) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $access_token = $hash->{".access_token"};
|
||
my $installation = AttrVal( $name, 'vitoconnect_installationID', 0 );
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
Log(5,$name.", --getDevice gw for call set: ".$gw);
|
||
|
||
my $param = {
|
||
url => $iotURL_V1
|
||
."installations/".$installation."/gateways/".$gw."/devices",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer ".$access_token,
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getDeviceCallback
|
||
};
|
||
HttpUtils_NonblockingGet($param);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Device-ID speichern, Anwort von Abfrage Device-ID
|
||
#####################################################################################################################
|
||
sub vitoconnect_getDeviceCallback {
|
||
my ( $param, $err, $response_body ) = @_;
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
Log(5,$name.", -getDeviceCallback get device gw: ".$gw);
|
||
if ($err eq "") {
|
||
Log3 $name, 4, "$name - getDeviceCallback went ok";
|
||
Log3 $name, 5, "$name - Received response: $response_body\n";
|
||
my $items = eval { decode_json($response_body) };
|
||
if ($@) {
|
||
RemoveInternalTimer($hash);
|
||
readingsSingleUpdate($hash,"state","JSON error while request: ".$@,1);
|
||
Log3($name,1,$name.", vitoconnect_getDeviceCallback: JSON error while request: ".$@);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
if ( $hash->{".logResponseOnce"} ) {
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $filename = "device_" . $gw . ".json";
|
||
my $file = $dir->child($filename);
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($items)); # Datei 'device.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
}
|
||
if (AttrVal( $name, 'vitoconnect_gw_readings', 0 ) eq "1") {
|
||
readingsSingleUpdate($hash,"device",$response_body,1); # im Reading 'device' merken
|
||
}
|
||
vitoconnect_getFeatures($hash);
|
||
}
|
||
else {
|
||
if ((defined($err) && $err ne "")) { # Fehler aufgetreten
|
||
Log3($name,1,$name." - An error occured: ".$err);
|
||
} else {
|
||
Log3($name,1,$name." - An undefined error occured");
|
||
}
|
||
RemoveInternalTimer($hash);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Abruf GW Features, Anwort von Abfrage Device-ID
|
||
# https://documentation.viessmann.com/static/iot/overview
|
||
#####################################################################################################################
|
||
sub vitoconnect_getFeatures {
|
||
my ($hash) = shift; # Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
my $access_token = $hash->{".access_token"};
|
||
my $installation = AttrVal( $name, 'vitoconnect_installationID', 0 );
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
my $dev = AttrVal($name,'vitoconnect_device',0); # Attribut: vitoconnect_device (0,1), Standard: 0
|
||
|
||
Log3($name,4,$name." - getFeatures went ok");
|
||
|
||
# Gateway features
|
||
my $param = {
|
||
url => $iotURL_V2
|
||
."installations/".$installation."/gateways/".$gw."/features",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer ".$access_token,
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getFeaturesCallback
|
||
};
|
||
|
||
HttpUtils_NonblockingGet($param);
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# GW Features speichern
|
||
# https://documentation.viessmann.com/static/iot/overview
|
||
#####################################################################################################################
|
||
sub vitoconnect_getFeaturesCallback {
|
||
my ( $param, $err, $response_body ) = @_;
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
my $decode_json = eval {decode_json($response_body)};
|
||
|
||
if ((defined($err) && $err ne "") || (defined($decode_json->{statusCode}) && $decode_json->{statusCode} ne "")) { # Fehler aufgetreten
|
||
Log3($name,1,$name.",vitoconnect_getFeatures: Fehler während Gateway features: ".$err." :: ".$response_body);
|
||
$err = vitoconnect_errorHandling($hash,$decode_json);
|
||
if ($err ==1){
|
||
return;
|
||
}
|
||
}
|
||
else { # kein Fehler aufgetreten
|
||
|
||
if ($hash->{".logResponseOnce"}) {
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $file = $dir->child("gw_features_" . $gw . ".json");
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($decode_json)); # Datei 'installation.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
}
|
||
|
||
if (AttrVal( $name, 'vitoconnect_gw_readings', 0 ) eq "1") {
|
||
readingsSingleUpdate($hash,"gw_features",$response_body,1); # im Reading 'gw_features' merken
|
||
}
|
||
vitoconnect_getResource($hash);
|
||
}
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Get der Daten vom Gateway
|
||
# Hier für den normalen Update
|
||
# Es wird im Sub entschieden ob für alle Gateways oder für eine vorgegeben Gateway Serial
|
||
#####################################################################################################################
|
||
sub vitoconnect_getResource {
|
||
my ($hash) = shift; # Übergabe-Parameter
|
||
my $name = $hash->{NAME}; # Device-Name
|
||
my $access_token = $hash->{".access_token"};
|
||
my $installation = AttrVal( $name, 'vitoconnect_installationID', 0 );
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
my $dev = AttrVal($name,'vitoconnect_device',0);
|
||
|
||
Log3($name,4,$name." - enter getResourceOnce");
|
||
Log3($name,4,$name." - access_token: ".substr($access_token,0,20)."...");
|
||
Log3($name,4,$name." - installation: ".$installation);
|
||
Log3($name,4,$name." - gw: ".$gw);
|
||
if ($access_token eq "" || $installation eq "" || $gw eq "") { # noch kein: Token, ID, GW
|
||
RemoveInternalTimer($hash);
|
||
vitoconnect_getCode($hash);
|
||
return;
|
||
}
|
||
my $param = {
|
||
url => $iotURL_V2
|
||
."installations/".$installation."/gateways/".$gw."/devices/".$dev."/features",
|
||
hash => $hash,
|
||
gw => $gw,
|
||
header => "Authorization: Bearer $access_token",
|
||
timeout => $hash->{timeout},
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
callback => \&vitoconnect_getResourceCallback
|
||
};
|
||
HttpUtils_NonblockingGet($param); # non-blocking aufrufen --> Antwort an: vitoconnect_getResourceCallback
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Verarbeiten der Daten vom Gateway und schreiben in Readings
|
||
# Entweder statisch gemapped oder über attribute mapping gemapped oder nur raw Werte
|
||
# Wenn gemapped wird wird für alle Treffer des Mappings kein raw Wert mehr aktualisiert
|
||
#####################################################################################################################
|
||
sub vitoconnect_getResourceCallback {
|
||
my ($param,$err,$response_body) = @_; # Übergabe-Parameter
|
||
my $hash = $param->{hash};
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
my @days = qw(mon tue wed thu fri sat sun); # Reihenfolge der Wochentage festlegen für type Schedule
|
||
|
||
Log(5,$name.", -getResourceCallback started");
|
||
Log3($name,5,$name." getResourceCallback calles with gw:".$gw);
|
||
|
||
if ($err eq "") { # kein Fehler aufgetreten
|
||
Log3($name,4,$name." - getResourceCallback went ok");
|
||
Log3($name,5,$name." - Received response: ".substr($response_body,0,100)."...");
|
||
my $items = eval {decode_json($response_body)};
|
||
if ($@) { # Fehler beim JSON dekodieren
|
||
readingsSingleUpdate($hash,"state","JSON error while request: ".$@,1); # Reading 'state'
|
||
Log3($name,1,$name.", vitoconnect_getResourceCallback: JSON error while request: ".$@);
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return;
|
||
}
|
||
|
||
$err = vitoconnect_errorHandling($hash,$items);
|
||
if ($err ==1){
|
||
return;
|
||
}
|
||
|
||
if ($hash->{".logResponseOnce"} ) {
|
||
my $dir = path(AttrVal("global","logdir","log")); # Verzeichnis
|
||
my $file = $dir->child("resource_".$gw.".json"); # Dateiname
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($response_body)); # Datei 'resource.json' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
$hash->{".logResponseOnce"} = 0;
|
||
}
|
||
|
||
$hash->{".response_$gw"} = $response_body;
|
||
|
||
Log(5,$name.", translations count:".scalar keys %translations);
|
||
Log(5,$name.", RequestListMapping count:".scalar keys %$RequestListMapping);
|
||
|
||
readingsBeginUpdate($hash);
|
||
foreach ( @{ $items->{data} } ) {
|
||
my $feature = $_;
|
||
my $properties = $feature->{properties};
|
||
|
||
|
||
if (AttrVal( $name, 'vitoconnect_actions_active', 0 ) eq "1") {
|
||
# Write all commands
|
||
if (exists $feature->{commands}) {
|
||
foreach my $command (keys %{$feature->{commands}}) {
|
||
my $Reading = $feature->{feature}.".".$command;
|
||
my $Value = $feature->{commands}{$command}{uri};
|
||
readingsBulkUpdate($hash,$Reading,$Value,1);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
foreach my $key ( sort keys %$properties ) {
|
||
|
||
|
||
my $Reading = "";
|
||
|
||
if ( scalar keys %translations > 0) {
|
||
|
||
# Use translation from attr
|
||
my @parts = split(/\./, $feature->{feature} . "." . $key);
|
||
foreach my $part (@parts) {
|
||
if ($part !~ /\d+/) {
|
||
$part = $translations{$part} // $part; # Übersetze den Teil oder behalte ihn bei
|
||
}
|
||
}
|
||
|
||
$Reading = join('.', @parts);
|
||
|
||
}
|
||
elsif ( scalar keys %$RequestListMapping > 0) {
|
||
# Use RequestListMapping from Attr
|
||
$Reading =
|
||
$RequestListMapping->{ $feature->{feature} . "." . $key };
|
||
}
|
||
elsif (AttrVal( $name, 'vitoconnect_mapping_roger', 0 ) eq "1") {
|
||
# Use build in Mapping Roger (old way)
|
||
$Reading = $RequestListRoger->{ $feature->{feature} . "." . $key };
|
||
}
|
||
else {
|
||
# Use build in Mapping SVN (old way)
|
||
$Reading = $RequestListSvn->{ $feature->{feature} . "." . $key };
|
||
};
|
||
|
||
if ( !defined($Reading) || AttrVal( $name, 'vitoconnect_raw_readings', 0 ) eq "1" )
|
||
{
|
||
$Reading = $feature->{feature} . "." . $key;
|
||
}
|
||
|
||
if ( !defined($Reading) && AttrVal( $name, 'vitoconnect_disable_raw_readings', 0 ) eq "1" )
|
||
{
|
||
next;
|
||
}
|
||
|
||
my $Type = $properties->{$key}->{type};
|
||
my $Value = $properties->{$key}->{value};
|
||
$Value =~ s/\x{FFFD}+/[VUC]/g; # Ersetze aufeinanderfolgende Vorkommen von U+FFFD durch "unknown characters" siehe https://forum.fhem.de/index.php?msg=1334504
|
||
#$Value =~ s/[^[:print:]]+//g; # Behalte alle druckbaren Zeichen
|
||
my $comma_separated_string = "";
|
||
if ( $Type eq "array" ) {
|
||
if ( defined($Value) ) {
|
||
if (ref($Value->[0]) eq 'HASH') {
|
||
foreach my $entry (@$Value) {
|
||
foreach my $hash_key (sort keys %$entry) {
|
||
if ($hash_key ne "audiences") {
|
||
my $hash_value = $entry->{$hash_key};
|
||
if (ref($hash_value) eq 'ARRAY') {
|
||
$comma_separated_string .= join(", ", @$hash_value) . ", ";
|
||
} else {
|
||
$comma_separated_string .= $hash_value . ", ";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
# Entferne das letzte Komma und Leerzeichen
|
||
$comma_separated_string =~ s/, $//;
|
||
readingsBulkUpdate($hash,$Reading,$comma_separated_string);
|
||
}
|
||
elsif (ref($Value) eq 'ARRAY') {
|
||
$comma_separated_string = ( join(",",@$Value) );
|
||
readingsBulkUpdate($hash,$Reading,$comma_separated_string);
|
||
Log3($name,5,$name." - ".$Reading." ".$comma_separated_string." (".$Type.")");
|
||
}
|
||
else {
|
||
Log3($name,4,$name." - Array Workaround for Property: ".$Reading);
|
||
}
|
||
}
|
||
}
|
||
elsif ($Type eq 'object') {
|
||
# Iteriere durch die Schlüssel des Hashes
|
||
foreach my $hash_key (sort keys %$Value) {
|
||
my $hash_value = $Value->{$hash_key};
|
||
$comma_separated_string .= $hash_value . ", ";
|
||
}
|
||
# Entferne das letzte Komma und Leerzeichen
|
||
$comma_separated_string =~ s/, $//;
|
||
readingsBulkUpdate($hash,$Reading,$comma_separated_string);
|
||
}
|
||
elsif ( $Type eq "Schedule" ) {
|
||
my @schedule;
|
||
foreach my $day (@days) {
|
||
if (exists $Value->{$day}) {
|
||
foreach my $entry (@{$Value->{$day}}) {
|
||
my $ordered_entry = sprintf('{"mode":"%s","start":"%s","end":"%s","position":%d}',
|
||
$entry->{mode}, $entry->{start}, $entry->{end}, $entry->{position}
|
||
);
|
||
push @schedule, sprintf('{"%s":%s}', $day, $ordered_entry);
|
||
}
|
||
}
|
||
}
|
||
my $Result = '[' . join(',', @schedule) . ']';
|
||
readingsBulkUpdate($hash, $Reading, $Result);
|
||
Log3($name, 5, "$name - $Reading: $Result ($Type)");
|
||
}
|
||
else {
|
||
readingsBulkUpdate($hash,$Reading,$Value);
|
||
Log3 $name, 5, "$name - $Reading: $Value ($Type)";
|
||
#Log3 $name, 1, "$name - $Reading: $Value ($Type)";
|
||
}
|
||
|
||
# Store power readings as asSingleValue
|
||
if ($Reading =~ m/dayValueReadAt$/) {
|
||
Log(5,$name.", -call setpower $Reading");
|
||
vitoconnect_getPowerLast ($hash,$name,$Reading);
|
||
}
|
||
|
||
# Get error codes from API
|
||
if ($Reading eq "device.messages.errors.raw.entries") {
|
||
Log(5,$name.", -call getErrorCode $Reading");
|
||
if (defined $comma_separated_string && $comma_separated_string ne '') {
|
||
vitoconnect_getErrorCode ($hash,$name,$comma_separated_string);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
readingsBulkUpdate($hash,"state","last update: ".TimeNow().""); # Reading 'state'
|
||
readingsEndUpdate( $hash, 1 ); # Readings schreiben
|
||
}
|
||
else {
|
||
Log3($name,1,$name." - An error occured: ".$err);
|
||
}
|
||
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
Log(5,$name.", -getResourceCallback ended");
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Implementierung power readings die nur sehr selten kommen in ein logbares reading füllen (asSingleValue)
|
||
#####################################################################################################################
|
||
sub vitoconnect_getPowerLast {
|
||
my ($hash, $name, $Reading) = @_;
|
||
|
||
# entferne alles hinter dem letzten Punkt
|
||
$Reading =~ s/\.[^.]*$//;
|
||
|
||
# Liste der Stromwerte
|
||
my @values = split(",", ReadingsVal($name,$Reading.".day","")); #(1.2, 76.7, 52.6, 40.9, 40.4, 30, 33.9, 75);
|
||
|
||
# Zeitpunkt des ersten Wertes
|
||
my $timestamp = ReadingsVal($name,$Reading.".dayValueReadAt",""); #'2024-11-29T11:28:56.915Z';
|
||
|
||
if (!defined($timestamp)) {
|
||
return;
|
||
}
|
||
|
||
# Datum extrahieren und in ein Time::Piece Objekt umwandeln
|
||
my $date = Time::Piece->strptime(substr($timestamp, 0, 10), '%Y-%m-%d');
|
||
|
||
# Anzahl der Sekunden in einem Tag
|
||
my $one_day = 24 * 60 * 60;
|
||
|
||
# Hash für die Key-Value-Paare
|
||
my %data;
|
||
my $readingLastTimestamp = ReadingsTimestamp($name,$Reading.".day.asSingleValue","0000000000");
|
||
#my $lastTS = "0000000000";
|
||
#if ($readingLastTimestamp ne "") {
|
||
my $lastTS = time_str2num($readingLastTimestamp);
|
||
#}
|
||
Log(5,$name.", -setpower: readinglast: $readingLastTimestamp lastTS $lastTS");
|
||
|
||
# Werte den entsprechenden Tagen zuordnen, start mit 1, letzten Tag ausschließen weil unvollständig
|
||
for (my $i = $#values; $i >= 1; $i--) {
|
||
my $current_date = $date - ($one_day * $i);
|
||
Log3($name, 5, ", -setpower: date:$current_date value:$values[$i] ($i)");
|
||
my $readingDate = $current_date->ymd . " 23:59:59";
|
||
my $readingTS = time_str2num($readingDate);
|
||
Log(5,$name.", -setpower: date $readingDate lastdate $readingLastTimestamp");
|
||
if ($readingTS > $lastTS) {
|
||
readingsBulkUpdate ($hash, $Reading.".day.asSingleValue", $values[$i], undef, $readingDate);
|
||
Log(4,$name.", -setpower: readingsBulkUpdate ($hash, $Reading.day.asSingleValue, $values[$i], undef, $readingDate");
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Error Code auslesesn
|
||
#####################################################################################################################
|
||
sub vitoconnect_getErrorCode {
|
||
my ($hash, $name, $comma_separated_string) = @_;
|
||
#$comma_separated_string = "customer, c2, warning, 2025-02-03T17:25:19.000Z"; # debug
|
||
my $language = AttrVal( 'global', 'language', 0 );
|
||
my %severity_translations = (
|
||
'note' => 'Hinweis',
|
||
'warning' => 'Warnung',
|
||
'error' => 'Fehler',
|
||
'criticalError' => 'kritischer Fehler'
|
||
);
|
||
|
||
if (defined $comma_separated_string && $comma_separated_string ne '') {
|
||
|
||
my $serial = ReadingsVal($name, "device.serial.value", "");
|
||
my $materialNumber = substr($serial, 0, 7); #"7733738"; #debug
|
||
my @values = split(/, /, $comma_separated_string);
|
||
my $Reading = "device.messages.errors.mapped";
|
||
|
||
my $fault_counter = -1;
|
||
my $cause_counter = -1;
|
||
|
||
for (my $i = 0; $i < @values; $i += 4) {
|
||
my $errorCode = $values[$i + 1];
|
||
my $severity = $values[$i + 2];
|
||
if (uc($language) eq 'DE') {
|
||
$severity = $severity_translations{$severity};
|
||
}
|
||
|
||
my $param = {
|
||
url => "$errorURL_V3?materialNumber=$materialNumber&errorCode=$errorCode&countryCode=${\uc($language)}&languageCode=${\lc($language)}",
|
||
hash => $hash,
|
||
timeout => $hash->{timeout}, # Timeout von Internals = 15s
|
||
method => "GET", # Methode auf GET ändern
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
};
|
||
Log3($name, 5, $name . ", vitoconnect_getErrorCode url=" . $param->{url});
|
||
|
||
my ($err, $msg) = HttpUtils_BlockingGet($param);
|
||
my $decode_json = eval { JSON->new->decode($msg) };#decode_json($msg) };
|
||
Log3($name, 5, $name . ", vitoconnect_getErrorCode debug err=$err msg=" . $msg . " json=" . Dumper($decode_json)); # wieder weg
|
||
|
||
if (defined($err) && $err ne "") { # Fehler bei Befehlsausführung
|
||
Log3($name, 1, $name . ", vitoconnect_getErrorCode call finished with error, err:" . $err);
|
||
} elsif (exists $decode_json->{statusCode} && $decode_json->{statusCode} ne "") {
|
||
Log3($name, 1, $name . ", vitoconnect_getErrorCode call finished with error, status code:" . $decode_json->{statusCode});
|
||
} else { # Befehl korrekt ausgeführt
|
||
Log3($name, 5, $name . ", vitoconnect_getErrorCode: finished ok");
|
||
if (exists $decode_json->{faultCodes} && @{$decode_json->{faultCodes}}) {
|
||
foreach my $fault (@{$decode_json->{faultCodes}}) {
|
||
$fault_counter++;
|
||
my $fault_code = $fault->{faultCode};
|
||
my $system_characteristics = $fault->{systemCharacteristics};
|
||
# remove html paragraphs
|
||
$system_characteristics =~ s/<\/?(p|q)>//g;
|
||
readingsBulkUpdate($hash, $Reading . ".$fault_counter.faultCode", $fault_code);
|
||
readingsBulkUpdate($hash, $Reading . ".$fault_counter.severity", $severity);
|
||
readingsBulkUpdate($hash, $Reading . ".$fault_counter.systemCharacteristics", $system_characteristics);
|
||
|
||
foreach my $cause (@{$fault->{causes}}) {
|
||
$cause_counter++;
|
||
my $cause_text = $cause->{cause};
|
||
my $measure = $cause->{measure};
|
||
# remove html paragraphs
|
||
$cause_text =~ s/<\/?(p|q)>//g;
|
||
$measure =~ s/<\/?(p|q)>//g;
|
||
readingsBulkUpdate($hash, $Reading . ".$fault_counter.faultCodes.$cause_counter.cause", $cause_text);
|
||
readingsBulkUpdate($hash, $Reading . ".$fault_counter.faultCodes.$cause_counter.measure", $measure);
|
||
}
|
||
}
|
||
} else {
|
||
Log3($name, 1, $name . ", vitoconnect_getErrorCode no faultcode in json found. json=" . Dumper($decode_json));
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
Log3($name, 1, $name . " , vitoconnect_getErrorCode the variable \$comma_separated_string does not exist or is empty");
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Setzen von Daten über Timer
|
||
#####################################################################################################################
|
||
sub vitoconnect_actionTimerWrapper {
|
||
my ($argRef) = @_;
|
||
|
||
unless (ref($argRef) eq 'ARRAY') {
|
||
my $type = ref($argRef) // 'undef';
|
||
my $name = ref($argRef) eq 'HASH' ? $argRef->{NAME} // 'unknown' : 'unknown';
|
||
Log3($name, 1, "$name - vitoconnect_actionTimerWrapper: Fehlerhafte Argumentübergabe (Typ: $type), erwartet ARRAY-Referenz");
|
||
return;
|
||
}
|
||
|
||
vitoconnect_action(@$argRef);
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Setzen von Daten
|
||
#####################################################################################################################
|
||
sub vitoconnect_action {
|
||
my ($hash, $feature, $data, $name, $opt, @args) = @_;
|
||
return delete $hash->{".action_retry_count"} if IsDisabled($name); # Modul deaktiviert → abbrechen
|
||
|
||
my $access_token = $hash->{".access_token"};
|
||
my $installation = AttrVal($name, 'vitoconnect_installationID', 0);
|
||
my $gw = AttrVal($name, 'vitoconnect_serial', 0);
|
||
my $dev = AttrVal($name, 'vitoconnect_device', 0);
|
||
my $Text = join(' ', @args);
|
||
my $retry_count = $hash->{".action_retry_count"} // 0;
|
||
|
||
my $param = {
|
||
url => $iotURL_V2."installations/$installation/gateways/$gw/devices/$dev/features/$feature",
|
||
hash => $hash,
|
||
header => "Authorization: Bearer $access_token\r\nContent-Type: application/json",
|
||
data => $data,
|
||
timeout => $hash->{timeout},
|
||
method => "POST",
|
||
sslargs => { SSL_verify_mode => 0 },
|
||
};
|
||
|
||
Log3($name,3,$name.", vitoconnect_action url=" .$param->{url}); # change back to 3
|
||
Log3($name,3,$name.", vitoconnect_action data=".$param->{data}); # change back to 3
|
||
# https://wiki.fhem.de/wiki/HttpUtils#HttpUtils_BlockingGet
|
||
my ($err, $msg) = HttpUtils_BlockingGet($param);
|
||
my $decode_json = eval { decode_json($msg) };
|
||
|
||
if ((defined($err) && $err ne "") || (defined($decode_json->{statusCode}) && $decode_json->{statusCode} ne "")) {
|
||
$retry_count++;
|
||
$hash->{".action_retry_count"} = $retry_count;
|
||
readingsSingleUpdate($hash, "Aktion_Status", "Fehler ($retry_count/20): $opt $Text", 1);
|
||
# Log3($name, 2, "$name - RetryLoop Fehler: $err :: $msg");
|
||
Log3($name,1,$name.",vitoconnect_action: set ".$name." ".$opt." ".@args.", Fehler bei Befehlsausfuehrung ($retry_count/20): ".$err." :: ".$msg);
|
||
|
||
# Token abgelaufen?
|
||
if ($decode_json->{statusCode} eq "401" && $decode_json->{error} eq "EXPIRED TOKEN") {
|
||
# Token erneuern, aber ohne getResource
|
||
$hash->{".retry_feature"} = $feature;
|
||
$hash->{".retry_data"} = $data;
|
||
$hash->{".retry_opt"} = $opt;
|
||
$hash->{".retry_args"} = [@args];
|
||
$hash->{".action_retry_count"} = $retry_count;
|
||
vitoconnect_getRefresh($hash, 'action'); # Kontext 'action' → kein getResource
|
||
return;
|
||
}
|
||
|
||
# Wiederholen in 10 Sekunden
|
||
if ($retry_count < 20) {
|
||
InternalTimer(gettimeofday() + 10, "vitoconnect_actionTimerWrapper", [$hash, $feature, $data, $name, $opt, @args]);
|
||
} else {
|
||
Log3($name, 1, "$name - vitoconnect_action: Abbruch nach 20 Fehlversuchen");
|
||
readingsSingleUpdate($hash, "Aktion_Status", "Fehlgeschlagen: $opt $Text (nach 20 Versuchen)", 1);
|
||
# Abbruch nach 20 versuchen → Retry-Zähler und Daten zurücksetzen
|
||
delete $hash->{".action_retry_count"};
|
||
delete $hash->{".retry_feature"};
|
||
delete $hash->{".retry_data"};
|
||
delete $hash->{".retry_opt"};
|
||
delete $hash->{".retry_args"};
|
||
}
|
||
return;
|
||
}
|
||
|
||
readingsSingleUpdate($hash,"Aktion_Status","OK: ".$opt." ".$Text,1); # Reading 'Aktion_Status' setzen
|
||
#Log3($name,1,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt: ".$err." :: ".$msg); # TODO: Wieder weg machen $err
|
||
Log3($name,3,$name.",vitoconnect_action: set name:".$name." opt:".$opt." text:".$Text.", korrekt ausgefuehrt");
|
||
|
||
# Spezial Readings update
|
||
if ($opt =~ /(.*)\.deactivate/) {
|
||
$opt = $1 . ".active";
|
||
$Text = "0";
|
||
} elsif ($opt =~ /(.*)\.activate/) {
|
||
$opt = $1 . ".active";
|
||
$Text = "1";
|
||
}
|
||
readingsSingleUpdate($hash,$opt,$Text,1); # Reading updaten
|
||
#Log3($name,1,$name.",vitoconnect_action: reading upd1 hash:".$hash." opt:".$opt." text:".$Text); # TODO: Wieder weg machen $err
|
||
|
||
# Spezial Readings update, activate mit temperatur siehe brenner Vitoladens300C
|
||
if ($feature =~ /(.*)\.deactivate/) {
|
||
# funktioniert da deactivate ohne temperatur gesendet wird
|
||
} elsif ($feature =~ /(.*)\/commands\/activate/) {
|
||
$opt = $1 . ".active";
|
||
$Text = "1";
|
||
}
|
||
readingsSingleUpdate($hash,$opt,$Text,1); # Reading updaten
|
||
#Log3($name,1,$name.",vitoconnect_action: reading upd2 hash:".$hash." opt:".$opt." text:".$Text); # TODO: Wieder weg machen $err
|
||
|
||
|
||
Log3($name,4,$name.",vitoconnect_action: set feature:".$feature." data:".$data.", korrekt ausgefuehrt"); #4
|
||
|
||
# Erfolg → Retry-Zähler und Daten zurücksetzen
|
||
delete $hash->{".action_retry_count"};
|
||
delete $hash->{".retry_feature"};
|
||
delete $hash->{".retry_data"};
|
||
delete $hash->{".retry_opt"};
|
||
delete $hash->{".retry_args"};
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# Errors bearbeiten
|
||
#####################################################################################################################
|
||
sub vitoconnect_errorHandling {
|
||
my ($hash,$items) = @_;
|
||
my $name = $hash->{NAME};
|
||
my $gw = AttrVal( $name, 'vitoconnect_serial', 0 );
|
||
|
||
#Log3 $name, 1, "$name - errorHandling StatusCode: $items->{statusCode} ";
|
||
|
||
if (defined $items->{statusCode} && !$items->{statusCode} eq "") {
|
||
Log3 $name, 4, "$name - statusCode: " . ($items->{statusCode} // 'undef') . " "
|
||
. "errorType: " . ($items->{errorType} // 'undef') . " "
|
||
. "message: " . ($items->{message} // 'undef') . " "
|
||
. "error: " . ($items->{error} // 'undef') . " "
|
||
. "reason: " . ($items->{extendedPayload}->{reason} // 'undef');
|
||
|
||
readingsSingleUpdate(
|
||
$hash,
|
||
"state",
|
||
"statusCode: " . ($items->{statusCode} // 'undef') . " "
|
||
. "errorType: " . ($items->{errorType} // 'undef') . " "
|
||
. "message: " . ($items->{message} // 'undef') . " "
|
||
. "error: " . ($items->{error} // 'undef') . " "
|
||
. "reason: " . ($items->{extendedPayload}->{reason} // 'undef'),
|
||
1
|
||
);
|
||
if ( $items->{statusCode} eq "401" ) {
|
||
# EXPIRED TOKEN
|
||
vitoconnect_getRefresh($hash,'update'); # neuen Access-Token anfragen
|
||
return(1);
|
||
}
|
||
elsif ( $items->{statusCode} eq "404" ) {
|
||
# DEVICE_NOT_FOUND
|
||
readingsSingleUpdate($hash,"state","Device not found: Optolink prüfen!",1);
|
||
Log3 $name, 1, "$name - Device not found: Optolink prüfen!";
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return(1);
|
||
}
|
||
elsif ( $items->{statusCode} eq "429" ) {
|
||
# RATE_LIMIT_EXCEEDED
|
||
readingsSingleUpdate($hash,"state","Anzahl der möglichen API Calls in überschritten!",1);
|
||
Log3 $name, 1,
|
||
"$name - Anzahl der möglichen API Calls in überschritten! Caller Name: $hash->{NAME}, memoryadress: $hash";
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return(1);
|
||
}
|
||
elsif ( $items->{statusCode} eq "502" ) {
|
||
readingsSingleUpdate($hash,"state","temporärer API Fehler",1);
|
||
# DEVICE_COMMUNICATION_ERROR error: Bad Gateway
|
||
Log3 $name, 1, "$name - temporärer API Fehler";
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return(1);
|
||
}
|
||
else {
|
||
readingsSingleUpdate($hash,"state","unbekannter Fehler, bitte den Entwickler informieren! (Typ: "
|
||
. ($items->{errorType} // 'undef') . " Grund: "
|
||
. ($items->{extendedPayload}->{reason} // 'NA') . ")",1);
|
||
Log3 $name, 1, "$name - unbekannter Fehler: "
|
||
. "Bitte den Entwickler informieren!";
|
||
Log3 $name, 1, "$name - statusCode: " . ($items->{statusCode} // 'undef') . " "
|
||
. "errorType: " . ($items->{errorType} // 'undef') . " "
|
||
. "message: " . ($items->{message} // 'undef') . " "
|
||
. "error: " . ($items->{error} // 'undef') . " "
|
||
. "reason: " . ($items->{extendedPayload}->{reason} // 'undef');
|
||
|
||
my $dir = path( AttrVal("global","logdir","log"));
|
||
my $file = $dir->child("vitoconnect_" . $gw . ".err");
|
||
my $file_handle = $file->openw_utf8();
|
||
$file_handle->print(Dumper($items)); # Datei 'vitoconnect_serial.err' schreiben
|
||
$file_handle->close();
|
||
Log3($name,3,$name." Datei: ".$dir."/".$file." geschrieben");
|
||
|
||
InternalTimer(gettimeofday() + $hash->{intervall},"vitoconnect_GetUpdate",$hash);
|
||
return(1);
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
#####################################################################################################################
|
||
# Werte verschlüsselt speichern
|
||
#####################################################################################################################
|
||
sub vitoconnect_StoreKeyValue {
|
||
# checks and stores obfuscated keys like passwords
|
||
# based on / copied from FRITZBOX_storePassword
|
||
my ( $hash, $kName, $value ) = @_;
|
||
my $index = $hash->{TYPE}."_".$hash->{NAME}."_".$kName;
|
||
my $key = getUniqueId().$index;
|
||
my $enc = "";
|
||
|
||
if ( eval "use Digest::MD5;1" ) {
|
||
$key = Digest::MD5::md5_hex( unpack "H*", $key );
|
||
$key .= Digest::MD5::md5_hex($key);
|
||
}
|
||
for my $char ( split //, $value ) {
|
||
my $encode = chop($key);
|
||
$enc .= sprintf( "%.2x", ord($char) ^ ord($encode) );
|
||
$key = $encode . $key;
|
||
}
|
||
my $err = setKeyValue( $index, $enc ); # Die Funktion setKeyValue() speichert die Daten $value unter dem Schlüssel $key ab.
|
||
return "error while saving the value - ".$err if ( defined($err) ); # Fehler
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# verschlüsselte Werte auslesen
|
||
#####################################################################################################################
|
||
sub vitoconnect_ReadKeyValue {
|
||
|
||
# reads obfuscated value
|
||
|
||
my ($hash,$kName) = @_; # Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
|
||
my $index = $hash->{TYPE}."_".$hash->{NAME}."_".$kName;
|
||
my $key = getUniqueId().$index;
|
||
|
||
my ( $value, $err );
|
||
|
||
Log3($name,5,$name." - ReadKeyValue tries to read value for ".$kName." from file");
|
||
($err,$value ) = getKeyValue($index); # Die Funktion getKeyValue() gibt Daten, welche zuvor per setKeyValue() gespeichert wurden, zurück.
|
||
|
||
if ( defined($err) ) { # im Fehlerfall
|
||
Log3($name,1,$name." - ReadKeyValue is unable to read value from file: ".$err);
|
||
return;
|
||
}
|
||
|
||
if ( defined($value) ) {
|
||
if ( eval "use Digest::MD5;1" ) {
|
||
$key = Digest::MD5::md5_hex( unpack "H*", $key );
|
||
$key .= Digest::MD5::md5_hex($key);
|
||
}
|
||
my $dec = '';
|
||
for my $char ( map { pack( 'C', hex($_) ) } ( $value =~ /(..)/g ) ) {
|
||
my $decode = chop($key);
|
||
$dec .= chr( ord($char) ^ ord($decode) );
|
||
$key = $decode . $key;
|
||
}
|
||
return $dec; # Rückgabe dekodierten Wert
|
||
}
|
||
else { # Fehler:
|
||
Log3($name,1,$name." - ReadKeyValue could not find key ".$kName." in file");
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
#####################################################################################################################
|
||
# verschlüsselte Werte löschen
|
||
#####################################################################################################################
|
||
sub vitoconnect_DeleteKeyValue {
|
||
my ($hash,$kName) = @_; # Übergabe-Parameter
|
||
my $name = $hash->{NAME};
|
||
|
||
Log3( $name, 5,$name." - called function Delete()" );
|
||
|
||
my $index = $hash->{TYPE}."_".$hash->{NAME}."_passwd";
|
||
setKeyValue( $index, undef );
|
||
$index = $hash->{TYPE}."_".$hash->{NAME}."_apiKey";
|
||
setKeyValue( $index, undef );
|
||
|
||
return;
|
||
}
|
||
|
||
1;
|
||
|
||
|
||
=pod
|
||
=item device
|
||
=item summary support for Viessmann API
|
||
=item summary_DE Unterstützung für die Viessmann API
|
||
=begin html
|
||
|
||
<a id="vitoconnect"></a>
|
||
<h3>vitoconnect</h3>
|
||
<ul>
|
||
<i>vitoconnect</i> implements a device for the Viessmann API
|
||
<a href="https://www.viessmann.de/de/viessmann-apps/vitoconnect.html">Vitoconnect100</a> or E3 One Base
|
||
based on the investigation of
|
||
<a href="https://github.com/thetrueavatar/Viessmann-Api">thetrueavatar</a>.<br>
|
||
|
||
You need the user and password from the ViCare App account.<br>
|
||
Additionally also an apiKey, see set apiKey.<br>
|
||
|
||
For details, see: <a href="https://wiki.fhem.de/wiki/Vitoconnect">FHEM Wiki (German)</a><br><br>
|
||
|
||
vitoconnect requires the following libraries:
|
||
<ul>
|
||
<li>Path::Tiny</li>
|
||
<li>JSON</li>
|
||
<li>JSON:XS</li>
|
||
<li>DateTime</li>
|
||
</ul>
|
||
|
||
Use <code>sudo apt install libtypes-path-tiny-perl libjson-perl libdatetime-perl</code> or
|
||
install the libraries via CPAN.
|
||
Otherwise, you will get an error message: "cannot load module vitoconnect".
|
||
|
||
<br><br>
|
||
<a id="vitoconnect-define"></a>
|
||
<b>Define</b>
|
||
<ul>
|
||
<code>define <name> vitoconnect <user> <password> <interval></code><br>
|
||
It is a good idea to use a fake password here and set the correct one later because it is
|
||
readable in the detail view of the device.
|
||
<br><br>
|
||
Example:<br>
|
||
<code>define vitoconnect vitoconnect user@mail.xx fakePassword 60</code><br>
|
||
<code>set vitoconnect password correctPassword</code>
|
||
<code>set vitoconnect apiKey Client-ID</code>
|
||
<br><br>
|
||
</ul>
|
||
<br>
|
||
|
||
<a id="vitoconnect-set"></a>
|
||
<b>Set</b><br>
|
||
<ul>
|
||
<a id="vitoconnect-set-update"></a>
|
||
<li><code>update</code><br>
|
||
Update readings immediately.</li>
|
||
<a id="vitoconnect-set-selectDevice"></a>
|
||
<li><code>selectDevice</code><br>
|
||
Has to be used if you have more than one Viessmann Gateway/Device. You have to choose one Viessmann Device per FHEM Device.<br>
|
||
You will be notified in the FHEM device state that you have to execute the set, and the Viessmann devices will be prefilled.<br>
|
||
Selecting one Viessmann device and executing the set will fill the attributes <code>vitoconnect_serial</code> and <code>vitoconnect_installationId</code>.<br>
|
||
If you have only one Viessmann device, this will be done automatically for you.<br>
|
||
You should save the change after initialization or set.
|
||
</li>
|
||
<a id="vitoconnect-set-clearReadings"></a>
|
||
<li><code>clearReadings</code><br>
|
||
Clear all readings immediately.</li>
|
||
<a id="vitoconnect-set-clearMappedErrors"></a>
|
||
<li><code>clearMappedErrors</code><br>
|
||
Clear all mapped errors immediately.</li>
|
||
<a id="vitoconnect-set-password"></a>
|
||
<li><code>password passwd</code><br>
|
||
Store password in the key store.</li>
|
||
<a id="vitoconnect-set-logResponseOnce"></a>
|
||
<li><code>logResponseOnce</code><br>
|
||
Dumps the JSON response of the Viessmann server to <code>entities.json</code>,
|
||
<code>gw.json</code>, and <code>actions.json</code> in the FHEM log directory.
|
||
If you have more than one gateway, the gateway serial is attached to the filenames.</li>
|
||
<a id="vitoconnect-set-apiKey"></a>
|
||
<li><code>apiKey</code><br>
|
||
You need to create an API Key under <a href="https://developer.viessmann-climatesolutions.com/">https://developer.viessmann-climatesolutions.com/</a>.
|
||
Create an account, add a new client (disable Google reCAPTCHA, Redirect URI = <code>http://localhost:4200/</code>).
|
||
Copy the Client ID here as <code>apiKey</code>.</li>
|
||
<li><code>Setters for your device will be available depending on the mapping method you choose with the help of the attributes <code>vitoconnect_raw_readings</code> or <code>vitoconnect_mapping_roger</code>.</code><br>
|
||
New setters are used if <code>vitoconnect_raw_readings = 1</code>.
|
||
The default is the static mapping of the old SVN version.
|
||
For this, the following setters are available:</li>
|
||
<li><code>HKn_Heizkurve_Niveau shift</code><br>
|
||
Set shift of heating curve for HKn.</li>
|
||
<li><code>HKn_Heizkurve_Steigung slope</code><br>
|
||
Set slope of heating curve for HKn.</li>
|
||
<li><code>HKn_Urlaub_Start_Zeit start</code><br>
|
||
Set holiday start time for HKn.<br>
|
||
<code>start</code> has to look like this: <code>2019-02-02</code>.</li>
|
||
<li><code>HKn_Urlaub_Ende_Zeit end</code><br>
|
||
Set holiday end time for HKn.<br>
|
||
<code>end</code> has to look like this: <code>2019-02-16</code>.</li>
|
||
<li><code>HKn_Urlaub_stop</code> <br>
|
||
Remove holiday start and end time for HKn.</li>
|
||
<li><code>HKn_Zeitsteuerung_Heizung schedule</code><br>
|
||
Sets the heating schedule for HKn in JSON format.<br>
|
||
Example: <code>{"mon":[],"tue":[],"wed":[],"thu":[],"fri":[],"sat":[],"sun":[]}</code> is completely off,
|
||
and <code>{"mon":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"tue":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"wed":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"thu":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"fri":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"sat":[{"mode":"on","start":"00:00","end":"24:00","position":0}],
|
||
"sun":[{"mode":"on","start":"00:00","end":"24:00","position":0}]}</code> is on 24/7.</li>
|
||
<li><code>HKn_Betriebsart heating,standby</code> <br>
|
||
Sets <code>HKn_Betriebsart</code> to <code>heating</code> or <code>standby</code>.</li>
|
||
<li><code>WW_Betriebsart balanced,off</code> <br>
|
||
Sets <code>WW_Betriebsart</code> to <code>balanced</code> or <code>off</code>.</li>
|
||
<li><code>HKn_Soll_Temp_comfort_aktiv activate,deactivate</code> <br>
|
||
Activate/deactivate comfort temperature for HKn.</li>
|
||
<li><code>HKn_Soll_Temp_comfort targetTemperature</code><br>
|
||
Set comfort target temperature for HKn.</li>
|
||
<li><code>HKn_Soll_Temp_eco_aktiv activate,deactivate</code><br>
|
||
Activate/deactivate eco temperature for HKn.</li>
|
||
<li><code>HKn_Soll_Temp_normal targetTemperature</code><br>
|
||
Sets the normal target temperature for HKn, where <code>targetTemperature</code> is an
|
||
integer between 3 and 37.</li>
|
||
<li><code>HKn_Soll_Temp_reduziert targetTemperature</code><br>
|
||
Sets the reduced target temperature for HKn, where <code>targetTemperature</code> is an
|
||
integer between 3 and 37.</li>
|
||
<li><code>HKn_Name name</code><br>
|
||
Sets the name of the circuit for HKn.</li>
|
||
<li><code>WW_einmaliges_Aufladen activate,deactivate</code><br>
|
||
Activate or deactivate one-time charge for hot water.</li>
|
||
<li><code>WW_Zirkulationspumpe_Zeitplan schedule</code><br>
|
||
Sets the schedule in JSON format for the hot water circulation pump.</li>
|
||
<li><code>WW_Zeitplan schedule</code> <br>
|
||
Sets the schedule in JSON format for hot water.</li>
|
||
<li><code>WW_Solltemperatur targetTemperature</code><br>
|
||
<code>targetTemperature</code> is an integer between 10 and 60.<br>
|
||
Sets hot water temperature to <code>targetTemperature</code>.</li>
|
||
<li><code>Urlaub_Start_Zeit start</code><br>
|
||
Set holiday start time.<br>
|
||
<code>start</code> has to look like this: <code>2019-02-02</code>.</li>
|
||
<li><code>Urlaub_Ende_Zeit end</code><br>
|
||
Set holiday end time.<br>
|
||
<code>end</code> has to look like this: <code>2019-02-16</code>.</li>
|
||
<li><code>Urlaub_stop</code> <br>
|
||
Remove holiday start and end time.</li>
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="vitoconnectget"></a>
|
||
<b>Get</b><br>
|
||
<ul>
|
||
Nothing to get here.
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="vitoconnect-attr"></a>
|
||
<b>Attributes</b>
|
||
<ul>
|
||
<code>attr <name> <attribute> <value></code>
|
||
<br><br>
|
||
See <a href="http://fhem.de/commandref.html#attr">commandref#attr</a> for more info about the <code>attr</code> command.
|
||
<br><br>
|
||
Attributes:
|
||
<ul>
|
||
<a id="vitoconnect-attr-disable"></a>
|
||
<li><i>disable</i>:<br>
|
||
Stop communication with the Viessmann server.
|
||
</li>
|
||
<a id="vitoconnect-attr-verbose"></a>
|
||
<li><i>verbose</i>:<br>
|
||
Set the verbosity level.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_raw_readings"></a>
|
||
<li><i>vitoconnect_raw_readings</i>:<br>
|
||
Create readings with plain JSON names like <code>heating.circuits.0.heating.curve.slope</code> instead of German identifiers (old mapping), mapping attribute, or translation attribute.<br>
|
||
When using raw readings, setters will be created dynamically matching the raw readings (new).<br>
|
||
I recommend this setting since you get everything as dynamically as possible from the API.<br>
|
||
You can use <code>stateFormat</code> or <code>userReadings</code> to display your important readings with a readable name.<br>
|
||
If <code>vitoconnect_raw_readings</code> is set, no mapping will be used.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_disable_raw_readings"></a>
|
||
<li><i>vitoconnect_disable_raw_readings</i>:<br>
|
||
This setting will disable the additional generation of raw readings.<br>
|
||
This means you will only see the readings that are explicitly mapped in your chosen mapping.<br>
|
||
This setting will not be active if you also choose <code>vitoconnect_raw_readings = 1</code>.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_gw_readings"></a>
|
||
<li><i>vitoconnect_gw_readings</i>:<br>
|
||
Create readings from the gateway, including information if you have more than one gateway.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_actions_active"></a>
|
||
<li><i>vitoconnect_actions_active</i>:<br>
|
||
Create readings for actions, e.g., <code>heating.circuits.0.heating.curve.setCurve.setURI</code>.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_mappings"></a>
|
||
<li><i>vitoconnect_mappings</i>:<br>
|
||
Define your own mapping of key-value pairs instead of using the built-in ones. The format has to be:<br>
|
||
<code>mapping<br>
|
||
{ 'device.serial.value' => 'device_serial',<br>
|
||
'heating.boiler.sensors.temperature.main.status' => 'status',<br>
|
||
'heating.boiler.sensors.temperature.main.value' => 'haupt_temperatur'}</code><br>
|
||
Mapping will be preferred over the old mapping.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_translations"></a>
|
||
<li><i>vitoconnect_translations</i>:<br>
|
||
Define your own translation; it will translate every word part by part. The format has to be:<br>
|
||
<code>translation<br>
|
||
{ 'device' => 'gerät',<br>
|
||
'messages' => 'nachrichten',<br>
|
||
'errors' => 'fehler'}</code><br>
|
||
Translation will be preferred over mapping and old mapping.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_mapping_roger"></a>
|
||
<li><i>vitoconnect_mapping_roger</i>:<br>
|
||
Use the mapping from Roger from 8. November (<a href="https://forum.fhem.de/index.php?msg=1292441">https://forum.fhem.de/index.php?msg=1292441</a>) instead of the SVN mapping.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_serial"></a>
|
||
<li><i>vitoconnect_serial</i>:<br>
|
||
This handling will now take place during the initialization of the FHEM device.<br>
|
||
You will be notified that you have to execute <code>set <name> selectDevice <serial></code>.<br>
|
||
The possible serials will be prefilled.<br>
|
||
You do not need to set this attribute manually.<br>
|
||
Defines the serial of the Viessmann device to be used.<br>
|
||
If there is only one Viessmann device, you do not have to care about it.<br>
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_installationID"></a>
|
||
<li><i>vitoconnect_installationID</i>:<br>
|
||
This handling will now take place during the initialization of the FHEM device.<br>
|
||
You will be notified that you have to execute <code>set <name> selectDevice <serial></code>.<br>
|
||
The possible serials will be prefilled.<br>
|
||
You do not need to set this attribute manually.<br>
|
||
Defines the installationID of the Viessmann device to be used.<br>
|
||
If there is only one Viessmann device, you do not have to care about it.<br>
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_timeout"></a>
|
||
<li><i>vitoconnect_timeout</i>:<br>
|
||
Sets a timeout for the API call.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_device"></a>
|
||
<li><i>vitoconnect_device</i>:<br>
|
||
You can define the device 0 (default) or 1. I cannot test this because I have only one device.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
|
||
=end html
|
||
=begin html_DE
|
||
|
||
<a id="vitoconnect"></a>
|
||
<h3>vitoconnect</h3>
|
||
<ul>
|
||
<i>vitoconnect</i> implementiert ein Gerät für die Viessmann API
|
||
<a href="https://www.viessmann.de/de/viessmann-apps/vitoconnect.html">Vitoconnect100</a> oder E3 One Base,
|
||
basierend auf der Untersuchung von
|
||
<a href="https://github.com/thetrueavatar/Viessmann-Api">thetrueavatar</a><br>
|
||
|
||
Es werden Benutzername und Passwort des ViCare App-Kontos benötigt.<br>
|
||
Zusätzlich auch eine Client-ID, siehe set apiKey.<br>
|
||
|
||
Weitere Details sind im <a href="https://wiki.fhem.de/wiki/Vitoconnect">FHEM Wiki (deutsch)</a> zu finden.<br><br>
|
||
|
||
Für die Nutzung werden die folgenden Bibliotheken benötigt:
|
||
<ul>
|
||
<li>Path::Tiny</li>
|
||
<li>JSON</li>
|
||
<li>JSON::XS</li>
|
||
<li>DateTime</li>
|
||
</ul>
|
||
|
||
Die Bibliotheken können mit dem Befehl <code>sudo apt install libtypes-path-tiny-perl libjson-perl libdatetime-perl</code> installiert werden oder über cpan. Andernfalls tritt eine Fehlermeldung "cannot load module vitoconnect" auf.
|
||
|
||
<br><br>
|
||
<a id="vitoconnect-define"></a>
|
||
<b>Define</b>
|
||
<ul>
|
||
<code>define <name> vitoconnect <user> <password> <interval></code><br>
|
||
Es wird empfohlen, zunächst ein falsches Passwort zu verwenden und dieses später zu ändern, da es in der Detailansicht des Geräts sichtbar ist.
|
||
<br><br>
|
||
Beispiel:<br>
|
||
<code>define vitoconnect vitoconnect user@mail.xx fakePassword 60</code><br>
|
||
<code>set vitoconnect password correctPassword 60</code>
|
||
<code>set vitoconnect apiKey Client-ID</code>
|
||
<br><br>
|
||
</ul>
|
||
<br>
|
||
|
||
<a id="vitoconnect-set"></a>
|
||
<b>Set</b><br>
|
||
<ul>
|
||
<a id="vitoconnect-set-update"></a>
|
||
<li><code>update</code><br>
|
||
Liest sofort die aktuellen Werte aus.</li>
|
||
<a id="vitoconnect-set-selectDevice"></a>
|
||
<li><code>selectDevice</code><br>
|
||
Wird benötigt, wenn mehr als ein Viessmann Gateway/Device vorhanden ist. Ein Viessmann Gerät muss für jedes FHEM Gerät ausgewählt werden.<br>
|
||
Der Set-Befehl muss ausgeführt werden, nachdem die Viessmann Geräte im Gerätestatus vorgefüllt sind.<br>
|
||
Bei Auswahl eines Viessmann Geräts und Ausführung des Set-Befehls werden die Attribute vitoconnect_serial und vitoconnect_installationId gefüllt.<br>
|
||
Bei nur einem Viessmann Gerät erfolgt dies automatisch.<br>
|
||
Es wird empfohlen, die Änderungen nach der Initialisierung oder dem Set zu speichern.
|
||
</li>
|
||
<a id="vitoconnect-set-clearReadings"></a>
|
||
<li><code>clearReadings</code><br>
|
||
Löscht sofort alle Werte.</li>
|
||
<a id="vitoconnect-set-clearMappedErrors"></a>
|
||
<li><code>clearMappedErrors</code><br>
|
||
Löscht sofort alle gemappten Fehler Werte.</li>
|
||
<a id="vitoconnect-set-password"></a>
|
||
<li><code>password passwd</code><br>
|
||
Speichert das Passwort im Schlüsselbund.</li>
|
||
<a id="vitoconnect-set-logResponseOnce"></a>
|
||
<li><code>logResponseOnce</code><br>
|
||
Speichert die JSON-Antwort des Viessmann-Servers in den Dateien entities.json, gw.json und actions.json im FHEM-Log-Verzeichnis.
|
||
Wenn mehrere Gateways vorhanden sind, wird die Seriennummer des Gateways an die Dateinamen angehängt.</li>
|
||
<a id="vitoconnect-set-apiKey"></a>
|
||
<li><code>apiKey</code><br>
|
||
Ein API-Schlüssel muss unter https://developer.viessmann-climatesolutions.com/ erstellt werden.
|
||
Dazu ein Konto anlegen, einen neuen Client hinzufügen (Google reCAPTCHA deaktivieren, Redirect URI = http://localhost:4200/).
|
||
Die Client-ID muss als apiKey hier eingefügt werden.</li>
|
||
<li><code>Die Setter für das Gerät hängen von der gewählten Mappingmethode ab, die durch die Attribute vitoconnect_raw_readings oder vitoconnect_mapping_roger gesteuert wird.</code><br>
|
||
Neue Setter werden verwendet, wenn vitoconnect_raw_readings = 1 gesetzt ist.
|
||
Standardmäßig wird das statische Mapping der alten SVN-Version verwendet.
|
||
Die folgenden Setter sind verfügbar:
|
||
</li>
|
||
<li><code>HKn_Heizkurve_Niveau shift</code><br>
|
||
Setzt die Verschiebung der Heizkurve für HKn.</li>
|
||
<li><code>HKn_Heizkurve_Steigung slope</code><br>
|
||
Setzt die Steigung der Heizkurve für HKn.</li>
|
||
<li><code>HKn_Urlaub_Start_Zeit start</code><br>
|
||
Setzt die Urlaubsstartzeit für HKn.<br>
|
||
Start muss im Format: 2019-02-02 angegeben werden.</li>
|
||
<li><code>HKn_Urlaub_Ende_Zeit end</code><br>
|
||
Setzt die Urlaubsendzeit für HKn.<br>
|
||
Ende muss im Format: 2019-02-16 angegeben werden.</li>
|
||
<li><code>HKn_Urlaub_stop</code><br>
|
||
Entfernt die Urlaubsstart- und Endzeit für HKn.</li>
|
||
<li><code>HKn_Zeitsteuerung_Heizung schedule</code><br>
|
||
Setzt den Heizplan für HKn im JSON-Format.<br>
|
||
Beispiel: {"mon":[],"tue":[],"wed":[],"thu":[],"fri":[],"sat":[],"sun":[]} für keinen Betrieb und {"mon":[{"mode":"on","start":"00:00","end":"24:00","position":0}],...} für 24/7 Betrieb.</li>
|
||
<li><code>HKn_Betriebsart heating,standby</code><br>
|
||
Setzt den Betriebsmodus für HKn auf heizen oder standby.</li>
|
||
<li><code>WW_Betriebsart balanced,off</code><br>
|
||
Setzt den Betriebsmodus für Warmwasser auf ausgeglichen oder aus.</li>
|
||
<li><code>HKn_Soll_Temp_comfort_aktiv activate,deactivate</code><br>
|
||
Aktiviert/deaktiviert die Komforttemperatur für HKn.</li>
|
||
<li><code>HKn_Soll_Temp_comfort targetTemperature</code><br>
|
||
Setzt die Komfortzieltemperatur für HKn.</li>
|
||
<li><code>HKn_Soll_Temp_eco_aktiv activate,deactivate</code><br>
|
||
Aktiviert/deaktiviert die Ökotemperatur für HKn.</li>
|
||
<li><code>HKn_Soll_Temp_normal targetTemperature</code><br>
|
||
Setzt die normale Zieltemperatur für HKn (zwischen 3 und 37 Grad Celsius).</li>
|
||
<li><code>HKn_Soll_Temp_reduziert targetTemperature</code><br>
|
||
Setzt die reduzierte Zieltemperatur für HKn (zwischen 3 und 37 Grad Celsius).</li>
|
||
<li><code>HKn_Name name</code><br>
|
||
Setzt den Namen des Kreislaufs für HKn.</li>
|
||
<li><code>WW_einmaliges_Aufladen activate,deactivate</code><br>
|
||
Aktiviert oder deaktiviert einmaliges Aufladen für Warmwasser.</li>
|
||
<li><code>WW_Zirkulationspumpe_Zeitplan schedule</code><br>
|
||
Setzt den Zeitplan im JSON-Format für die Warmwasserzirkulationspumpe.</li>
|
||
<li><code>WW_Zeitplan schedule</code><br>
|
||
Setzt den Zeitplan im JSON-Format für Warmwasser.</li>
|
||
<li><code>WW_Solltemperatur targetTemperature</code><br>
|
||
Setzt die Warmwassertemperatur (zwischen 10 und 60 Grad Celsius) auf targetTemperature.</li>
|
||
<li><code>Urlaub_Start_Zeit start</code><br>
|
||
Setzt die Urlaubsstartzeit.<br>
|
||
Start muss im Format: 2019-02-02 angegeben werden.</li>
|
||
<li><code>Urlaub_Ende_Zeit end</code><br>
|
||
Setzt die Urlaubsendzeit.<br>
|
||
Ende muss im Format: 2019-02-16 angegeben werden.</li>
|
||
<li><code>Urlaub_stop</code><br>
|
||
Entfernt die Urlaubsstart- und Endzeit.</li>
|
||
</ul>
|
||
</ul>
|
||
<br>
|
||
<a name="vitoconnectget"></a>
|
||
<b>Get</b><br>
|
||
<ul>
|
||
Keine Daten zum Abrufen verfügbar.
|
||
</ul>
|
||
<br>
|
||
|
||
<a name="vitoconnect-attr"></a>
|
||
<b>Attributes</b>
|
||
<ul>
|
||
<code>attr <name> <attribute> <value></code>
|
||
<br><br>
|
||
Weitere Informationen zum attr-Befehl sind in der <a href="http://fhem.de/commandref.html#attr">commandref#attr</a> zu finden.
|
||
<br><br>
|
||
Attribute:
|
||
<ul>
|
||
<a id="vitoconnect-attr-disable"></a>
|
||
<li><i>disable</i>:<br>
|
||
Stoppt die Kommunikation mit dem Viessmann-Server.
|
||
</li>
|
||
<a id="vitoconnect-attr-verbose"></a>
|
||
<li><i>verbose</i>:<br>
|
||
Setzt das Verbositätslevel.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_raw_readings"></a>
|
||
<li><i>vitoconnect_raw_readings</i>:<br>
|
||
Erstellt Readings mit einfachen JSON-Namen wie 'heating.circuits.0.heating.curve.slope' anstelle von deutschen Bezeichnern (altes Mapping), Mapping-Attributen oder Übersetzungen.<br>
|
||
Wenn raw Readings verwendet werden, werden die Setter dynamisch erstellt, die den raw Readings entsprechen.<br>
|
||
Diese Einstellung wird empfohlen, um die Daten so dynamisch wie möglich von der API zu erhalten.<br>
|
||
stateFormat oder userReadings können verwendet werden, um wichtige Readings mit einem lesbaren Namen anzuzeigen.<br>
|
||
Wenn vitoconnect_raw_readings gesetzt ist, wird kein Mapping verwendet.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_disable_raw_readings"></a>
|
||
<li><i>vitoconnect_disable_raw_readings</i>:<br>
|
||
Deaktiviert die zusätzliche Generierung von raw Readings.<br>
|
||
Es werden nur die Messwerte angezeigt, die im gewählten Mapping explizit zugeordnet sind.<br>
|
||
Diese Einstellung wird nicht aktiv, wenn vitoconnect_raw_readings = 1 gesetzt ist.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_gw_readings"></a>
|
||
<li><i>vitoconnect_gw_readings</i>:<br>
|
||
Erstellt ein Reading vom Gateway, einschließlich Informationen, wenn mehrere Gateways vorhanden sind.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_actions_active"></a>
|
||
<li><i>vitoconnect_actions_active</i>:<br>
|
||
Erstellt Readings für Aktionen, z.B. 'heating.circuits.0.heating.curve.setCurve.setURI'.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_mappings"></a>
|
||
<li><i>vitoconnect_mappings</i>:<br>
|
||
Definiert eigene Zuordnungen von Schlüssel-Wert-Paaren anstelle der eingebauten Zuordnungen. Das Format muss wie folgt sein:<br>
|
||
mapping<br>
|
||
{ 'device.serial.value' => 'device_serial',<br>
|
||
'heating.boiler.sensors.temperature.main.status' => 'status',<br>
|
||
'heating.boiler.sensors.temperature.main.value' => 'haupt_temperatur'}<br>
|
||
Die eigene Zuordnung hat Vorrang vor der alten Zuordnung.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_translations"></a>
|
||
<li><i>vitoconnect_translations</i>:<br>
|
||
Definiert eigene Übersetzungen für Wörter, die dann Teil für Teil übersetzt werden. Das Format muss wie folgt sein:<br>
|
||
translation<br>
|
||
{ 'device' => 'gerät',<br>
|
||
'messages' => 'nachrichten',<br>
|
||
'errors' => 'fehler'}<br>
|
||
Die eigene Übersetzung hat Vorrang vor der Zuordnung und der alten Zuordnung.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_mapping_roger"></a>
|
||
<li><i>vitoconnect_mapping_roger</i>:<br>
|
||
Verwendet das Mapping von Roger vom 8. November (https://forum.fhem.de/index.php?msg=1292441) anstelle der SVN-Zuordnung.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_serial"></a>
|
||
<li><i>vitoconnect_serial</i>:<br>
|
||
Dieses Attribut wird bei der Initialisierung des FHEM-Geräts gesetzt.<br>
|
||
Der Befehl <code>set <name> selectDevice <serial></code> muss ausgeführt werden, wenn mehrere Seriennummern verfügbar sind.<br>
|
||
Dieses Attribut muss nicht manuell gesetzt werden, wenn nur ein Viessmann Gerät vorhanden ist.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_installationID"></a>
|
||
<li><i>vitoconnect_installationID</i>:<br>
|
||
Dieses Attribut wird bei der Initialisierung des FHEM-Geräts gesetzt.<br>
|
||
Der Befehl <code>set <name> selectDevice <serial></code> muss ausgeführt werden, wenn mehrere Seriennummern verfügbar sind.<br>
|
||
Dieses Attribut muss nicht manuell gesetzt werden, wenn nur ein Viessmann Gerät vorhanden ist.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_timeout"></a>
|
||
<li><i>vitoconnect_timeout</i>:<br>
|
||
Setzt ein Timeout für den API-Aufruf.
|
||
</li>
|
||
<a id="vitoconnect-attr-vitoconnect_device"></a>
|
||
<li><i>vitoconnect_device</i>:<br>
|
||
Es kann zwischen den Geräten 0 (Standard) oder 1 gewählt werden. Diese Funktion konnte nicht getestet werden, da nur ein Gerät verfügbar ist.
|
||
</li>
|
||
</ul>
|
||
</ul>
|
||
|
||
=end html_DE
|
||
|
||
=for :application/json;q=META.json 98_vitoconnect.pm
|
||
{
|
||
"abstract": "Using the viessmann API to read and set data",
|
||
"x_lang": {
|
||
"de": {
|
||
"abstract": "Benutzt die Viessmann API zum lesen und setzen von daten"
|
||
}
|
||
},
|
||
"keywords": [
|
||
"inverter",
|
||
"photovoltaik",
|
||
"electricity",
|
||
"heating",
|
||
"burner",
|
||
"heatpump",
|
||
"gas",
|
||
"oil"
|
||
],
|
||
"version": "v1.1.1",
|
||
"release_status": "stable",
|
||
"author": [
|
||
"Stefan Runge <stefanru@gmx.de>"
|
||
],
|
||
"x_fhem_maintainer": [
|
||
"Stefanru"
|
||
],
|
||
"x_fhem_maintainer_github": [
|
||
"stefanru1"
|
||
],
|
||
"prereqs": {
|
||
"runtime": {
|
||
"requires": {
|
||
"FHEM": 5.00918799,
|
||
"perl": 5.014,
|
||
"POSIX": 0,
|
||
"GPUtils": 0,
|
||
"Encode": 0,
|
||
"Blocking": 0,
|
||
"Color": 0,
|
||
"utf8": 0,
|
||
"HttpUtils": 0,
|
||
"JSON": 4.020,
|
||
"FHEM::SynoModules::SMUtils": 1.0270,
|
||
"Time::HiRes": 0,
|
||
"MIME::Base64": 0,
|
||
"Math::Trig": 0,
|
||
"List::Util": 0,
|
||
"Storable": 0
|
||
},
|
||
"recommends": {
|
||
"FHEM::Meta": 0,
|
||
"FHEM::Utility::CTZ": 1.00,
|
||
"DateTime": 0,
|
||
"DateTime::Format::Strptime": 0,
|
||
"AI::DecisionTree": 0,
|
||
"Data::Dumper": 0
|
||
},
|
||
"suggests": {
|
||
}
|
||
}
|
||
},
|
||
"resources": {
|
||
"x_wiki": {
|
||
"web": "https://wiki.fhem.de/wiki/Vitoconnect",
|
||
"title": "vitoconnect"
|
||
},
|
||
"repository": {
|
||
"x_dev": {
|
||
"type": "svn",
|
||
"url": "https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/",
|
||
"web": "https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/98_vitoconnect.pm",
|
||
"x_branch": "dev",
|
||
"x_filepath": "fhem/contrib/",
|
||
"x_raw": "https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/98_vitoconnect.pm"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
=end :application/json;q=META.json
|
||
|
||
=cut
|