Page 4 of 5

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Sunday 16 May 2021 22:27
by rgroothuis
Trying to get the plugin working as well but without any luck.

This is what I'm getting, any suggestions on how to fix it?

Code: Select all

2021-05-16 22:20:00.180 Error: (Domoticz-Home-Connect-Plugin) failed to load 'plugin.py', Python Path used was '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/:/usr/lib/python37.zip:/usr/lib/python3.7:/usr/lib/python3.7/lib-dynload:/usr/local/lib/python3.7/dist-packages:/usr/lib/python3/dist-packages:/usr/lib/python3.7/dist-packages'.
2021-05-16 22:20:00.180 Error: (Dishwasher) Module Import failed, exception: 'ModuleNotFoundError'
2021-05-16 22:20:00.180 Error: (Dishwasher) Module Import failed: ' Name: sseclient'
2021-05-16 22:20:00.180 Error: (Dishwasher) Error Line details not available.
FYI, I went through this entire thread and could find the answer. Will read it again tomorrow, maybe I overlooked something.

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Sunday 16 May 2021 22:31
by rgroothuis
Oh, I just realised that I had to install SSECLIENT module also in Python. This above error is solved, now running into the next error:

Code: Select all

2021-05-16 22:30:19.645 Error: (Dishwasher) Device "" is not authorized by Home_Connect.
2021-05-16 22:30:19.790 Error: (Dishwasher) 'onStart' failed 'TypeError':'string indices must be integers'.
2021-05-16 22:30:19.790 Error: (Dishwasher) ----> Line 459 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-16 22:30:19.790 Error: (Dishwasher) ----> Line 95 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-16 22:30:19.790 Error: (Dishwasher) ----> Line 91 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnecthelper.py', function gethaId
2021-05-16 22:30:23.003 Error: (Dishwasher) Device "" is not authorized by Home_Connect.
2021-05-16 22:30:23.149 Error: (Dishwasher) 'onStart' failed 'TypeError':'string indices must be integers'.
2021-05-16 22:30:23.149 Error: (Dishwasher) ----> Line 459 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-16 22:30:23.149 Error: (Dishwasher) ----> Line 95 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-16 22:30:23.149 Error: (Dishwasher) ----> Line 91 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnecthelper.py', function gethaId

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Sunday 16 May 2021 22:36
by rgroothuis
Just checking, maybe somebody can confirm if I filled in the Siemens connect dev API correctly, see screenshot?

What do I need to fill in for the redirection URL?
Screenshot 2021-05-16 at 22.33.11.png
Screenshot 2021-05-16 at 22.33.11.png (183.83 KiB) Viewed 2737 times

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Monday 17 May 2021 22:13
by rgroothuis
Anybody any suggestions?

What I don't understand is how to connect my Dishwasher into the account that I've created at https://developer.home-connect.com/! How do I connect my Dishwasher into this account? Any suggestions?

The errors in Domoticz are still:

Code: Select all

2021-05-17 22:02:44.121 Error: (Dishwasher) Device "" is not authorized by Home_Connect.
2021-05-17 22:02:44.321 Error: (Dishwasher) 'onStart' failed 'TypeError':'string indices must be integers'.
2021-05-17 22:02:44.321 Error: (Dishwasher) ----> Line 459 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-17 22:02:44.321 Error: (Dishwasher) ----> Line 95 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-17 22:02:44.321 Error: (Dishwasher) ----> Line 91 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnecthelper.py', function gethaId
In the installation steps it is stated: "Register an application with the following parameters: ** OAuth Flow = "Device Flow"" what name do I need to fill in for the Device Flow? Or is this the actual string that I need to exactly copy when I'm registering? See also screenshot above.

So I guess that somehow to link to my Dishwasher is not setup correctly. I review all the install steps and cannot find what is wrong. Any suggestions?

If anybody can help me on this it would be appreciated. Even suggestions on how to debug this issue would be great. Thanks.

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 19 May 2021 15:11
by rgroothuis
Anybody who can help on this?

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 19 May 2021 15:25
by EscApe
rgroothuis wrote: Wednesday 19 May 2021 15:11 Anybody who can help on this?
Hi,

I don’t know if the plugin is being actively maintained. Tried it for a while but it would always stop updating values so I turned to ifttt instead.

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 19 May 2021 15:30
by rgroothuis
Thanks for the feedback. Indeed of the plugin is not maintained it is an issue.

How did you add the Siemens/Bosch device into the developer API account? THat is something I don't understand. Maybe that is the only issue I'm having. If that is solved, maybe the plugin is working.

I created an account, created an application etc, see also screenshot above. But I was not able to add my dishwasher into that account. Somehow you need to link the DishWasher at home into that account, correct?

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 19 May 2021 15:39
by EscApe
Sorry, it’s a while ago and I can’t remember this from the top of my mind. Otherwise I would have responded with a real answer ;)

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 19 May 2021 15:50
by rgroothuis
Decided to delete the application etc in the Siemens portal and redo the config. Seems that I'm one step further, this is the error code/logging now:

Code: Select all

2021-05-19 15:48:06.415 Status: (Dishwasher) Started.
2021-05-19 15:48:07.139 Status: (Dishwasher) Initialized version 3.2.1, author 'Mario Peters'
2021-05-19 15:48:07.138 Status: (Dishwasher) Entering work loop.
2021-05-19 15:48:09.029 Error: (Dishwasher) 'onStart' failed 'TypeError':'string indices must be integers'.
2021-05-19 15:48:09.029 Error: (Dishwasher) ----> Line 459 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-19 15:48:09.029 Error: (Dishwasher) ----> Line 95 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py', function onStart
2021-05-19 15:48:09.029 Error: (Dishwasher) ----> Line 91 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnecthelper.py', function gethaId
Next is I will check the lines 459, 95 and 91 to see if I see something strange.

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Monday 06 December 2021 21:24
by garycooper
hi ! No-one found how to use this plugin ? Unfortunately, it seems not maintained again ... I have a washer dryer and want to use it with domoticz.

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Monday 06 December 2021 22:43
by FireWizard
Hi @garycooper,

You might want to have a look at this thread as well:

viewtopic.php?f=64&t=33586&hilit=Bosch

Regards

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Thursday 09 December 2021 10:19
by garycooper
Hi FireWizard, I saw this thread but I don't understand how to do the same. It would be fun and easily with a plugin

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Thursday 09 December 2021 16:41
by FireWizard
Hello @garycooper

I do not have any experience with that plugin, so I'm afraid I cannot help you further.
If you need some help with the Node RED solution, let me know.

Regards

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Tuesday 26 April 2022 18:36
by teha
mario-peters is a star!

finally got my washer and dryer up and running, kind of amazing that this still works after this many years

There are some addons that need to work properly in python to make this happen

So I got things working in an ubuntu virtual environment, i wll in the next comming weeks try to implement this in my production pi environment, there are some differences to take care of with regards to the python install

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Tuesday 26 April 2022 19:02
by teha
So register an account at https://developer.home-connect.com/
create an application
1_homeconnect.jpg
1_homeconnect.jpg (62.81 KiB) Viewed 2238 times
in domoticz create harware with the home connect plugin
2_Domoticzhardware.jpg
2_Domoticzhardware.jpg (24.48 KiB) Viewed 2238 times
username/pwd should be the username in the app (not in developer.home-connect.com)
port number is your choice, I did choose 8399 for the washer hardware (matching below)

