Feature Request: Switchbot Tastendrückroboter einbinden

Antworten
sonnencorsa
Beiträge: 66
Registriert: Mi Jul 07, 2021 11:55 am

Feature Request: Switchbot Tastendrückroboter einbinden

Beitrag von sonnencorsa »

Hallo zusammen,

da IFTTT kürzlich die Webhooks kostenpflichtig gemacht hat, kann ich unseren Tastendrückroboter ("Switchbot Bot") nicht mehr automatisiert über die OpenWB steuern. Der Switchbot ist im Prinzip ein kleiner Kasten mit einem Hebel, welcher einen Knopf an unserer Wärmepumpe drückt, um die Warmwasserzubereitung einzuschalten, wenn genug Überschuss da ist. Steuerbar ist das Ganze über eine Cloud-App oder (bis vorgestern) über IFTTT-Webhooks. Bei letzterem ruft man eine URL auf und der Bot drückt den Knopf, perfekt um den Switchbot in SmartHome 2.0 einzubinden.

Nun verfügt der Switchbot aber auch über eine gut dokumentierte API mit Beispielcode usw. Findet sich vielleicht jemand, der den Switchbot direkt über Smarthome 2.0 steuerbar machen könnte? Also quasi um den den "Umweg" IFTTT zu umgehen?

Hier die API: https://github.com/OpenWonderLabs/SwitchBotAPI

Ich habe mich dort bereits ein wenig eingelesen, folgender Python 3-Code müsste, sofern ich das richtig verstanden habe, in Smarthome 2.0 integriert werden (und zusätzlich halt die Änderungen an der Einstellungsseite, damit man token und secret etc. eingeben kann):

Authentifizerung (token und secret kann ich (via PN) gerne mitteilen):

Code: Alles auswählen

import json
import time
import hashlib
import hmac
import base64
import uuid

# Declare empty header dictionary
apiHeader = {}
# open token
token = '' # copy and paste from the SwitchBot app V6.14 or later
# secret key
secret = '' # copy and paste from the SwitchBot app V6.14 or later
nonce = uuid.uuid4()
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(token, t, nonce)

string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')

sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())
print ('Authorization: {}'.format(token))
print ('t: {}'.format(t))
print ('sign: {}'.format(str(sign, 'utf-8')))
print ('nonce: {}'.format(nonce))

#Build api header JSON
apiHeader['Authorization']=token
apiHeader['Content-Type']='application/json'
apiHeader['charset']='utf8'
apiHeader['t']=str(t)
apiHeader['sign']=str(sign, 'utf-8')
apiHeader['nonce']=str(nonce)
Einschalten des Bots - Request:

Code: Alles auswählen

POST https://api.switch-bot.com/v1.1/devices/210/commands
{
    "command": "turnOn",
    "parameter": "default",
    "commandType": "command"
}
Einschalten des Bots - Response:

Code: Alles auswählen

{
    "statusCode": 100,
    "body": {},
    "message": "success"
}

Ausschalten des Bots - Request (wird in meinem Szenario nicht benötigt, da sich die Warmwasserzubereitung automatisch abschaltet):

Code: Alles auswählen

POST https://api.switch-bot.com/v1.1/devices/210/commands
{
    "command": "turnOff",
    "parameter": "default",
    "commandType": "command"
}
Ausschalten des Bots - Response (hier bin ich nicht ganz sicher, da die Doku keinen entsprechenden Beispielcode hat):

Code: Alles auswählen

{
    "statusCode": 100,
    "body": {},
    "message": "success"
}
Ich nutze die OpenWB 2.0 und bin gerne bereit, zu testen, mitzuhelfen, Zugangsdaten zur Verfügung zu stellen usw., nur leider kann ich nicht programmieren und habe keine Erfahrung mit Github etc. Ich würde mich sehr freuen, wenn mir jemand weiterhelfen könnte. Der Switchbot funktioniert sehr zuverlässig und ist eine gute Methode, auch andere "dumme" Geräte smart zu machen, da er im Prinzip jegliche Art von physischen Schaltern betätigen kann (auch Lichtschalter etc.). Ist also sicher auch für andere Smarthome-Nutzer von Vorteil.
sonnencorsa
Beiträge: 66
Registriert: Mi Jul 07, 2021 11:55 am

