abbrechen
Suchergebnisse werden angezeigt für 
Anzeigen  nur  | Stattdessen suchen nach 
Meintest du: 

Viessmann-API integration into RaspberryMatic / HomeMatic CCU3 + RegaScript

Hi all,

for all looking for some starting point to get the Viessmann-API integrated into the RaspberryMatic, please find below the script I am using for my heat-pump AWB201.E10 2C.
You need 

  • to set "debug" to true (1) to get the fundamental systemvariables created once and
  • to add the code-challenge either from the examples given by Viessmann or create your own.
  • Last, you need to provide your personal login-credentials here (at least once to get the refresh_token). The client-id you get from here after initial registration: https://app.developer.viessmann.com/ go with the standard recommendations and you are fine.

Since I have the system up-and-running and did delete my credentials and some bits around this I could not test it from scratch.

 

!-- HeatPump AllInOne -- v0.10 --
!_________________________________________________________________________________________________
! All-in-One script to generate tokens and get parameters of heat-pump form Viessmann-API
! ------------------------------------------------------------------------------------------
! VitoHeld
! ******************************************************************************************
!
! --------------------------------------------------------------------------------------------------
! https://documentation.viessmann.com/static/getting-started
! --------------------------------------------------------------------------------------------------

! set to 'true' for first execution to create system variables
boolean debug                = true; 
boolean initializeAllTokens  = false;
boolean renewalAccessToken   = false;
integer timeout              = 5;
! access data Viessmann acount
! https://account.viessmann.com/
string client_id = ""; ! enter your client-id 
string email     = ""; ! enter your login email
string password  = ""; ! enter your password

string AUTHORIZE_URL   = "https://iam.viessmann.com/idp/v3/authorize";
string TOKEN_URL       = "https://iam.viessmann.com/idp/v3/token";
string FEATURE_URL     = "https://api.viessmann.com/iot/v1/equipment/installations";
string EVENT_URL       = "https://api.viessmann.com/iot/v2/events-history/installations";
string REDIRECT_URI    = "http://localhost:4200/";
string VIESSMANN_SCOPE = "IoT%20User%20offline_access"; 
! Code Challenge using S256
! https://developer.pingidentity.com/en/tools/pkce-code-generator.html
string code_verifier    = ""; ! enter your personlized code-challenge here; on issues: use example provided by Viessmann
string code_challenge   = ""; ! enter your personlized code-challenge here; on issues: use example provided by Viessmann

string stdout           = "";
string stderr           = "";
string func             = "";
string access_token     = "";
string refresh_token    = "";
string api_error        = "";
string hpStatus         = "";

time now = system.Date("%F %X").ToTime();

! if not present: create system variables to store access credentials; also hpStatus - but not for features
if (debug) {
    object svObjects = dom.GetObject(ID_SYSTEM_VARIABLES);
    string svName = "hpIDInstallation"; object svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Installation-ID Viessmann"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "hpIDGateway"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Gateway-ID Viessmann"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "hpIDDevice"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Device-ID Viessmann"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "hpTokenAccess"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Access-Token Viessmann-API"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "hpTokenRefresh"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Refresh-Token Viessmann-API"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "hpStatus"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("Status Wärmepumpe/API"); svObj.Name(svName); svObj.ValueType(ivtString); svObj.ValueSubType(istChar8859); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(""); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    svName = "sysStatus"; svObj  = dom.GetObject(svName);
    if (!svObj) { svObj = dom.CreateObject(OT_VARDP); svObjects.Add(svObj.ID()); svObj.DPInfo("CCU3 Status"); svObj.Name(svName); svObj.ValueType(ivtBinary); svObj.ValueSubType(istBool); svObj.ValueName0("Normalbetrieb"); svObj.ValueName1("Reboot"); svObj.ValueUnit(""); svObj.DPArchive(true); svObj.State(false); svObj.Internal(false); svObj.Visible(true); dom.RTUpdate(false); }
    if (debug) { WriteLine("...sytem variables created/checked successfully."); }
}

