Ankündigung

Einklappen
Keine Ankündigung bisher.

Interesse an HomeConnect Plugin?

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    #61
    OK. kein Stress.
    kämpfe zurzeit an mehreren Fronten mit Software-Tücken.
    Da wird mal wieder deutlich, wie sorgfältig Software entwickelt wird, aber auch, wie anfällig solche Systeme sind.

    Kommentar


      #62
      Hallo psilo ,

      bist du in der dunklen Jahreszeit weiter gekommen?

      Viele Grüße,
      Hendrik

      Kommentar


        #63
        Hi,

        an alle die hier vieleicht was tun möchten - ich habe mal die OAuth-Identifizierung durchgespielt, mit folgendem Code-Snippet bekommt man einen access/refresh-Token. Alles "pure-requests".

        Die Daten im Kopf entsprechend den Angaben in der Home-Connect-Developer Konsole eintragen. Ich hatte zum testen als Redirect-URL "https://www.smarthomeng.de" angegeben. Die Redirect-URL muss beim erstellen der Applikation in der Cloud von Anfang an korrekt sein. Nachträglich ändern geht schief da diese irgendwie in Client-ID und Client-Secret "gehasht" wird. Beim Ändern wird nicht neu berechnet, d.h. ClientId und ClientSecret passen nicht zur redirect-URI.

        Ich habe den Code noch um eine Funktion für Token-Refresh ergänzt.

        Vielleicht kann es ja jemand brauchen

        Code:
        import json
        import requests
        import urllib
        import uuid
        import time
        
        ######################################
        # Your Information from HC-Cloud
        ######################################
        hc_ClientId = '<YOUR_CLIENT_ID>'
        hc_email = '<YOUR_MAIL_ADRESS>'
        hc_pwd = '<YOUR_PASSWORD>'
        hc_Scope = '<YOUR_SCOPE>' # -> "IdentifyAppliance Monitor Control Images Settings" for all
        hc_ClientSecret = '<YOUR_CLIENT_SECRET>'
        hc_redirect_URI = '<YOUR_REDIRECT_URL>
        
        
        def getToken():
            myHeader={
                        'Host'              : 'api.home-connect.com',
                        'User-Agent'        : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0',
                        'Accept'            : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
                        'Accept-Language'   : 'de,en-US;q=0.7,en;q=0.3',
                        'Accept-Encoding'   : 'gzip, deflate, br',
                        'Content-Type'      : 'application/x-www-form-urlencoded',
                        'Host'              : 'api.home-connect.com'
                    }
        
        
            # Login to get a Code for getting a Token
        
            myData = {'client_id'       : hc_ClientId,
                      'redirect_uri'    : hc_redirect_URI,
                      'response_type'   : 'code',
                      'scope'           : hc_Scope,
                      'state'           : uuid.uuid4().hex
                      }
            postfields = urllib.parse.urlencode(myData)
            mySession = requests.session()
            myResponse = mySession.get('https://api.home-connect.com/security/oauth/authorize',params=postfields,headers=myHeader)
        
            if myResponse.status_code != 200:
                 print ('cold not get Login-Form : ' + myResponse.status_code)
        
            myLines = (myResponse.content.decode()).split("\n")
            for myString in myLines:
                if 'hidden' in myString:
                    myArray = myString.split(" ")
                    if 'name="sessionId"' in myArray:
                        mySessionId=myArray[(myArray.index('name="sessionId"')+1)].replace("/>","").split("=")[1].replace('"','')
                    if 'name="sessionData"' in myArray:
                        mySessionData=myArray[(myArray.index('name="sessionData"')+1)].replace("/>","").split('"')[1]
                    if 'name="client_id"' in myArray:
                        myClientId=myArray[(myArray.index('name="client_id"')+1)].replace("/>","").split("=")[1].replace('"','')
                    if 'name="region"' in myArray:
                        myRegion=myArray[(myArray.index('name="region"')+1)].replace("/>","").split("=")[1].replace('"','')
                    if 'name="environment"' in myArray:
                        myEnvironment=myArray[(myArray.index('name="environment"')+1)].replace("/>","").split("=")[1].replace('"','')
        
        
            myData = {
                        'sessionId'         : mySessionId,
                        'sessionData'       : mySessionData,
                        'aborted'           : False,
                        'client_id'         : myClientId,
                        'accept_language'   : 'de',
                        'region'            : myRegion,
                        'environment'       : myEnvironment,
                        'email'             : hc_email,
                        'password'          : hc_pwd
                     }
            postfields = urllib.parse.urlencode(myData)
            myResponse = mySession.post('https://api.home-connect.com/security/oauth/login',data=postfields,headers=myHeader)
        
            if myResponse.status_code != 200:
                 print ('cold not Login : ' + str(myResponse.status_code))
        
            myData = {
                        'sessionId'         : mySessionId,
                        'aborted'           : False,
                        'accept_language'   : 'de',
                        'client_id'         : myClientId,
                        'email'             : hc_email,
                        'region'            : myRegion,
                        'environment'       : myEnvironment,
                        'scope'             : hc_Scope
                     }
            postfields = urllib.parse.urlencode(myData)
        
            myResponse = requests.post('https://api.home-connect.com/security/oauth/grant',data=postfields,headers=myHeader,allow_redirects=False)
        
            if myResponse.status_code != 302:
                 print ('cold not get grant-access : ' + str(myResponse.status_code))
        
            myLocation = urllib.parse.unquote(myResponse.headers['Location'])
        
            myCode          = myLocation.split("?")[1].split("&")[0].split(("="))[1]
            my_grant_type   = myLocation.split("?")[1].split("&")[2].split(("="))[1]
            my_state        = myLocation.split("?")[1].split("&")[1].split(("="))[1]
        
            # Now get the Token
            myData = {
                        'client_id'         : myClientId,
                        'client_secret'     : hc_ClientSecret,
                        'redirect_uri'      : hc_redirect_URI,
                        'grant_type'        : my_grant_type,
                        'code'              : myCode
                     }
            postfields = urllib.parse.urlencode(myData)
            myResponse = requests.post('https://api.home-connect.com/security/oauth/token',data=postfields,headers=myHeader,allow_redirects=False)
        
            if myResponse.status_code != 200:
                 print ('cold not get access-Token : ' + str(myResponse.status_code))
            else:
                myBearerDict = json.loads(myResponse.content.decode())
                myAccessToken  = myBearerDict['access_token']
                myRefreshToken = myBearerDict['refresh_token']
                myExperition   = myBearerDict['expires_in']
                myIdToken      = myBearerDict['id_token']
                myTokenType    = myBearerDict['token_type']
                print ('Got Access/Refresh-Token - Acces-Token : ' + myAccessToken )
                return myAccessToken,myRefreshToken
        
        def get_refresh_Token(refresh_Token):
            #grant_type=refresh_token&refresh_token={refresh_token}&client_secret={client_secret}
            myHeader={
                    'Host'              : 'api.home-connect.com',
                    'User-Agent'        : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0',
                    'Accept'            : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
                    'Accept-Language'   : 'de,en-US;q=0.7,en;q=0.3',
                    'Accept-Encoding'   : 'gzip, deflate, br',
                    'Content-Type'      : 'application/x-www-form-urlencoded',
                    'Host'              : 'api.home-connect.com'
                }
            myData = {
                        'grant_type'        : 'refresh_token',
                        'refresh_token'     : refresh_Token,
                        'client_secret'      : hc_ClientSecret
                     }
            postfields = urllib.parse.urlencode(myData)
            myResponse = requests.post('https://api.home-connect.com/security/oauth/token',data=postfields,headers=myHeader,allow_redirects=False)
            if myResponse.status_code != 200:
                 print ('cold not get new access-Token : ' + str(myResponse.status_code))
            else:
                myBearerDict = json.loads(myResponse.content.decode())
                myAccessToken  = myBearerDict['access_token']
                myRefreshToken = myBearerDict['refresh_token']
                return myAccessToken, myRefreshToken
        
        if __name__ == '__main__':
            myToken, myRefreshToken = getToken()
            time.sleep(10)
            myNewToken, myNewRefreshToken = get_refresh_Token(myRefreshToken)
            print ('new Token : ' + myNewToken)
        Viele Grüsse
        Andre
        Zuletzt geändert von AndreK; 31.01.2022, 22:20. Grund: Code für Refresh-Token ergänzt

        Kommentar


          #64
          Moin,

          ganz fresh: https://github.com/osresearch/hcpy/tree/singlekey
          Damit ist der Zugriff auf ein BSH "Home-Connect" Geschirrspüler ohne dauerhafte Cloud-Verbindung möglich.

          Zur Erstellung des initialen "config.json" benötigt man User+Pass+Cloud, und anschließend eben nicht mehr :-)
          Ein Beispiel-Script schiebt den Status dann via MQTT weiter.

          Ein kleiner Vorgeschmack, welche Infos sichtbar sind.

          Code:
          2023-03-13 19:08:43.443847 {'DoorState': 'Open', 'ProgramFinished': 'Off'}
          publish homeconnect/dishwasher {"state": "Inactive", "door": "Open", "remaining": "0:00", "power": false, "lowwaterpressure": false, "aquastop": false, "error": false, "remainingseconds": 0}
          2023-03-13 19:08:48.252266 {'AllowBackendConnection': True, 'BackendConnected': False, 'SoftwareUpdateAvailable': 'Off', 'ActiveProgram': 0, 'SelectedProgram': 8196, '515': False, '516': False, 'RemoteControlStartAllowed': False, 'AllowFlexStart': False, 'ApplianceTime': '19:08:47', 'RemoteControlActive': True, '524': False, 'AquaStopOccured': 'Off', 'DoorState': 'Open', 'CustomerEnergyManagerPaired': False, '532': False, 'Language': 'De', '534': False, 'PowerState': 'On', 'ProgramFinished': 'Off', 'ProgramProgress': 0, 'LowWaterPressure': 'Off', 'RemainingProgramTime': 12900, 'ProgramAborted': 'Off', 'SynchronizeWithTimeServer': True, 'OperationState': 'Ready', 'CustomerServiceConnectionAllowed': False, 'StartInRelative': 0}
          publish homeconnect/dishwasher {"state": "Ready", "door": "Open", "remaining": "3:35", "power": true, "lowwaterpressure": false, "aquastop": false, "error": false, "remainingseconds": 12900}
          2023-03-13 19:08:48.385299 {'CustomerServiceRequest': 'Off', 'EnergyForecast': 36, 'WaterForecast': 48, 'FlexStart': 'Disabled', 'FlexStartInRelative': 0, 'TimeFormat': '24Hours', '587': True, '588': 100, '589': 0, '590': '#000000', '591': 0, 'SoftwareUpdateTransactionID': 0, 'SoftwareDownloadAvailable': 'Off', 'SoftwareUpdateSuccessful': 'Off', 'ProgramPhase': 'None', '4097': 255, '4098': 255, '4099': 0, '4352': 0, 'RelAbsOperatingTime': 'Absolute', 'RinseAid': 'R03', 'SensitivityTurbidity': 'Standard', 'ExtraDry': True, 'HotWater': 'HotWater', 'EcoPrognosis': True, '4359': 1, '4360': True, '4361': True}
          2023-03-13 19:08:48.501947 {'TimeLight': 'On', 'EcoAsDefault': 'LastProgram', 'SoundLevelSignal': 'Low', 'SoundLevelKey': 'Low', 'BrandLogo': False, 'WaterHardness': 'H04', '4368': False, '4376': False, '4377': True, '4378': True, '4379': True, '4381': 1, 'InternalError': 'Off', 'CheckFilterSystem': 'Off', 'DrainingNotPossible': 'Off', 'DrainPumpBlocked': 'Off', 'WaterheaterCalcified': 'Off', 'LowVoltage': 'Off', 'SaltLack': 'Off', 'RinseAidLack': 'Off', 'SaltNearlyEmpty': 'Off', 'RinseAidNearlyEmpty': 'Off', 'MachineCareReminder': 'Off', '4629': 0, '4630': 0, '4631': 0, '4632': 0, '4633': 0, '4640': 0, '4641': 0, '5120': False, '5121': False, '5122': False}
          publish homeconnect/dishwasher {"state": "Ready", "door": "Open", "remaining": "3:35", "power": true, "lowwaterpressure": false, "aquastop": false, "error": false, "remainingseconds": 12900}
          2023-03-13 19:08:48.584275 {'5123': False, '5124': False, '5125': False, 'IntensivZone': False, 'VarioSpeedPlus': False, 'BrillianceDry': False, '5129': False, '5130': False, '5131': False, '5132': False, '5133': False, '5134': False, '5135': False}
          2023-03-13 19:08:49.648937 {'AllowFlexStart': False, 'FlexStartInRelative': 0, '588': 100, '590': '#000000', 'SoftwareUpdateTransactionID': 0, '4099': 0}
          2023-03-13 19:09:00.343002 {'PowerState': 'Off', 'OperationState': 'Inactive'}
          publish homeconnect/dishwasher {"state": "Inactive", "door": "Open", "remaining": "3:35", "power": false, "lowwaterpressure": false, "aquastop": false, "error": false, "remainingseconds": 12900}
          2023-03-13 19:09:03.526100 {'DoorState': 'Closed'}
          publish homeconnect/dishwasher {"state": "Inactive", "door": "Closed", "remaining": "3:35", "power": false, "lowwaterpressure": false, "aquastop": false, "error": false, "remainingseconds": 12900}
          Aktuell wird nur die letzte Zeile via MQTT ausgegeben..

          Kommentar


            #65
            Gibt es zum Thema eigentlich was neues? Ich habe hier einen Geschirrspüler den ich integrieren will und mir ist nicht klar ob es nun ein funktionsfähiges Plugin gibt oder nicht...?

            Kommentar


              #66
              Also, das ganze ohne cloud zwang wäre nice, hätte dann auch nen geschirrspüler zur integration

              Ich glaube bei der initialen idee bzw plugin war die cloud Authentifizierung der knackpunkt ..

              Kommentar


                #67
                von meiner Seite nicht. Der "need" ist allerdings auch nicht so groß, da ich ja nur eine Kaffeemaschine habe

                Kommentar


                  #68
                  Bei gibt es 3 Geräte, die integriert werden könnten. (Waschmaschine, &rockner, Geschirrspüler)
                  Der Geschirrspüler wäre am interessantesten, da ich durch die Einbausituation keine Möglichkeit habe den Betrieb und die Restlaufzeit zu sehen, ohne die Tür zu öffnen.
                  Viele Grüße
                  Martin

                  There is no cloud. It's only someone else's computer.

                  Kommentar


                    #69
                    Zitat von bmx Beitrag anzeigen
                    Gibt es zum Thema eigentlich was neues? Ich habe hier einen Geschirrspüler den ich integrieren will und mir ist nicht klar ob es nun ein funktionsfähiges Plugin gibt oder nicht...?
                    Ein Plug-in kenne ich nicht, jedoch läuft das Python-Script als Service und teilt sich fleißig per MQTT mit; siehe https://github.com/osresearch/hcpy/b...glekey/hc2mqtt

                    Hatte noch die "topics" erweitert:
                    Code:
                    topics = {
                        "OperationState": "state",
                        "DoorState": "door",
                        "RemainingProgramTime": "remaining",
                        "PowerState": "power",
                        "LowWaterPressure": "lowwaterpressure",
                        "AquaStopOccured": "aquastop",
                        "InternalError": "errorINTERNAL",
                        "FatalErrorOccured": "errorFATAL",
                        "CustomerServiceRequest":"errorCSR",
                        "LowVoltage":"errorLowVoltage",
                        "ProgramAborted":"EventProgramAborted",
                        "ProgramFinished":"EventProgramFinished",
                        "FlexStart":"StatusFlexStart",
                        "RemoteControlStartAllowed":"RemoteControlStartAllowed",
                        "WiFiSignalStrength":"WiFiSignalStrength",
                        "CheckFilterSystem":"CheckFilterSystem",
                        "DrainPumpBlocked":"DrainPumpBlocked",
                        "DrainingNotPossible":"DrainingNotPossible",
                        "MachineCareReminder":"MachineCareReminder",
                        "RinseAidLack":"RinseAidLack",
                        "RinseAidNearlyEmpty":"RinseAidNearlyEmpty",
                        "SaltLack":"SaltLack",
                        "SaltNearlyEmpty":"SaltNearlyEmpty",
                        "WaterheaterCalcified":"WaterheaterCalcified",
                        "ProgramPhase":"ProgramPhase"
                    }
                    
                    ​
                    Ich habe nach kurzer Zeit die WLAN Funktion meines Geschirrspülers wieder ausgestellt, da die WLAN Verbindung nicht stabil war - zudem war der Mehrwert sehr gering für uns; da unser Geschirrspüler die Restzeit auf den Boden projiziert.
                    Zuletzt geändert von KHome; 19.09.2023, 21:27.

                    Kommentar


                      #70
                      In dem Script haben sie offenbar den Login hinbekommen: https://github.com/osresearch/hcpy/b...lekey/hc-login

                      Kommentar


                        #71
                        Zitat von psilo Beitrag anzeigen
                        In dem Script haben sie offenbar den Login hinbekommen: https://github.com/osresearch/hcpy/b...lekey/hc-login
                        Benutzt von euch jemand dieses Skript?

                        Hatte es erfolgreich am Laufen, bekomme neuerdings aber nur noch "Connection reset by peer". Hat hier Siemens evtl. ein FW-Update nachgeschoben, das die Verbindung ablehnt? Kann sonst keinen Fehler verbinden, habe auch schon Gerät neu gestartet und Benutzerdaten neu generiert.

                        Kommentar


                          #72
                          Benutzt von euch jemand dieses Skript?​
                          Bisher leider noch nicht getestet. Liegt im Todo Stapel.

                          Kommentar


                            #73
                            Zitat von blobo Beitrag anzeigen
                            neuerdings aber nur noch "Connection reset by peer".
                            Probier mal folgendes angehängte Script mit PyCharm aus und prüfe, ob folgendes eingestellt ist:
                            Code:
                            {'AllowBackendConnection': True,
                            Ich habe über die Siemens-App die Backend Connection aktiv gelassen, jedoch den Internetzugriff über Kindersicherung der FritzBox unterbunden.

                            Angehängte Dateien

                            Kommentar


                              #74
                              Zitat von KHome Beitrag anzeigen

                              Probier mal folgendes angehängte Script mit PyCharm aus und prüfe, ob folgendes eingestellt ist:
                              Was ist denn - bis auf die integrierte Config - der Unterschied zwischen dieser Versionen und des original hcpy?

                              Das ursprüngliche Skript läuft auf einmal ohne weiteres Zutun wieder - keine Ahnung was da los war.
                              AllowBackendConnection ist gesetzt - abgesehen davon würde ich wohl auch nicht mehr draufkommen wenn das deaktiviert wäre, oder?
                              Ich nehme mal an, dass die Cloudanbindung dasselbe Websocket-Interface benutzt wie auch hcpy - d.h. "Backend" aus = cloud und lokal aus?

                              Kommentar


                                #75
                                Zitat von blobo Beitrag anzeigen
                                Was ist denn - bis auf die integrierte Config - der Unterschied zwischen dieser Versionen und des original hcpy?
                                In der Datei "HCDevice.py" gibt es noch weitere Anpassungen
                                Code:
                                                self.get("/ci/authentication", version=2, data={"nonce": token}) ### do authentication
                                                self.get("/ci/info", version=2)  # clothes washer - why do i need this?
                                                #self.get("/iz/info")  # dish washer
                                                self.get("/ci/tzInfo", version=2)  ###get time
                                                #self.get("/ni/info")
                                                ###self.get("/ni/config", data={"interfaceID": 0}) ### get network data, dont need that
                                                self.get("/ei/deviceReady", version=2, action="NOTIFY")
                                                self.get("/ro/allDescriptionChanges")
                                                #self.get("/ro/allDescriptionChanges")
                                                self.get("/ro/allMandatoryValues")​
                                ​

                                AllowBackendConnection ist gesetzt - abgesehen davon würde ich wohl auch nicht mehr draufkommen wenn das deaktiviert wäre, oder?
                                Ich nehme mal an, dass die Cloudanbindung dasselbe Websocket-Interface benutzt wie auch hcpy - d.h. "Backend" aus = cloud und lokal aus?​
                                AllowBackend ist nach meinem Verständnis die Verbindung zu den Servern von BSH und hat theoretisch nichts mit dem lokalen Zugriff zu tun. Um das auszuschließen - und um die gleiche Umgebung wie bei mir abzuprüfen - hatte ich diese Idee.


                                Das ursprüngliche Skript läuft auf einmal ohne weiteres Zutun wieder - keine Ahnung was da los war.
                                😏 - Gut das es wieder funktioniert.
                                Um die Analyse (falls wieder notwendig) tiefer zu betreiben, kann man in der Datei "HCDevice.py" noch Debug-Nachrichten aktivieren
                                Code:
                                self.debug = True​

                                Kommentar

                                Lädt...
                                X