Re: Feature Request: Switchbot Tastendrückroboter einbinden

Beitrag von sonnencorsa »

Update: Ich habe nun für mich einen funktionierenden Workaround gefunden, und zwar kann man über das Automatisierungs-Tool "Pipedream" einen Webhook erstellen, also eine URL, bei deren Aufrufen Python3-Code (und damit die SwitchBot-API) ausgeführt wird. Den entsprechenden Code habe ich gemeinsam mit ChatGPT aus der der Switchbot-API-Dokumentation erstellt. Man benötigt lediglich die API-Zugangsdaten (token und secret), die bekommt man in der SwitchBot-App (siehe API-Dokumentation: https://github.com/OpenWonderLabs/SwitchBotAPI) und muss diese im Code ersetzen. Jedenfalls kann man so über den Abruf von URLs den Switchbot via dessen API bedienen, perfekt für die Integration (via HTTP) in Smarthome2.0. Getestet & funktioniert.

Eleganter wäre es natürlich, wenn man die API direkt über SmartHome 2.0 aus der OpenWB heraus aufrufen könnte (also ohne den Pipedream-Webhook-HTTP-Umweg). Dazu müsste man in den SmartHome2.0-Einstellungen einen weiteren Gerätetyp (SwitchBot) sowie Felder für token, secret und Device-Nummer (falls jemand mehrere Switchbots hat, siehe Comments im Code) erstellen. Das Gerät kann "einschalten" und "ausschalten" (was beim "Einschalten" und "Ausschalten" konkret passiert kann man in der App konfigurieren, bei mir ist z. B. Einschalten 3x den Knopf drücken).

Mein Code zum API-Abruf funktioniert jedenfalls und könnte fast 1:1 übernommen werden, token und secret (siehe Code, XXXXXXXX) sowie die Device-Nummer (siehe Code, zurzeit [0]) müssten entsprechend aus den SmartHome2.0-Einstellungen übernommen werden.

Hier der Code zum "Einschalten" des Bots (meinen Code oben bitte ignorieren, da waren paar Fehler drin):

Code: Alles auswählen

import json
import time
import hashlib
import hmac
import base64
import uuid

# Declare empty header dictionary
apiHeader = {}
# open token
token = 'XXXXXXXX' # copy and paste from the SwitchBot app V6.14 or later
# secret key
secret = 'XXXXXXXX' # copy and paste from the SwitchBot app V6.14 or later
nonce = uuid.uuid4()
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(token, t, nonce)

string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')

sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())
print ('Authorization: {}'.format(token))
print ('t: {}'.format(t))
print ('sign: {}'.format(str(sign, 'utf-8')))
print ('nonce: {}'.format(nonce))

#Build api header JSON
apiHeader['Authorization']=token
apiHeader['Content-Type']='application/json'
apiHeader['charset']='utf8'
apiHeader['t']=str(t)
apiHeader['sign']=str(sign, 'utf-8')
apiHeader['nonce']=str(nonce)


import requests

# Declare the URL for the GET request
url_get = "https://api.switch-bot.com/v1.1/devices"
# Declare the URL for the POST request
url_post = "https://api.switch-bot.com/v1.1/devices/{}/commands"

# Make the GET request with the specified headers
response_get = requests.get(url_get, headers=apiHeader)

# Check if the GET request was successful (status code 200)
if response_get.status_code == 200:
    # Parse the response content (JSON data)
    response_data = response_get.json()

    # Print the JSON response
    print("GET Response:", response_data)
    
    # Extract deviceId from the response
    device_id = response_data['body']['deviceList'][0]['deviceId']  # Assuming the first device is the one you want to control, change [0] to [1] for second etc.

    # Update the URL for the POST request with the correct deviceId
    url_post = url_post.format(device_id)
    
    # Print the device ID
    print("Device ID:", device_id)

    # Sample data to be sent with the POST request
    data_post = {
        "command": "turnOn",
        "parameter": "default",
        "commandType": "command"
    }

    # Make the POST request with the specified headers and data
    response_post = requests.post(url_post, headers=apiHeader, json=data_post)

    # Check if the POST request was successful (status code 200)
    if response_post.status_code == 200:
        # Print the response content (JSON data)
        print("POST Response:", response_post.json())
    else:
        # Print the error status code if the POST request was not successful
        print("POST Error:", response_post.status_code)
