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?