I cloned the homeconnectSSE.sh file to homeconnectSSE_washer.sh
following line should be edited

PYTHON_PATH=/usr/bin/python3
DIR=/home/teha/domoticz/plugins/Domoticz-Home-Connect-Plugin
DAEMON=$DIR/homeconnectSSE.py
DEVICE_NAME=Washer
DOMOTICZ_IP=YOUR_DOMITICZ_LOCAL_IP
DOMOTICZ_PORT=8399
DAEMON_NAME=homeconnectSSE_$DEVICE_NAME
DAEMON_LOG=/home/teha/logs/$DAEMON_NAME.log
# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you ar using the Raspberry Pi GPIO from Python.
DAEMON_USER=YOUR_USER_THAT_RUN_DOMOTICZ

copy homeconnectSSE_washer.sh from plugin to /etc/init.d
sudo update-rc.d homeconnectSSE_washer.sh defaults
sudo service homeconnectSSE_washer.sh start

restart domoticz
restart homeconnectSSE_washer.sh

last lines in the /home/USERNAME/logs/homeconnectSSE_Washer.log should now be some access token and then there will be a new line everytime domoticz make a call to the sseclient

maybe I skipped some of the steps with regards to instalkling python, python3, pip, pip3 and sseclient

hope this helps (remember this is for ubuntu and not for raspberry pi)

One more thing!
If you install the hardware in Domoticz and doing "update" on the harware and you get some data in to the devices (as your bosch device is running) but you don't get any continous updates, this is an indication on the everything is OK at https://developer.home-connect.com/ and also in Domoticz, however there is some problem with the communication to the sseclient, look in the logs at /home/USER/logs/xxxxx.log

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Tuesday 30 August 2022 17:35
by mariopeters
Currently I'm supporting a couple of Home Connect devices.
Shortly I want to implement some more.
Special the devices Hob and Fridge/Freezer or Refrigerator (with camera) are interesting me.
For testing purposes I'm searching for people who own these devices.
Please let me know by creating an issue in https://github.com/mario-peters/Domotic ... ect-Plugin

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Sunday 25 September 2022 9:10
by garycooper
Hi Mario ! I don't have Fridge/Freezer or Refrigerator but I've got a washer-dryer machine to test the plugin.

I tried to install the plugin but when I type "sudo service homeconnectSSE_Washer.sh start", it returns "Failed to start homeconnectSSE_Washer.service: Unit homeconnectSSE_Washer.service not found."

Also have this error
"2022-09-25 21:45:27.424 Error: Lave linge: (Lave linge) 'onStart' failed 'TypeError':'can only concatenate str (not "NoneType") to str'.
2022-09-25 21:45:27.424 Error: Lave linge: (Lave linge) ----> Line 464 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect/plugin.py', function onStart
2022-09-25 21:45:27.424 Error: Lave linge: (Lave linge) ----> Line 101 in '/home/pi/domoticz/plugins/Domoticz-Home-Connect/plugin.py', function onStart"

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 15 March 2023 11:04
by friso82
Hi,

Tried a lot and finally got something to work. Had to pip3 install the sseclient by the way :-)

Now I get the following in the log. How can this error be solved?

Code: Select all

2023-03-15 10:55:00.112 Status: Bosch Home Connect: Started.
2023-03-15 10:55:00.116 Status: Bosch Home Connect: Entering work loop.
2023-03-15 10:55:07.930 Bosch Home Connect: onStart called Domoticz-Home-Connect-Plugin
2023-03-15 10:55:07.918 Status: Bosch Home Connect: Initialized version 3.2.1, author 'Mario Peters'
2023-03-15 10:55:08.612 Bosch Home Connect: device_code: 1037d4c4-5b8a-4eb9-89a5-188b85dff000
2023-03-15 10:55:08.617 Bosch Home Connect: verification_uri_complete: https://api.home-connect.com/security/oauth/device_verify?user_code=H307-AMYU
2023-03-15 10:55:09.629 Bosch Home Connect: sessionid: html>
2023-03-15 10:55:09.629 <html>
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629 <head>
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629
2023-03-15 10:55:09.629 <meta http-equiv=
2023-03-15 10:55:09.879 Bosch Home Connect: Device "1037d4c4-5b8a-4eb9-89a5-188b85dff000" is authorized by Home-Connect.
2023-03-15 10:55:10.500 Bosch Home Connect: Device "1037d4c4-5b8a-4eb9-89a5-188b85dff000" has token:
2023-03-15 10:55:11.394 Bosch Home Connect: onHeartbeat called
2023-03-15 10:55:11.268 Error: Bosch Home Connect: Call to function 'onStart' failed, exception details:
2023-03-15 10:55:11.285 Error: Bosch Home Connect: Traceback (most recent call last):
2023-03-15 10:55:11.288 Error: Bosch Home Connect: File "/home/pi/domoticz/plugins/HomeConnect/plugin.py", line 459, in onStart
2023-03-15 10:55:11.290 Error: Bosch Home Connect: _plugin.onStart()
2023-03-15 10:55:11.292 Error: Bosch Home Connect: File "/home/pi/domoticz/plugins/HomeConnect/plugin.py", line 95, in onStart
2023-03-15 10:55:11.293 Error: Bosch Home Connect: self.haId = homeconnecthelper.gethaId(self,Parameters["Mode1"],Parameters["Mode4"])
2023-03-15 10:55:11.293 Error: Bosch Home Connect: File "/home/pi/domoticz/plugins/HomeConnect/homeconnecthelper.py", line 91, in gethaId
2023-03-15 10:55:11.293 Error: Bosch Home Connect: Domoticz.Debug(key + " --> " + str(item[key]))
2023-03-15 10:55:11.293 Error: Bosch Home Connect: TypeError: string indices must be integers
2023-03-15 10:55:21.066 Bosch Home Connect: onHeartbeat called

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Wednesday 29 March 2023 14:26
by Xavier82
Finally installed this plugin, I also missed the SSEclient, after installing I get this error in the logg:

Code: Select all

2023-03-29 14:21:42.281 Error: Siemens Home Connect: Call to function 'onStart' failed, exception details:
2023-03-29 14:21:42.284 Error: Siemens Home Connect: Traceback (most recent call last):
2023-03-29 14:21:42.284 Error: Siemens Home Connect: File "/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py", line 459, in onStart
2023-03-29 14:21:42.284 Error: Siemens Home Connect: _plugin.onStart()
2023-03-29 14:21:42.284 Error: Siemens Home Connect: File "/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/plugin.py", line 95, in onStart
2023-03-29 14:21:42.284 Error: Siemens Home Connect: self.haId = homeconnecthelper.gethaId(self,Parameters["Mode1"],Parameters["Mode4"])
2023-03-29 14:21:42.284 Error: Siemens Home Connect: File "/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnecthelper.py", line 91, in gethaId
2023-03-29 14:21:42.285 Error: Siemens Home Connect: Domoticz.Debug(key + " --> " + str(item[key]))
2023-03-29 14:21:42.285 Error: Siemens Home Connect: TypeError: string indices must be integers
Domoticz version: 2022.2
Running on Raspberry Pi with OS "Buster"