else:
    # Print the error status code if the GET request was not successful
    print("GET Error:", response_get.status_code)
Und hier zum "Ausschalten", einzige Änderung ist das Ersetzen von "turnOn" durch "turnOff".

Code: Alles auswählen

import json
import time
import hashlib
import hmac
import base64
import uuid

# Declare empty header dictionary
apiHeader = {}
# open token
token = 'XXXXXXXX' # copy and paste from the SwitchBot app V6.14 or later
# secret key
secret = 'XXXXXXXX' # copy and paste from the SwitchBot app V6.14 or later
nonce = uuid.uuid4()
t = int(round(time.time() * 1000))
string_to_sign = '{}{}{}'.format(token, t, nonce)

string_to_sign = bytes(string_to_sign, 'utf-8')
secret = bytes(secret, 'utf-8')

sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest())
print ('Authorization: {}'.format(token))
print ('t: {}'.format(t))
print ('sign: {}'.format(str(sign, 'utf-8')))
print ('nonce: {}'.format(nonce))

#Build api header JSON
apiHeader['Authorization']=token
apiHeader['Content-Type']='application/json'
apiHeader['charset']='utf8'
apiHeader['t']=str(t)
apiHeader['sign']=str(sign, 'utf-8')
apiHeader['nonce']=str(nonce)


import requests

# Declare the URL for the GET request
url_get = "https://api.switch-bot.com/v1.1/devices"
# Declare the URL for the POST request
url_post = "https://api.switch-bot.com/v1.1/devices/{}/commands"

# Make the GET request with the specified headers
response_get = requests.get(url_get, headers=apiHeader)

# Check if the GET request was successful (status code 200)
if response_get.status_code == 200:
    # Parse the response content (JSON data)
    response_data = response_get.json()

    # Print the JSON response
    print("GET Response:", response_data)
    
    # Extract deviceId from the response
    device_id = response_data['body']['deviceList'][0]['deviceId']  # Assuming the first device is the one you want to control, change [0] to [1] for second etc.

    # Update the URL for the POST request with the correct deviceId
    url_post = url_post.format(device_id)
    
    # Print the device ID
    print("Device ID:", device_id)

    # Sample data to be sent with the POST request
    data_post = {
        "command": "turnOff",
        "parameter": "default",
        "commandType": "command"
    }

    # Make the POST request with the specified headers and data
    response_post = requests.post(url_post, headers=apiHeader, json=data_post)

    # Check if the POST request was successful (status code 200)
    if response_post.status_code == 200:
        # Print the response content (JSON data)
        print("POST Response:", response_post.json())
    else:
        # Print the error status code if the POST request was not successful
        print("POST Error:", response_post.status_code)
else:
    # Print the error status code if the GET request was not successful
    print("GET Error:", response_get.status_code)
Gero
Beiträge: 2557
Registriert: Sa Feb 20, 2021 9:55 am

Re: Feature Request: Switchbot Tastendrückroboter einbinden

Beitrag von Gero »

Normalerweise ist @okaegi sehr hilfsbereit, wenn es um neue Geräte im smarthome-Bereich geht. Neue Wärmepumpen oder Shellies werden von ihm sehr zügig implementiert und stehen dann im Nightly oder Master sehr schnell zum testen bereit.

Allerdings ist das smarthome in der 2er-Software noch nicht da, wo es hinsoll und von daher vermute ich, dass er gerade daran arbeitet. Aber vielleicht meldet er sich ja hier.
openWB-series2, openWB-Buchse, E3/DC S10pro+19.5kWh, 30kWp Ost-Süd, Model 3 und Ion
Antworten