-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mod for switchbot api 1.1 #491
Changes from all commits
5083557
77343d3
9d49127
e5ed02b
2b211bd
429cd88
d535017
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
<launch> | ||
<arg name="token" /> | ||
<arg name="secret" default="''" /> | ||
<arg name="respawn" default="true" /> | ||
|
||
<node name="switchbot_ros" pkg="switchbot_ros" type="switchbot_ros_server.py" | ||
respawn="$(arg respawn)" output="screen"> | ||
<rosparam subst_value="true"> | ||
token: $(arg token) | ||
secret: $(arg secret) | ||
</rosparam> | ||
</node> | ||
</launch> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#!/usr/bin/env python | ||
|
||
import rospy | ||
from switchbot_ros.switchbot_ros_client import SwitchBotROSClient | ||
|
||
rospy.init_node('controler_node') | ||
client = SwitchBotROSClient() | ||
|
||
devices = client.get_devices() | ||
print(devices) | ||
|
||
client.control_device('pendant-light', 'turnOff') | ||
|
||
client.control_device('bot74a', 'turnOn') | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,15 +4,28 @@ | |||||
import os.path | ||||||
import requests | ||||||
|
||||||
import sys | ||||||
import os | ||||||
import time | ||||||
import hashlib | ||||||
import hmac | ||||||
import base64 | ||||||
import uuid | ||||||
|
||||||
|
||||||
class SwitchBotAPIClient(object): | ||||||
""" | ||||||
For Using SwitchBot via official API. | ||||||
Please see https://github.com/OpenWonderLabs/SwitchBotAPI for details. | ||||||
""" | ||||||
def __init__(self, token): | ||||||
self._host_domain = "https://api.switch-bot.com/v1.0/" | ||||||
def __init__(self, token, secret=""): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
if not secret: | ||||||
self.api_version = "v1.0" | ||||||
else: | ||||||
self.api_version = "v1.1" | ||||||
self._host_domain = "https://api.switch-bot.com/" + self.api_version + "/" | ||||||
self.token = token | ||||||
self.secret = secret # SwitchBot API v1.1 | ||||||
self.device_list = None | ||||||
self.infrared_remote_list = None | ||||||
self.scene_list = None | ||||||
|
@@ -21,6 +34,41 @@ def __init__(self, token): | |||||
self.update_device_list() | ||||||
self.update_scene_list() | ||||||
|
||||||
def make_sign(self, token, secret): | ||||||
""" | ||||||
Make Sign from token and secret | ||||||
""" | ||||||
nonce = uuid.uuid4() | ||||||
t = int(round(time.time() * 1000)) | ||||||
string_to_sign = '{}{}{}'.format(token, t, nonce) | ||||||
|
||||||
if sys.version_info[0] > 2: | ||||||
string_to_sign = bytes(string_to_sign, 'utf-8') | ||||||
secret = bytes(secret, 'utf-8') | ||||||
else: | ||||||
string_to_sign = bytes(string_to_sign) | ||||||
secret = bytes(secret) | ||||||
|
||||||
sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest()) | ||||||
|
||||||
if sys.version_info[0] > 2: | ||||||
sign = sign.decode('utf-8') | ||||||
|
||||||
return sign, str(t), nonce | ||||||
|
||||||
def make_request_header(self, token, secret): | ||||||
""" | ||||||
Make Request Header | ||||||
""" | ||||||
sign, t, nonce = self.make_sign(token, secret) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please keep backward compatibility for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even if a request is sent to SwitchBot API v1.0 with the secret key included in the request header, it behaves like it is just not used and the request seems executed without any problems. Even so, are there any compatibility issues with API V1.0? As for another problem about Python 2 compatibility, I changed the code to work in both Python 2 and 3. 429cd88#diff-396497c868baf8630a5e57ccf98059c7d6f1d45e91faccfe0917e1012f124191R45-R66 |
||||||
headers={ | ||||||
"Authorization": token, | ||||||
"sign": str(sign), | ||||||
"t": str(t), | ||||||
"nonce": str(nonce), | ||||||
"Content-Type": "application/json; charset=utf8" | ||||||
} | ||||||
return headers | ||||||
|
||||||
def request(self, method='GET', devices_or_scenes='devices', service_id='', service='', json_body=None): | ||||||
""" | ||||||
|
@@ -30,20 +78,20 @@ def request(self, method='GET', devices_or_scenes='devices', service_id='', serv | |||||
raise ValueError('Please set devices_or_scenes variable devices or scenes') | ||||||
|
||||||
url = os.path.join(self._host_domain, devices_or_scenes, service_id, service) | ||||||
|
||||||
headers = self.make_request_header(self.token, self.secret) | ||||||
|
||||||
if method == 'GET': | ||||||
response = requests.get( | ||||||
url, | ||||||
headers={'Authorization': self.token} | ||||||
headers=headers | ||||||
) | ||||||
elif method == 'POST': | ||||||
response = requests.post( | ||||||
url, | ||||||
json_body, | ||||||
headers={ | ||||||
'Content-Type': 'application/json; charset=utf8', | ||||||
'Authorization': self.token | ||||||
}) | ||||||
json=json_body, | ||||||
headers=headers | ||||||
) | ||||||
else: | ||||||
raise ValueError('Got unexpected http request method. Please use GET or POST.') | ||||||
|
||||||
|
@@ -87,8 +135,8 @@ def update_device_list(self): | |||||
self.infrared_remote_list = res['body']['infraredRemoteList'] | ||||||
for device in self.device_list: | ||||||
self.device_name_id[device['deviceName']] = device['deviceId'] | ||||||
for infrated_remote in self.infrared_remote_list: | ||||||
self.device_name_id[device['deviceName']] = device['deviceId'] | ||||||
for infrared_remote in self.infrared_remote_list: | ||||||
self.device_name_id[infrared_remote['deviceName']] = infrared_remote['deviceId'] | ||||||
|
||||||
return self.device_list, self.infrared_remote_list | ||||||
|
||||||
|
@@ -99,7 +147,7 @@ def update_scene_list(self): | |||||
""" | ||||||
self.scene_list = self.request(devices_or_scenes='scenes')['body'] | ||||||
for scene in self.scene_list: | ||||||
self.scene_name_id[scene['sceneName']] = device['sceneId'] | ||||||
self.scene_name_id[scene['sceneName']] = scene['sceneId'] | ||||||
|
||||||
return self.scene_list | ||||||
|
||||||
|
@@ -125,11 +173,11 @@ def control_device(self, command, parameter='default', command_type='command', d | |||||
""" | ||||||
Send Command to the device. Please see https://github.com/OpenWonderLabs/SwitchBotAPI#send-device-control-commands for command options. | ||||||
""" | ||||||
json_body = json.dumps({ | ||||||
"command": command, | ||||||
"parameter": parameter, | ||||||
"commandType": command_type | ||||||
}) | ||||||
json_body = { | ||||||
"command": str(command), | ||||||
"parameter": str(parameter), | ||||||
"commandType": str(command_type) | ||||||
} | ||||||
if device_id: | ||||||
pass | ||||||
elif device_name: | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use
null
and it will be treated asNone
in python.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my environments, both
<arg name="secret" default="null" />
and<arg name="secret" default="" />
make an errorload_parameters: unable to set parameters (last param was [/switchbot_ros/secret=None]): cannot marshal None unless allow_none is enabled
and quit the process. But<arg name="secret" default="''" />
works finely.Does this problem depend on just only my environments?
Or do you know any solutions for the load_parameter error other than
<arg name="secret" default="''" />
?The console output with load_parameter error occurs when I used
<arg name="secret" default="null" />
and<arg name="secret" default="" />
in switchbot.launch is shown as followings.