UPDATE (31-3-2023 11:25)
Seems to be an issue with SingleKeyID?

What can I do to resolve this?

Re: Siemens/Bosch Home Connect Ecosystem

Posted: Monday 22 May 2023 20:13
by Xavier82
Finally managed to fix the issue.

Important is to use an OTHER PORT!! in the plugin as the Domoticz port

file plugin.py:

Code: Select all

"""
"""
<plugin key="Domoticz-Home-Connect-Plugin" name="Home Connect Plugin" author="Mario Peters" version="3.2.1" wikilink="https://github.com/mario-peters/Domoticz-Home-Connect-Plugin/wiki" externallink="https://github.com/mario-peters/Domoticz-Home-Connect-Plugin">
    <description>
        <h2>Home Connect domoticz plugin 3.2.1</h2><br/>
        <h3>Features</h3>
        <ul style="list-style-type:square">
            <li>Dishwasher supported</li>
            <li>Washer supported</li>
            <li>Oven supported</li>
            <li>Dryer supported</li>
            <li>Hood supported</li>
        </ul>
        <h3>Configuration</h3>
        <ul style="list-style-type:square">
            <li>Username. This is the username which you use in the Home Connect app</li>
            <li>Password. This is the password which you use in the Home Connect app</li>
            <li>Port. This is the port on which the httplistener will listen for commands from the homeconnectSSE.sh script.</li>
            <li>Scope. This is the scope of the devices according to the Home Connect API (<a href="https://developer.home-connect.com/docs/authorization/scope">API Home Connect</a>).
                <ul style="list-style-type:square">
                    <li>Dishwasher</li>
                    <li>Washer</li>
                    <li>Oven</li>
                    <li>Dryer</li>
                    <li>Hood</li>
                </ul>
            </li>
            <li>Custom icons. Option for choosing custom icons. Default is False.</li>
            <li>Client ID: Client ID of the application as you registerd in your Home Connect Developer account.</li>
            <li>Device E-number: Unique E-number of the Siemens/Bosch device.</li>
        </ul>
        <br/><br/>
    </description>
    <params>
        <param field="Username" label="Username" width="150px" required="true"/>
        <param field="Password" label="Password" width="150px" required="true" password="true"/>
        <param field="Port" label="Port" width="150px" required="true"/>
        <param field="Mode1" label="Scope" width="150px" required="true">
            <options>
                <option label="Dishwasher" value="Dishwasher" default="true"/>
                <option label="Washer" value="Washer"/>
                <option label="Oven" value="Oven"/>
                <option label="Dryer" value="Dryer"/>
                <option label="Hood" value="Hood"/>
            </options>
        </param>
        <param field="Mode2" label="Custom icons" width="150px" required="false">
            <options>
                <option label="True" value="True"/>
                <option label="False" value="False" default="true"/>
            </options>
        </param>
        <param field="Mode3" label="Client ID" width="600px" required="true"/>
        <param field="Mode4" label="Device E-number" width="150px" required="true"/>
    </params>