! exit while rebooting... but reset deviceID in order to active token-generation 
if (dom.GetObject(ID_SYSTEM_VARIABLES).Get("sysStatus")) { if (dom.GetObject(ID_SYSTEM_VARIABLES).Get("sysStatus").Value()) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDDevice").State(""); quit; } }

! get information if already available
string installationID = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDInstallation").Value();
string gatewayID      = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDGateway").Value();
string deviceID       = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDDevice").Value();
if (debug) { WriteLine("installationID: " # installationID # "\ngatewayID: " # gatewayID # "\n(deviceID: " # deviceID # ")"); }

! TTL = 3600s for access_token -> revoke script e.g. every 3333 seconds
string access_token = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenAccess").Value();
if (access_token <> "")
{
    object sysvar = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenAccess");
    time lastChange = sysvar.Timestamp();
    integer atValidity = 3600 - (now - lastChange).ToInteger();
    if (debug) { WriteLine("Access-Token last update: " # lastChange # " (still valid for: " # atValidity # " sec)"); }
}
elseif (debug) { WriteLine("No Access-Token found - will get generated..."); }

! TTL = 15552000 for refresh_token
string refresh_token = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenRefresh").Value();
if (refresh_token <> "") 
{
    sysvar = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenRefresh");
    lastChange = sysvar.Timestamp();
    integer rtValidity = 15552000 - (now - lastChange).ToInteger();
    if (debug) { WriteLine("Refresh-Token last update: " # lastChange # " (still valid for: " # rtValidity # " sec)"); }

}
elseif (debug) { WriteLine("No Refresh-Token found - will get generated..."); }

! revoke tokens as required
if ((rtValidity < 333333) || (deviceID == "")) { initializeAllTokens = true; } elseif (atValidity < 333) { renewalAccessToken = true; }
! if not all tokens and IDs are given, generate or get them
if ((installationID == "") || (gatewayID == "") || (deviceID == "") || (access_token == "") || (refresh_token == "")) { initializeAllTokens = true; }

! initialize or renew tokens only if required
if (initializeAllTokens) 
{
    ! Step 1: Authorization request
    func = AUTHORIZE_URL # "?client_id=" # client_id # "&redirect_uri=" # REDIRECT_URI # "&scope=" # VIESSMANN_SCOPE # "&response_type=code&code_challenge_method=S256&code_challenge=" # code_challenge;
    func = "curl -m " # timeout # " -u '" # email # ":" # password # "' '" # func # "'";
    system.Exec(func, &stdout, &stderr); 
    ! exit on error, provide API-return code as hpStatus
    if (stdout.Find('{"viErrorId":') == 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = "API-Error: " # api_error.Substr(0, api_error.Find("}")-1); dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }
    string code = stdout.Substr(stdout.Find("?code=")+6, stdout.Length()-(stdout.Find("?code=")+6));
    code = code.Substr(0, code.Find("\""));
    if (debug) { WriteLine("Code = " # code); }

    ! Step 2: Authorization code exchange
    func = "curl -m " # timeout # " -X POST '" # TOKEN_URL # "' -H 'Content-Type: application/x-www-form-urlencoded' -d 'client_id=" # client_id # "&redirect_uri=" # REDIRECT_URI # "&grant_type=authorization_code&code_verifier=" # code_verifier # "&code=" # code # "'";
    system.Exec(func, &stdout, &stderr); 
    ! exit on error, provide API-return code as hpStatus
    if (stdout.Find('{"viErrorId":') == 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = "API-Error: " # api_error.Substr(0, api_error.Find("}")-1); dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }

    ! TTL (time to life) of access_token is: 3600s = 1 hour
    access_token = stdout.Substr(stdout.Find("access_token")+15, stdout.Length()-(stdout.Find("access_token")+15));
    access_token = access_token.Substr(0, access_token.Find(",")-1);
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenAccess").State(access_token);

    ! TTL (time to life) of refresh_token is: 15552000s = 180 days
    refresh_token = stdout.Substr(stdout.Find("refresh_token")+16, stdout.Length()-(stdout.Find("refresh_token")+16));
    refresh_token = refresh_token.Substr(0, refresh_token.Find(",")-1);
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenRefresh").State(refresh_token);

    if (debug) { WriteLine("Access-Token: " # access_token); WriteLine("Refresh-Token: " # refresh_token); }
}
elseif (renewalAccessToken)
{
    ! Refreshing an access token
    ! curl -X POST "https://iam.viessmann.com/idp/v3/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=refresh_token&client_id=my_oauth_client_id&refresh_token=083ed7fe41a619242df5978190fd11b5"

    access_token  = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenAccess").Value();
    refresh_token = dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenRefresh").Value();
    if (debug) { WriteLine("Refresh-Token: " # refresh_token); }

    ! renewal of access_token
    func = "curl -m " # timeout # " -X POST '" # TOKEN_URL # "' -H 'Content-Type: application/x-www-form-urlencoded' -d 'client_id=" # client_id # "&grant_type=refresh_token&refresh_token=" # refresh_token # "'";
    system.Exec(func, &stdout, &stderr); 
    ! exit on error, provide API-return code as hpStatus
    if (stdout.Find('{"viErrorId":') == 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = "API-Error: " # api_error.Substr(0, api_error.Find("}")-1); dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }

    ! TTL (time to life) of access_token is: 3600s = 1 hour
    access_token = stdout.Substr(stdout.Find("access_token")+15, stdout.Length()-(stdout.Find("access_token")+15));
    access_token = access_token.Substr(0, access_token.Find(",")-1);
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpTokenAccess").State(access_token);

    if (debug) { WriteLine("Access-Token: " # access_token); WriteLine("Refresh-Token: " # refresh_token); }
}

! ensure all IDs are available
if (deviceID == "")
{
    ! For using IoT features, you need essential three numbers of your heating device: installationID, gatewaySerial and deviceID. 
    ! curl -X GET "https://api.viessmann.com/iot/v1/equipment/installations?includeGateways=true" -H "Authorization: Bearer {{Acces_Token}}"
    func = "curl -m " # timeout # " -X GET '" # FEATURE_URL # "?includeGateways=true' -H 'content-type: application/json' -H 'authorization:Bearer " # access_token # "'";
    system.Exec(func, &stdout, &stderr); 
    ! exit on error, provide API-return code as hpStatus
    if (stdout.Find('{"viErrorId":') == 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = "API-Error: " # api_error.Substr(0, api_error.Find("}")-1); dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }

    ! get installationID 
    installationID = stdout.Substr(stdout.Find("id")+4, stdout.Length()-(stdout.Find("id")+4));
    installationID = installationID.Substr(0, installationID.Find(","));
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDInstallation").State(installationID);
    if (debug) { WriteLine("InstallationID = " # installationID); }

    ! get GatewayID
    gatewayID = stdout.Substr(stdout.Find("gatewaySerial")+16, stdout.Length()-(stdout.Find("gatewaySerial")+16));
    gatewayID = gatewayID.Substr(0, gatewayID.Find(",")-1);
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDGateway").State(gatewayID);
    if (debug) { WriteLine("GatewayID = " # gatewayID); }

    ! curl -X GET https://api.viessmann.com/iot/v1/equipment/installations/{{installationID}}/gateways/{{gatewaySerial}}/devices
    func = "curl -m " # timeout # " -X GET '" # FEATURE_URL # "/" # installationID # "/gateways/" # gatewayID # "/devices' -H 'content-type: application/json' -H 'authorization:Bearer " # access_token # "'";
    system.Exec(func, &stdout, &stderr); 
    ! exit on error, provide API-return code as hpStatus
    if (stdout.Find('{"viErrorId":') == 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = "API-Error: " # api_error.Substr(0, api_error.Find("}")-1); dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }

    ! get DeviceID
    string deviceID = stdout.Substr(stdout.Find(',"id":"0","boilerSerial":"')+26, stdout.Length()-(stdout.Find(',"id":"0","boilerSerial":"')+26));
    ! worked until 01.02.2024: string deviceID = stdout.Substr(stdout.Find("boilerSerial")+15, stdout.Length()-(stdout.Find("boilerSerial")+15));
    deviceID = deviceID.Substr(0, deviceID.Find(",")-1);
    dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDDevice").State(deviceID);
    if (debug) { WriteLine("DeviceID = " # deviceID); }
}

! get overall status of heatpump
func = "curl -m " # timeout # " -X GET '" # FEATURE_URL # "' -H 'content-type: application/json' -H 'authorization:Bearer " # access_token # "'";
system.Exec(func, &stdout, &stderr); 
! exit on error, provide API-return code as hpStatus
if (stdout.Find('{"viErrorId":') == 0) { if (stdout.Find(',"error":') > 0) { api_error = stdout.Substr(stdout.Find(',"error":')+10, stdout.Length()-(stdout.Find(',"error":')+10)); api_error = api_error.Substr(0, api_error.Find("}")-1); } elseif (stdout.Find(',"errorType":') > 0) { api_error = stdout.Substr(stdout.Find(',"errorType":')+14, stdout.Length()-(stdout.Find(',"errorType":')+14)); api_error = api_error.Substr(0, api_error.Find('",')); } else { api_error = "unknown"; } api_error = "API-Error: " # api_error; if (api_error.Find("TOKEN") > 0) { dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpIDDevice").State(""); } if (debug) { WriteLine("hpStatus := " # api_error); } dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); quit; }
if (stdout.Find('{"cursor":{"next":') <> 0) { api_error = "unexpected content returned by API-call"; if (stderr.Find("Operation timed out after") > 0) { api_error = api_error # " (timeout/vi-maintenance)"; } dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(api_error); if (debug) { WriteLine(api_error); } quit; }
hpStatus = stdout.Substr(stdout.Find("aggregatedStatus")+19, stdout.Length()-(stdout.Find("aggregatedStatus")+19));
hpStatus = hpStatus.Substr(0, hpStatus.Find(",")-1);
dom.GetObject(ID_SYSTEM_VARIABLES).Get("hpStatus").State(hpStatus);
if (debug) { WriteLine("hpStatus = " # hpStatus); }

 

0 ANTWORTEN 0