</plugin>
"""
import Domoticz
import json
import base64
import homeconnecthelper
import datetime
import os

class BasePlugin:

    httpServerConn = None
    httpServerConns = {}
    httpClientConn = None
    clientid = ""
    haId = ""
    access_token = ""
    token_expired = datetime.datetime.now()
    refresh_token = ""
    selectedprogram = ""
    DRY_ICON = "Domoticz-Home-Connect-PluginAlt1"
    RINSE_ICON = "Domoticz-Home-Connect-PluginAlt2"
    SHINE_ICON = "Domoticz-Home-Connect-PluginAlt3"
    FINISH_ICON = "Domoticz-Home-Connect-PluginAlt4"
    CLEAN_ICON = "Domoticz-Home-Connect-PluginAlt5"
    HOMECONNECT_ICON = "Domoticz-Home-Connect-Plugin"
    DEVICE_DISHWASHER = "Dishwasher"
    DEVICE_WASHER = "Washer"
    DEVICE_OVEN = "Oven"
    DEVICE_DRYER = "Dryer"
    DEVICE_HOOD = "Hood"

    def __init__(self):
        #self.var = 123
        return

    def onStart(self):
        Domoticz.Log("onStart called "+Parameters["Key"])
        self.clientid = Parameters["Mode3"]
        homeconnecthelper.connectHomeConnect(self, Parameters["Username"], Parameters["Password"], Parameters["Mode1"])
        self.haId = homeconnecthelper.gethaId(self, Parameters["Mode1"], Parameters["Mode4"])
        Domoticz.Log("haId: " + (self.haId or ""))
        if Parameters["Mode2"] == "True":
            loadIcons(self, Images)
        
        #Create devices
        if len(Devices) == 0:
            Domoticz.Log("Create devices")
            self.haId = "blaat"
            if self.haId != None:
                #Generic devices
                ##Operation state
                if Parameters["Mode2"] == "True":
                    #Domoticz.Device(Name="Operation state", Unit=1, TypeName="Custom", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                    Domoticz.Device(Name="Operation state", Unit=1, TypeName="Text", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                else:
                    Domoticz.Device(Name="Operation state", Unit=1, TypeName="Text").Create()
                
                ##Power state
                Domoticz.Device(Name="Power state", Unit=2, Type=244, Subtype=73, Switchtype=0).Create()

                ##Active program
                if Parameters["Mode2"] == "True":
                    Domoticz.Device(Name="Active program", Unit=3, TypeName="Text", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                else:
                    Domoticz.Device(Name="Active program", Unit=3, TypeName="Text").Create()

                ##Program progres
                Domoticz.Device(Name="Program progress", Unit=6, TypeName="Percentage").Create()

                ##Remaining program time
                #Domoticz.Device(Name="Remaining program time", Unit=7, TypeName="Text").Create()
                if Parameters["Mode2"] == "True":
                    Domoticz.Device(Name="Remaining program time", Unit=7, TypeName="Custom", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                else:
                    Domoticz.Device(Name="Remaining program time", Unit=7, TypeName="Custom").Create()

                ##Estimated time
                if Parameters["Mode2"] == "True":
                    #Domoticz.Device(Name="Estimated time", Unit=8, TypeName="Custom", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                    Domoticz.Device(Name="Estimated program time", Unit=8, TypeName="Text", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                else:
                    Domoticz.Device(Name="Estimated program time", Unit=8, TypeName="Text").Create()

                ##Device specific devices
                if Parameters["Mode1"] == self.DEVICE_DISHWASHER:
                    #Custom Dishwasher devices
                    if Parameters["Mode2"] == "True":
                        Domoticz.Device(Name="Current program state", Unit=4, TypeName="Text", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                    else:
                        Domoticz.Device(Name="Current program state", Unit=4, TypeName="Text").Create()

                    ##Door state
                    Domoticz.Device(Name="Door state", Unit=5, Type=244, Subtype=73, Switchtype=11).Create()

                if Parameters["Mode1"] == self.DEVICE_WASHER:
                    #Customer Washer devices
                    ##Door state
                    Domoticz.Device(Name="Door state", Unit=5, Type=244, Subtype=73, Switchtype=11).Create()

                if Parameters["Mode1"] == self.DEVICE_OVEN:
                    #Custom Oven devices
                    ##Door state
                    Domoticz.Device(Name="Door state", Unit=5, Type=244, Subtype=73, Switchtype=11).Create()

                    Domoticz.Device(Name="Current cavity temperature", Unit=9, TypeName="Temperature").Create()
                if Parameters["Mode1"] == self.DEVICE_DRYER:
                    #Custom Dryer devices
                    ##Door state
                    Domoticz.Device(Name="Door state", Unit=5, Type=244, Subtype=73, Switchtype=11).Create()

                if Parameters["Mode1"] == self.DEVICE_HOOD:
                    #Custom Hood devices
                    ##Elepsed program time
                    if Parameters["Mode2"] == "True":
                        #Domoticz.Device(Name="Elapesed program time", Unit=9, TypeName="Custom", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                        Domoticz.Device(Name="Elapsed program time", Unit=9, TypeName="Text", Image=Images[self.HOMECONNECT_ICON].ID).Create()
                    else:
                        Domoticz.Device(Name="Elepsed program time", Unit=9, TypeName="Text").Create()

                    ##Venting level
                    OptionsVentingLevel = {"LevelActions": "||||", "LevelNames": "FanOff|FanStage01|FanStage02|FanStage03|FanStage04|FanStage05", "LevelOffHidden": "false", "SelectorStyle": "1"}
                    Domoticz.Device(Name="Venting level", Unit=10, TypeName="Selector Switch", Options=OptionsVentingLevel).Create()

                    ##Intensive level
                    OptionsIntensiveLevel = {"LevelActions": "||||", "LevelNames": "IntensiveStageOff|IntensiveStage1|IntensiveStage2", "LevelOffHidden": "false", "SelectorStyle": "1"}
                    Domoticz.Device(Name="Intensive level", Unit=11, TypeName="Selector Switch", Options=OptionsIntensiveLevel).Create()

        operationstate = "" 
        operationstate = homeconnecthelper.getOperationState(self,self.haId)
        if operationstate != "" and operationstate != None:
            #Devices[1].Update(nValue=Devices[1].nValue,sValue=operationstate.rpartition(".")[2],Options={"Custom": operationstate.rpartition(".")[2]})
            Devices[1].Update(nValue=Devices[1].nValue,sValue=operationstate.rpartition(".")[2])

        powerstate = ""
        powerstate = homeconnecthelper.getPowerState(self,self.haId)
        if powerstate != "" and powerstate != None:
            powerstate = powerstate.rpartition(".")[2]
            if powerstate == "On":
                Devices[2].Update(nValue=1,sValue="On")
            else:
                Devices[2].Update(nValue=0,sValue="Off")

        self.selectedprogram = ""
        self.selectedprogram = homeconnecthelper.getActiveProgram(self,self.haId)
        if self.selectedprogram != "" and self.selectedprogram != None:
            self.selectedprogram = self.selectedprogram.rpartition(".")[2]
            Devices[3].Update(nValue=Devices[3].nValue,sValue=self.selectedprogram)

        doorstate = ""
        doorstate = homeconnecthelper.getDoorState(self,self.haId)
        if doorstate != "" and doorstate != None:
            doorstate = doorstate.rpartition(".")[2]
            if doorstate == "Open":
                Devices[5].Update(nValue=1,sValue="Open")
            else:
                Devices[5].Update(nValue=0,sValue="Closed")

        self.httpServerConn = Domoticz.Connection(Name="Home-Connect "+Parameters["Mode1"]+" WebServer", Transport="TCP/IP", Protocol="HTTP", Port=Parameters["Port"])
        self.httpServerConn.Listen()
        Domoticz.Log("Listen on Home-Connect Webserver - Port: "+str(Parameters["Port"]))

    def onStop(self):
        Domoticz.Log("onStop called")

    def onConnect(self, Connection, Status, Description):
        Domoticz.Log("onConnect called")

        if (Status == 0):
            Domoticz.Debug("Connected successfully to "+Connection.Address+":"+Connection.Port)
        else:
            Domoticz.Log("Failed to connect ("+str(Status)+") to: "+Connection.Address+":"+Connection.Port+" with error: "+Description)
            Domoticz.Debug(str(Connection))
        if (Connection != self.httpClientConn):
            self.httpServerConns[Connection.Name] = Connection
            self.httpClientConn = Connection
        return

    def onMessage(self, Connection, Data):
        Domoticz.Log("onMessage called")
        
        data = ""
        for key_msg, value_msg in Data.items():
            Domoticz.Debug(str(key_msg)+" --> "+str(value_msg))
            if key_msg == "Data":
                a = value_msg.decode("utf-8")
                #Domoticz.Log(a)
                if a == "access_token":
                    if homeconnecthelper.isTokenValid(self) != True:
                        if homeconnecthelper.refreshToken(self) != True:
                            homeconnecthelper.connectHomeConnect(self,Parameters["Username"],Parameters["Password"],Parameters["Mode1"])
                    data = self.access_token
                elif a.startswith("haId:") == True:
                    data = self.haId
                else:
                    #Domoticz.Log(a)
                    json_items = json.loads(a)
                    deviceItems = []
                    for q,w in json_items.items():
                        Domoticz.Debug(q)
                        if q == "items":
                            deviceItems = w
                    for deviceItemList in deviceItems:
                        Domoticz.Debug(str(deviceItemList))
                        deviceKey = ""
                        deviceValue = ""
                        for k in deviceItemList:
                            Domoticz.Debug(k + " —> "+str(deviceItemList[k]))
                            if k == "key":
                                deviceKey = deviceItemList[k]
                            elif k == "value":
                                deviceValue = deviceItemList[k]
                        if (deviceKey != "") and (deviceValue != ""):
                            if deviceKey == "BSH.Common.Root.SelectedProgram":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                Devices[3].Update(nValue=Devices[3].nValue,sValue=deviceValue.rpartition(".")[2])
                            elif deviceKey == "BSH.Common.Option.Hood.IntensiveLevel":
                                Domoticz.Log(deviceKey+" --> "+str(deviceValue))
                                if Parameters["Mode1"] == self.DEVICE_HOOD:
                                    intensiveLevel = deviceValue.rpartition(".")[2]
                                    if intensiveLevel == "IntensiveStageOff":
                                        Devices[11].Update(nValue=0,sValue="0")
                                    elif intensiveLevel == "IntensiveStage1":
                                        Devices[11].Update(nValue=10,sValue="10")
                                    elif intensiveLevel == "IntensiveStage2":
                                        Devices[11].Update(nValue=20,sValue="20")
                            elif deviceKey == "BSH.Common.Option.Hood.VentingLevel":
                                Domoticz.Log(deviceKey+" --> "+str(deviceValue))
                                if Parameters["Mode1"] == self.DEVICE_HOOD:
                                    ventingLevel = deviceValue.rpartition(".")[2]
                                    if ventingLevel == "FanOff":
                                        Devices[10].Update(nValue=0,sValue="0")
                                    elif ventingLevel == "FanStage01":
                                        Devices[10].Update(nValue=10,sValue="10")
                                    elif ventingLevel == "FanStage02":
                                        Devices[10].Update(nValue=20,sValue="20")
                                    elif ventingLevel == "FanStage03":
                                        Devices[10].Update(nValue=30,sValue="30")
                                    elif ventingLevel == "FanStage04":
                                        Devices[10].Update(nValue=40,sValue="40")
                                    elif ventingLevel == "FanStage05":
                                        Devices[10].Update(nValue=50,sValue="50")
                            elif deviceKey == "BSH.Common.Option.ElapsedProgramTime":
                                Domoticz.Log(deviceKey+" --> "+str(deviceValue))
                                if Parameters["Mode1"] == self.DEVICE_HOOD:
                                    Devices[9].Update(nValue=0,sValue=str(deviceValue), Options={"Custom": "1;sec"})
                            elif deviceKey == "BSH.Common.Option.RemainingProgramTime":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                #Devices[7].Update(nValue=deviceValue,sValue=str(deviceValue)+" sec")
                                Devices[7].Update(nValue=0,sValue=str(deviceValue), Options={"Custom": "1;sec"})
                                if deviceValue > 0:
                                    remainingTime = datetime.datetime.now() + datetime.timedelta(seconds=deviceValue)
                                    Domoticz.Debug("remainingTime: "+str(remainingTime.strftime("%H:%M")))
                                    Devices[8].Update(nValue=Devices[8].nValue,sValue=str(remainingTime.strftime("%H:%M")))
                                    #Devices[8].Update(nValue=Devices[8].nValue,sValue=str(remainingTime.hour),Options={"Custom": str(remainingTime.hour)+"; : "+str(remainingTime.strftime("%M"))})
                            elif deviceKey == "BSH.Common.Option.ProgramProgress": 
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                Devices[6].Update(nValue=deviceValue,sValue=str(deviceValue))
                                if Parameters["Mode1"] == self.DEVICE_DISHWASHER:
                                    if Devices[3].sValue == "PreRinse":
                                        if Parameters["Mode2"] == "True":
                                            Devices[4].Update(nValue=Devices[4].nValue,sValue="Rinse", Image=Images[self.RINSE_ICON].ID)
                                        else:
                                            Devices[4].Update(nValue=Devices[4].nValue,sValue="Rinse")
                                    #elif Devices[3].sValue == "Quick45":
                                        #TODO
                                    #elif Devices[3].sValue == "Glass48":
                                        #TODO
                                    #elif Devices[3].sValue == "Kurz40":
                                        #TODO
                                    #elif Devices[3].sValue == "NightWash":
                                        #TODO
                                    elif Devices[3].sValue == "Eco50":
                                        if deviceValue > 0 and deviceValue < 10:
                                            if Parameters["Mode2"] == "True":
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Rinse", Image=Images[self.RINSE_ICON].ID)
                                            else:
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Rinse")
                                        elif deviceValue >= 10 and deviceValue < 60:
                                            if Parameters["Mode2"] == "True":
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Clean", Image=Images[self.CLEAN_ICON].ID)
                                            else:
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Clean")
                                        elif deviceValue >= 60 and deviceValue < 70:
                                            if Parameters["Mode2"] == "True":
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Shine", Image=Images[self.SHINE_ICON].ID)
                                            else:
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Shine")
                                        else:
                                            if Parameters["Mode2"] == "True":
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Dry", Image=Images[self.DRY_ICON].ID)
                                            else:
                                                Devices[4].Update(nValue=Devices[4].nValue,sValue="Dry")
                                    #elif Devices[3].sValue == "Auto2":
                                        #TODO
                                    #elif Devices[3].sValue == "Intensiv70":
                                        #TODO
                            elif deviceKey == "BSH.Common.Root.ActiveProgram":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                if "." in str(deviceValue):
                                    Devices[3].Update(nValue=Devices[3].nValue,sValue=str(deviceValue).rpartition(".")[2])
                                else:
                                    Devices[3].Update(nValue=Devices[3].nValue,sValue=str(deviceValue))
                            elif deviceKey == "BSH.Common.Status.OperationState":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                #Devices[1].Update(nValue=Devices[1].nValue,sValue=deviceValue.rpartition(".")[2],Options={"Custom": deviceValue.rpartition(".")[2]})
                                Devices[1].Update(nValue=Devices[1].nValue,sValue=deviceValue.rpartition(".")[2])
                            elif deviceKey == "BSH.Common.Setting.PowerState":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                powerstate = deviceValue.rpartition(".")[2]
                                if powerstate == "On":
                                    Devices[2].Update(nValue=1,sValue="On")
                                else:
                                    Devices[2].Update(nValue=0,sValue="Off")
                            elif deviceKey == "BSH.Common.Status.DoorState":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                doorstate = deviceValue.rpartition(".")[2]
                                if doorstate == "Open":
                                    Devices[5].Update(nValue=1,sValue="Open")
                                else:
                                    Devices[5].Update(nValue=0,sValue="Closed")
                            elif deviceKey == "BSH.Common.Event.ProgramFinished":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                Devices[1].Update(nValue=Devices[1].nValue,sValue="")
                                Devices[3].Update(nValue=Devices[3].nValue,sValue="")
                                if Parameters["Mode1"] == self.DEVICE_DISHWASHER:
                                    Devices[4].Update(nValue=Devices[4].nValue,sValue="")
                                Devices[6].Update(nValue=100,sValue=str(100))
                                #Devices[7].Update(nValue=0,sValue="0 sec")
                                Devices[7].Update(nValue=0,sValue="0", Options= {"Custom": "1;sec"})
                                Devices[8].Update(nValue=0,sValue="")
                            elif deviceKey == "Cooking.Oven.Status.CurrentCavityTemperature":
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
                                if Parameters["Mode1"] == self.DEVICE_OVEN:
                                    Domoticz.Debug("Temp: "+str(deviceValue))
                                    Devices[9].Update(nValue=0,sValue=str(deviceValue))
                            else:
                                Domoticz.Log(deviceKey+" —> "+str(deviceValue))
        self.httpClientConn.Send({"Status":"200 OK", "Headers": {"Connection": "keep-alive", "Accept": "Content-Type: text/html; charset=UTF-8"}, "Data": data})

    def onCommand(self, Unit, Command, Level, Hue):
        Domoticz.Log("onCommand called for Unit " + str(Unit) + ": Parameter '" + str(Command) + "', Level: " + str(Level))
        if Parameters["Mode1"] == self.DEVICE_DISHWASHER:
            if str(Command) == "On":
                if homeconnecthelper.setPowerState(self, self.DEVICE_DISHWASHER, str(Command)) == True:
                    Devices[Unit].Update(nValue=1,sValue="On")
            elif str(Command) == "Off":
                if homeconnecthelper.setPowerState(self, self.DEVICE_DISHWASHER, str(Command)) == True:
                    Devices[Unit].Update(nValue=1,sValue="Off")
        elif Parameters["Mode1"] == self.DEVICE_OVEN:
            if str(Command) == "On":
                if homeconnecthelper.setPowerState(self, self.DEVICE_OVEN, str(Command)) == True:
                    Devices[Unit].Update(nValue=1,sValue="On")
            elif str(Command) == "Off":
                if homeconnecthelper.setPowerState(self, self.DEVICE_OVEN, str("Standby")) == True:
                    Devices[Unit].Update(nValue=0,sValue="Off")
        elif Parameters["Mode1"] == self.DEVICE_HOOD:
            if str(Command) == "Set Level" and Unit == 10:
                if Level == 0:
                    if homeconnecthelper.setVentingLevel(self,"FanOff") == True:
                        Devices[10].Update(nValue=0,sValue="0")
                elif Level == 10:
                    if homeconnecthelper.setVentingLevel(self,"FanStage01") == True:
                        Devices[10].Update(nValue=10,sValue="10")
                elif Level == 20:
                    if homeconnecthelper.setVentingLevel(self,"FanStage02") == True:
                        Devices[10].Update(nValue=20,sValue="20")
                elif Level == 30:
                    if homeconnecthelper.setVentingLevel(self,"FanStage03") == True:
                        Devices[10].Update(nValue=30,sValue="30")
                elif Level == 40:
                    if homeconnecthelper.setVentingLevel(self,"FanStage04") == True:
                        Devices[10].Update(nValue=40,sValue="40")
                elif Level == 50:
                    if homeconnecthelper.setVentingLevel(self,"FanStage05") == True:
                        Devices[10].Update(nValue=50,sValue="50")
            elif str(Command) == "Set Level" and Unit == 11:
                if Level == 0:
                    if homeconnecthelper.setIntensiveLevel(self,"IntensiveStageOff") == True:
                        Devices[11].Update(nValue=0,sValue="0")
                elif Level == 10:
                    if homeconnecthelper.setIntensiveLevel(self,"IntensiveStage1") == True:
                        Devices[11].Update(nValue=10,sValue="10")
                elif Level == 20:
                    if homeconnecthelper.setIntensiveLevel(self,"IntensiveStage2") == True:
                        Devices[11].Update(nValue=20,sValue="20")

    def onNotification(self, Name, Subject, Text, Status, Priority, Sound, ImageFile):
        Domoticz.Log("Notification: " + Name + "," + Subject + "," + Text + "," + Status + "," + str(Priority) + "," + Sound + "," + ImageFile)

    def onDisconnect(self, Connection):
        Domoticz.Log("onDisconnect called")

        if (Connection.Name in self.httpServerConns):
            del self.httpServerConns[Connection.Name]

    def onHeartbeat(self):
        Domoticz.Log("onHeartbeat called")

global _plugin
_plugin = BasePlugin()

def onStart():
    global _plugin
    _plugin.onStart()

def onStop():
    global _plugin
    _plugin.onStop()

def onConnect(Connection, Status, Description):
    global _plugin
    _plugin.onConnect(Connection, Status, Description)

def onMessage(Connection, Data):
    global _plugin
    _plugin.onMessage(Connection, Data)

def onCommand(Unit, Command, Level, Hue):
    global _plugin
    _plugin.onCommand(Unit, Command, Level, Hue)

def onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile):
    global _plugin
    _plugin.onNotification(Name, Subject, Text, Status, Priority, Sound, ImageFile)

def onDisconnect(Connection):
    global _plugin
    _plugin.onDisconnect(Connection)

def onHeartbeat():
    global _plugin
    _plugin.onHeartbeat()

    # Generic helper functions
def DumpConfigToLog():
    for x in Parameters:
        if Parameters[x] != "":
            Domoticz.Debug( "'" + x + "':'" + str(Parameters[x]) + "'")
    Domoticz.Debug("Device count: " + str(len(Devices)))
    for x in Devices:
        Domoticz.Debug("Device:           " + str(x) + " - " + str(Devices[x]))
        Domoticz.Debug("Device ID:       '" + str(Devices[x].ID) + "'")
        Domoticz.Debug("Device Name:     '" + Devices[x].Name + "'")
        Domoticz.Debug("Device nValue:    " + str(Devices[x].nValue))
        Domoticz.Debug("Device sValue:   '" + Devices[x].sValue + "'")
        Domoticz.Debug("Device LastLevel: " + str(Devices[x].LastLevel))
    return

def loadIcons(self, Images):
    #Home-Connect Logo
    if self.HOMECONNECT_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.HOMECONNECT_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect Image")
        Domoticz.Image("Home-Connect-Plugin Icons.zip").Create()

    #Dry Logo
    if self.DRY_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.DRY_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect dry Image")
        Domoticz.Image("Home-Connect-Plugin1 Icons.zip").Create()

    #Rinse Logo
    if self.RINSE_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.RINSE_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect rinse Image")
        Domoticz.Image("Home-Connect-Plugin2 Icons.zip").Create()

    #Shine Logo
    if self.SHINE_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.SHINE_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect shine Image")
        Domoticz.Image("Home-Connect-Plugin3 Icons.zip").Create()

    #Finish Logo
    if self.FINISH_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.FINISH_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect finish Image")
        Domoticz.Image("Home-Connect-Plugin4 Icons.zip").Create()

    #Clean Logo
    if self.CLEAN_ICON in Images:
        Domoticz.Debug("ID: "+str(Images[self.CLEAN_ICON].ID))
    else:
        Domoticz.Debug("no Home-Connect clean Image")
        Domoticz.Image("Home-Connect-Plugin5 Icons.zip").Create()

    Domoticz.Log(str(Images))
and file homeconnecthelper.py:

Code: Select all

import Domoticz
import datetime
import requests
import json
from sseclient import SSEClient
from requests.exceptions import HTTPError
import traceback

BASEURL = "https://api.home-connect.com"
HEADER_URLENCODED = {"content-type": "application/x-www-form-urlencoded"}
CLIENT_ID = "EB32287B74E25B85212E25C2A6A3793B48CB2B4361F742101XXXXXXXXXX"
APP_NAME = "Domoticz connection"

"""
Method for checking if a oauth2 token is still valid
 
Parameters
----------
self : BasePlugin
    for getting plugin variables
"""
def isTokenValid(self):
    if datetime.datetime.now() < self.token_expired:
        return True
    return False

"""
Method for refreshing the token after token is invalid (24 hours)

Parameters
----------
self : BasePlugin
    for getting plugin variables

Return values
-------------
True : Token correctly refreshed
False : Token not correctly refreshed
"""
def refreshToken(self):
    url_refresh_token = BASEURL + "/security/oauth/token"
    data_refresh_token = {"refresh_token": self.refresh_token, "grant_type": "refresh_token"}
    response_refresh_token = requests.post(url_refresh_token,data_refresh_token,HEADER_URLENCODED)
    json_refresh_token = json.loads(response_refresh_token.text)
    response_refresh_token.close()
    self.access_token = ""
    self.refresh_token = ""
    for key, value in json_refresh_token.items():
        if key == "access_token":
            self.access_token = value
        if key == "expires_in":
            self.token_expires = datetime.datetime.now() + datetime.timedelta(seconds=value)
        if key == "refresh_token":
            self.refresh_token = value

    if (self.access_token == "") or (self.token_expired < datetime.datetime.now()) or (self.refresh_token == ""):
        return False
    return True

"""
Method for getting the Home-Connect Appliance ID

Parameters
----------
self : BasePlugin
    for getting plugin variables
scope : String
    Devide for wich the haId must be retrieved

Return
------
haId : Retrieved String or None
"""
def gethaId(self, scope, enumber):
    url_homeappliances = BASEURL + "/api/homeappliances"
    header = {"Accept": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    response_homeappliances = requests.get(url_homeappliances, headers=header)
    Domoticz.Debug(response_homeappliances.text)
    json_homeappliances = json.loads(response_homeappliances.text)
    response_homeappliances.close()

    if "data" in json_homeappliances:
        homeappliances_data = json_homeappliances["data"]
        for item in homeappliances_data:
            if "haId" in item and "type" in item and "enumber" in item:
                haId = item["haId"]
                scopeType = item["type"]
                en = item["enumber"]

                if scopeType == scope or (scopeType + "-Monitor") == scope:
                    if enumber == en:
                        Domoticz.Log("Enumber: " + enumber)
                        return haId

    return None

def getActiveProgram(self,haId):
    Domoticz.Debug("getActiveProgram")
    url_getActiveProgram = BASEURL + "/api/homeappliances/" + (haId or "") + "/programs/active"
    header = {"Accept": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    response_getActiveProgram = requests.get(url_getActiveProgram, headers=header)
    json_items = json.loads(str(response_getActiveProgram.text))
    response_getActiveProgram.close()
    Domoticz.Debug(response_getActiveProgram.text)
    for key_item, value_item in json_items.items():
        Domoticz.Debug(str(key_item)+" --> "+str(value_item))
        for data in value_item:
            if data == "key":
                Domoticz.Debug(data+" --> "+str(value_item[data]))
                return str(value_item[data])
    return ""

def getDoorState(self,haId):
    Domoticz.Debug("getDoorState")
    url_getDoorState = BASEURL + "/api/homeappliances/" + (haId or "") + "/status/BSH.Common.Status.DoorState"
    header = {"Accept": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    response_getDoorState = requests.get(url_getDoorState, headers=header)
    json_items = json.loads(str(response_getDoorState.text))
    response_getDoorState.close()
    Domoticz.Debug(response_getDoorState.text)
    for key_item, value_item in json_items.items():
        Domoticz.Debug(str(key_item)+" --> "+str(value_item))
        for data in value_item:
            if data == "value":
                Domoticz.Debug(data+" --> "+str(value_item[data]))
                return str(value_item[data])

def getPowerState(self, haId):
    Domoticz.Debug("getPowerState")
    if self.haId is not None:
        url_setPowerState = BASEURL + "/api/homeappliances/" + self.haId + "/settings/BSH.Common.Setting.PowerState"
    else:
        Domoticz.Log("Home Appliance ID is not available.")
        return

    header = {"Accept": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    response_getPowerState = requests.get(url_getPowerState, headers=header)
    json_items = json.loads(str(response_getPowerState.text))
    response_getPowerState.close()
    Domoticz.Debug(response_getPowerState.text)

    for key_item, value_item in json_items.items():
        Domoticz.Debug(str(key_item)+" --> "+str(value_item))
        for data in value_item:
            if data == "value":
                Domoticz.Debug(data+" --> "+str(value_item[data]))
                return str(value_item[data])
def setVentingLevel(self,level):
    Domoticz.Debug("setVentingLevel")
    url_setVentingLevel = BASEURL + "/api/homeappliances/"+ self.haId + "/programs/active/options/Cooking.Common.Option.Hood.VentingLevel"
    header = {"Content-Type": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    data = json.dumps({
      'data': {
        'key': 'Cooking.Common.Option.Hood.VentingLevel',
        'value': 'Cooking.Hood.EnumType.Stage.'+level,
        'type': 'Cooking.Hood.EnumType.Stage',
        'constrains': {
           'allowedvalues': ['Cooking.Hood.EnumType.Stage.FanOff', 'Cooking.Hood.EnumType.Stage.FanStage01', 'Cooking.Hood.EnumType.Stage.FanStage02', 'Cooking.Hood.EnumType.Stage.FanStage03', 'Cooking.Hood.EnumType.Stage.FanStage04', 'Cooking.Hood.EnumType.Stage.FanStage05']
        }
      }
    })
    response = requests.put(url_setVentingLevel, headers=header, data=data)
    Domoticz.Log(str(response.status_code))
    if str(response.status_code) == "204":
        response.close()
        return True
    response.close()
    return False 

def setIntensiveLevel(self,level):
    Domoticz.Debug("setIntensiveLevel")
    url_setIntentsiveLevel = BASEURL + "/api/homeappliances/"+ self.haId + "/programs/active/options/Cooking.Common.Option.Hood.IntensiveLevel"
    header = {"Content-Type": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    data = json.dumps({
      'data': {
        'key': 'Cooking.Common.Option.Hood.IntensiveLevel',
        'value': 'Cooking.Hood.EnumType.IntensiveStage.'+level,
        'type': 'Cooking.Hood.EnumType.IntensiveStage',
        'constrains': {
           'allowedvalues': ['Cooking.Hood.EnumType.IntensiveStage.IntensiveStageOff', 'Cooking.Hood.EnumType.IntensiveStage.IntensiveStage1', 'Cooking.Hood.EnumType.IntensiveStage.IntensiveStage2']
        }
      }
    })
    response = requests.put(url_setIntensiveLevel, headers=header, data=data)
    Domoticz.Log(str(response.status_code))
    if str(response.status_code) == "204":
        response.close()
        return True
    response.close()
    return False 

def setPowerState(self,devicetype,state):
    Domoticz.Debug("setPowerState")
    url_setPowerState = BASEURL + "/api/homeappliances/" + self.haId + "/settings/BSH.Common.Setting.PowerState"
    header = {"Content-Type": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    data = None 
    if state == "On":
        l1 = [self.DEVICE_DISHWASHER, self.DEVICE_HOOD]
        if devicetype in l1:
            data = json.dumps({
              'data': {
                'key': 'BSH.Common.Setting.PowerState',
                'value': 'BSH.Common.EnumType.PowerState.On',
                'type': 'BSH.Common.EnumType.PowerState',
                'constraints': {
                  'allowedvalues': ['BSH.Common.EnumType.Powerstate.On', 'BSH.Common.EnumType.PowerState.Off']
                }
              }
            })
        elif devicetype == self.DEVICE_OVEN:
            data = json.dumps({
              'data': {
                'key': 'BSH.Common.Setting.PowerState',
                'value': 'BSH.Common.EnumType.PowerState.On',
                'type': 'BSH.Common.EnumType.PowerState',
                'constraints': {
                  'allowedvalues': ['BSH.Common.EnumType.Powerstate.On', 'BSH.Common.EnumType.PowerState.Standby']
                }
              }
            })
    elif state == "Off":
        data = json.dumps({
          'data': {
            'key': 'BSH.Common.Setting.PowerState',
            'value': 'BSH.Common.EnumType.PowerState.Off',
            'type': 'BSH.Common.EnumType.PowerState',
            'constraints': {
              'allowedvalues': ['BSH.Common.EnumType.Powerstate.On', 'BSH.Common.EnumType.PowerState.Off']
            }
          }
        })
    elif state == "Standby":
        data = json.dumps({
          'data': {
            'key': 'BSH.Common.Setting.PowerState',
            'value': 'BSH.Common.EnumType.PowerState.Standby',
            'type': 'BSH.Common.EnumType.PowerState',
            'constraints': {
              'allowedvalues': ['BSH.Common.EnumType.Powerstate.On', 'BSH.Common.EnumType.PowerState.Standby']
            }
          }
        })
 
    response = requests.put(url_setPowerState, headers=header, data=data)
    Domoticz.Debug(str(response.status_code))
    if str(response.status_code) == "204":
        response.close()
        return True
    response.close()
    return False

def getOperationState(self,haId):
    Domoticz.Debug("getOperationState")
    url_getOperationState = BASEURL + "/api/homeappliances/" + (haId or "") + "/status/BSH.Common.Status.OperationState"
    header = {"Accept": "application/vnd.bsh.sdk.v1+json", "Authorization": "Bearer " + self.access_token}
    response_getOperationState = requests.get(url_getOperationState, headers=header)
    json_items = json.loads(str(response_getOperationState.text))
    response_getOperationState.close()
    Domoticz.Debug(response_getOperationState.text)
    for key_item, value_item in json_items.items():
        Domoticz.Debug(str(key_item)+" --> "+str(value_item))
        for data in value_item:
            if data == "value":
                Domoticz.Debug(data+" --> "+str(value_item[data]))
                return str(value_item[data])

"""
Method for device authorization and getting a token

Parameters
----------
self : BasePlugin
    for getting plugin variables
username : String
    Home-Connect username
password : String
    Home-Connect password
ascope : String
    Scope for which authorization is requested

Return
------
None
"""
def connectHomeConnect(self,username,password,ascope):
    #'Request authorization to access home appliance" and "Return device code, user code, verification uri, ..."
    url_authorization = BASEURL + "/security/oauth/device_authorization"
    scope = "IdentifyAppliance "+ascope+"-Monitor "+ascope+"-Settings"
    data_authorization = {"client_id": self.clientid, "scope": scope}
    response_authorization = requests.post(url_authorization,data_authorization,HEADER_URLENCODED)
    Domoticz.Debug(response_authorization.text)
    json_data_authorization = json.loads(response_authorization.text)
    response_authorization.close()
    device_code = ""
    verification_uri_complete = ""
    user_code = ""
    for key, value in json_data_authorization.items():
        Domoticz.Debug(key + " --> " + str(value))
        if key == "device_code":
            device_code = value
        if key == "verification_uri_complete":
            verification_uri_complete = value
        if key == "user_code":
            user_code = value
    Domoticz.Log("device_code: "+device_code)
    Domoticz.Log("verification_uri_complete: "+verification_uri_complete)
    Domoticz.Debug("user_code: "+user_code)

    #Enter user code, log in and authorize access
    authorized = False
    
    if(device_code != "") and (verification_uri_complete != "") and (user_code != ""):
        session = requests.Session()

        #log in part
        payload_login = {"client_id": self.clientid, "user_code": user_code, "email": username, "password": password}
        url_login = BASEURL + "/security/oauth/device_login"
        response_login = session.post(url_login, data=payload_login)
        Domoticz.Debug(response_login.text)
        sessionid = response_login.text[response_login.text.find("session_id\" value=\"")+len("session_id\" value=\""):]
        sessionid = sessionid[:sessionid.find("\"")]
        Domoticz.Log("sessionid: "+sessionid)
        response_login.close()
    
        #authorize part
        #payload_grant = {"session_id": sessionid, "client_id": self.clientid, "user_code": user_code, "email": username, "app_name": APP_NAME, "scope": scope}
        payload_grant = {"user_code": user_code, "session_id": sessionid, "input_aborted": "false", "app_name": APP_NAME, "accept_language": "nl", "client_id": self.clientid, "email": username, "scope": scope, "region": "EU", "environment": "PRD"}
        url_grant = BASEURL + "/security/oauth/device_grant"
        response_grant = session.post(url_grant, data=payload_grant)
        Domoticz.Debug("response_grant: "+response_grant.text)
        authorized = True
        response_grant.close()
    
    #Token request
    if authorized:
        Domoticz.Log("Device \"" + device_code + "\" is authorized by Home-Connect.")
        url_tokenrequest = BASEURL + "/security/oauth/token"
        payload_tokenrequest = {"grant_type": "device_code", "device_code": device_code, "client_id": self.clientid}
        response_tokenrequest = requests.post(url_tokenrequest,payload_tokenrequest, HEADER_URLENCODED)
        Domoticz.Debug("response_tokenrequest: "+response_tokenrequest.text)
        json_tokenrequest = json.loads(response_tokenrequest.text)
        response_tokenrequest.close()
        for key, value in json_tokenrequest.items():
            Domoticz.Debug(key + " --> " + str(value))
            if key == "access_token":
                self.access_token = value
            if key == "expires_in":
                self.token_expired = datetime.datetime.now() + datetime.timedelta(seconds=value) #default 86400 seconds (=24h)
            if key == "refresh_token":
                self.refresh_token = value
        Domoticz.Log("Device \"" + device_code + "\" has token: " + self.access_token)
    else:
        Domoticz.Error("Device \"" + device_code + "\" is not authorized by Home_Connect.")

    return
file "homeconnectSSE_dishwasher.sh" code:

Code: Select all

#!/bin/sh

### BEGIN INIT INFO
# Provides:          myservice
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Put a short description of the service here
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
PYTHON_PATH=/usr/bin/python3
DIR=/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin
DAEMON=/home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin/homeconnectSSE.py
DEVICE_NAME=Dishwasher
DOMOTICZ_IP=IP address of Domoticz
DOMOTICZ_PORT=Same IP address as configured in Domoticz but NOT the port of Domoticz itself!!
DAEMON_NAME=homeconnectSSE_$DEVICE_NAME
DAEMON_LOG=/home/pi/domoticz/log/$DAEMON_NAME.log
# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=pi

# Add any command line options for your daemon here
DAEMON_OPTS="$DAEMON $DEVICE_NAME $DOMOTICZ_IP $DOMOTICZ_PORT $DAEMON_LOG"

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --exec $PYTHON_PATH -- $DAEMON_OPTS
    log_end_msg $?
}

do_stop () {
    log_daemon_msg "Stopping system $DAEMON_NAME daemon"
    start-stop-daemon --stop --pidfile $PIDFILE --retry 10
    log_end_msg $?
}

case "$1" in
    start|stop)
        do_"$1"
        ;;
    restart|reload|force-reload)
        do_stop
        do_start
        ;;
    status)
        status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $?
        ;;
    *)
        echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}"
        exit 1
        ;;
esac

exit 0

After this:
On Raspberry PI:
Go to folder /home/pi/domoticz/plugins/Domoticz-Home-Connect-Plugin
then:
sudo cp homeconnectSSE_DEVICENAME!!.sh /etc/init.d
then
sudo update-rc.d homeconnectSSE_DEVICENAME!!.sh defaults
then
sudo service homeconnectSSE_DEVICENAME!!.sh start
then
sudo service domoticz.sh restart
then
sudo service homeconnectSSE_dishwasher.sh restart

I have tested the dishwasher and it works, devices are being created now, I have no more error on start up, or error of api token.
But now I get this message:
2023-06-20 16:10:59.472 Siemens Home Connect: haId:
2023-06-20 16:10:59.660 Siemens Home Connect: Home Appliance ID is not available.

It seems I don't get the haID (HomeAppliance ID).
Probably because of SingleKeyId...

Anybody a sollution for this?