From d7b924ae2d1a6af11df9929994b7f6571730e1a5 Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Wed, 13 Mar 2024 17:45:12 +0900 Subject: [PATCH 1/7] 1st commit for adding switchbot_status_publisher. --- .../scripts/switchbot_state_publisher.py | 202 ++++++++++++++++++ .../src/switchbot_ros/switchbot_ros_client.py | 2 + 2 files changed, 204 insertions(+) create mode 100644 switchbot_ros/scripts/switchbot_state_publisher.py diff --git a/switchbot_ros/scripts/switchbot_state_publisher.py b/switchbot_ros/scripts/switchbot_state_publisher.py new file mode 100644 index 000000000..d1cf4e740 --- /dev/null +++ b/switchbot_ros/scripts/switchbot_state_publisher.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python + +# import actionlib +import os.path +from requests import ConnectionError +import rospy +# from switchbot_ros.msg import SwitchBotCommandAction +# from switchbot_ros.msg import SwitchBotCommandFeedback +# from switchbot_ros.msg import SwitchBotCommandResult +from switchbot_ros.msg import Device +from switchbot_ros.msg import DeviceArray +from switchbot_ros.switchbot import SwitchBotAPIClient +from switchbot_ros.switchbot import DeviceError, SwitchBotAPIError + + +class SwitchBotStatePublisher: + """ + Publissh your switchbot status with ROS and SwitchBot API + """ + def __init__(self): + # SwitchBot configs + # '~token' can be file path or raw characters + token = rospy.get_param('~token') + if os.path.exists(token): + with open(token) as f: + self.token = f.read().replace('\n', '') + else: + self.token = token + + # Switchbot API v1.1 needs secret key + secret = rospy.get_param('~secret', None ) + if secret is not None and os.path.exists(secret): + with open(secret, 'r', encoding='utf-8') as f: + self.secret = f.read().replace('\n', '') + else: + self.secret = secret + + # Initialize switchbot client + self.bots = self.get_switchbot_client() + self.print_apiversion() + self.print_devices() + self.print_scenes() +# # Actionlib +# self._as = actionlib.SimpleActionServer( +# '~switch', SwitchBotCommandAction, +# execute_cb=self.execute_cb, auto_start=False) +# self._as.start() + # Topic + self.pub = rospy.Publisher('~devices', DeviceArray, queue_size=1, latch=True) + self.published = False + +# self.status_publisher_list = [][] + self.status_pub = rospy.Publisher('~device_name/temperature', Temperature, queue_size=1, latch=True) + + rospy.loginfo('Ready.') + + def get_switchbot_client(self): + try: + client = SwitchBotAPIClient(token=self.token, secret=self.secret) + rospy.loginfo('Switchbot API Client initialized.') + return client + except ConnectionError: # If the machine is not connected to the internet + rospy.logwarn_once('Failed to connect to the switchbot server. The client would try connecting to it when subscribes the ActionGoal topic.') + return None + + def spin(self): + rate = rospy.Rate(1) + while not rospy.is_shutdown(): + rate.sleep() + if self.bots is None: + self.bots = self.get_switchbot_client() + elif not self.published: + self.publish_devices() + self.published = True + self.get_status() + + def get_status(self): + if self.bots is None: + return + + + + + def print_apiversion(self): + if self.bots is None: + return + + apiversion_str = 'Using SwitchBot API '; + apiversion_str += self.bots.api_version; + rospy.loginfo(apiversion_str) + + + def print_devices(self): + if self.bots is None: + return + + device_list_str = 'Switchbot Device List:\n' + device_list = sorted( + self.bots.device_list, + key=lambda device: str(device.get('deviceName'))) + device_list_str += str(len(device_list)) + ' Item(s)\n' + for device in device_list: + device_list_str += 'deviceName: ' + str(device.get('deviceName')) + device_list_str += ', deviceID: ' + str(device.get('deviceId')) + device_list_str += ', deviceType: ' + str(device.get('deviceType')) + device_list_str += '\n' + rospy.loginfo(device_list_str) + + remote_list_str = 'Switchbot Remote List:\n' + infrared_remote_list = sorted( + self.bots.infrared_remote_list, + key=lambda infrared_remote: str(infrared_remote.get('deviceName'))) + remote_list_str += str(len(infrared_remote_list)) + ' Item(s)\n' + for infrared_remote in infrared_remote_list: + remote_list_str += 'deviceName: ' + str(infrared_remote.get('deviceName')) + remote_list_str += ', deviceID: ' + str(infrared_remote.get('deviceId')) + remote_list_str += ', remoteType: ' + str(infrared_remote.get('remoteType')) + remote_list_str += '\n' + rospy.loginfo(remote_list_str) + + + def print_scenes(self): + if self.bots is None: + return + + scene_list_str = 'Switchbot Scene List:\n' + scene_list = sorted( + self.bots.scene_list, + key=lambda scene: str(scene.get('sceneName'))) + scene_list_str += str(len(scene_list)) + ' Item(s)\n' + for scene in scene_list: + scene_list_str += 'sceneName: ' + str(scene.get('sceneName')) + scene_list_str += ', sceneID: ' + str(scene.get('sceneId')) + scene_list_str += '\n' + rospy.loginfo(scene_list_str) + + + def publish_devices(self): + if self.bots is None: + return + + msg = DeviceArray() + + device_list = sorted( + self.bots.device_list, + key=lambda device: str(device.get('deviceName'))) + for device in device_list: + msg_device = Device() + msg_device.name = str(device.get('deviceName')) + msg_device.type = str(device.get('deviceType')) + msg.devices.append(msg_device) + + infrared_remote_list = sorted( + self.bots.infrared_remote_list, + key=lambda infrared_remote: str(infrared_remote.get('deviceName'))) + for infrared_remote in infrared_remote_list: + msg_device = Device() + msg_device.name = str(infrared_remote.get('deviceName')) + msg_device.type = str(infrared_remote.get('remoteType')) + msg.devices.append(msg_device) + + self.pub.publish(msg) + + def execute_cb(self, goal): + feedback = SwitchBotCommandFeedback() + result = SwitchBotCommandResult() + r = rospy.Rate(1) + success = True + # start executing the action + parameter, command_type = goal.parameter, goal.command_type + if not parameter: + parameter = 'default' + if not command_type: + command_type = 'command' + try: + if not self.bots: + self.bots = SwitchBotAPIClient(token=self.token, secret=self.secret) + feedback.status = str( + self.bots.control_device( + command=goal.command, + parameter=parameter, + command_type=command_type, + device_name=goal.device_name + )) + except (DeviceError, SwitchBotAPIError, KeyError) as e: + rospy.logerr(str(e)) + feedback.status = str(e) + success = False + finally: + self._as.publish_feedback(feedback) + r.sleep() + result.done = success + self._as.set_succeeded(result) + + +if __name__ == '__main__': + try: + rospy.init_node('switchbot_state_publisher') + ssp = SwitchBotAction() + ssp.spin() + except rospy.ROSInterruptException: + pass diff --git a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py index cd1b8a8d8..9119c075a 100644 --- a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py +++ b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py @@ -17,6 +17,8 @@ def __init__(self, actionname, SwitchBotCommandAction ) + rospy.loginfo("Waiting for action server to start.") + self.action_client.wait_for_server() def get_devices(self, timeout=None): From 07a016426a63abb83f99a6605190b30843d8ee24 Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Thu, 14 Mar 2024 16:08:44 +0900 Subject: [PATCH 2/7] add processes to publish SwitchBot device status with Bot, Hub 2, Meter, StripLight. --- switchbot_ros/CMakeLists.txt | 5 + switchbot_ros/launch/switchbot.launch | 15 ++ switchbot_ros/msg/Bot.msg | 6 + switchbot_ros/msg/Hub2.msg | 6 + switchbot_ros/msg/Meter.msg | 5 + switchbot_ros/msg/PlugMini.msg | 7 + switchbot_ros/msg/StripLight.msg | 6 + .../scripts/switchbot_state_publisher.py | 243 ++++++++---------- 8 files changed, 161 insertions(+), 132 deletions(-) create mode 100644 switchbot_ros/msg/Bot.msg create mode 100644 switchbot_ros/msg/Hub2.msg create mode 100644 switchbot_ros/msg/Meter.msg create mode 100644 switchbot_ros/msg/PlugMini.msg create mode 100644 switchbot_ros/msg/StripLight.msg diff --git a/switchbot_ros/CMakeLists.txt b/switchbot_ros/CMakeLists.txt index 9cdd6c183..176f91733 100644 --- a/switchbot_ros/CMakeLists.txt +++ b/switchbot_ros/CMakeLists.txt @@ -14,6 +14,11 @@ add_message_files( FILES Device.msg DeviceArray.msg + Meter.msg + PlugMini.msg + Hub2.msg + Bot.msg + StripLight.msg ) add_action_files( diff --git a/switchbot_ros/launch/switchbot.launch b/switchbot_ros/launch/switchbot.launch index 7e5a69e0b..7351e01d4 100644 --- a/switchbot_ros/launch/switchbot.launch +++ b/switchbot_ros/launch/switchbot.launch @@ -2,6 +2,9 @@ + + + @@ -10,4 +13,16 @@ secret: $(arg secret) + + + + token: $(arg token) + secret: $(arg secret) + device_name: $(arg pub_device_name) + rate: $(arg pub_status_rate) + + + diff --git a/switchbot_ros/msg/Bot.msg b/switchbot_ros/msg/Bot.msg new file mode 100644 index 000000000..92befda69 --- /dev/null +++ b/switchbot_ros/msg/Bot.msg @@ -0,0 +1,6 @@ +Header header # timestamp + +float64 battery # the current battery level, 0-100 + +string power # ON/OFF state +string device_mode # pressMode, switchMode, or customizeMode diff --git a/switchbot_ros/msg/Hub2.msg b/switchbot_ros/msg/Hub2.msg new file mode 100644 index 000000000..dfdf40b4f --- /dev/null +++ b/switchbot_ros/msg/Hub2.msg @@ -0,0 +1,6 @@ +Header header # timestamp + +float64 temperature # temperature in celsius +float64 humidity # humidity percentage + +int64 light_level # the level of illuminance of the ambience light, 1~20 diff --git a/switchbot_ros/msg/Meter.msg b/switchbot_ros/msg/Meter.msg new file mode 100644 index 000000000..df731f552 --- /dev/null +++ b/switchbot_ros/msg/Meter.msg @@ -0,0 +1,5 @@ +Header header # timestamp + +float64 temperature # temperature in celsius +float64 humidity # humidity percentage +float64 battery # the current battery level, 0-100 diff --git a/switchbot_ros/msg/PlugMini.msg b/switchbot_ros/msg/PlugMini.msg new file mode 100644 index 000000000..e74b320d0 --- /dev/null +++ b/switchbot_ros/msg/PlugMini.msg @@ -0,0 +1,7 @@ +Header header # timestamp + +float64 voltage # the voltage of the device, measured in Volt +float64 weight # the power consumed in a day, measured in Watts +float64 current # the current of the device at the moment, measured in Amp + +int32 minutes_day # he duration that the device has been used during a day, measured in minutes diff --git a/switchbot_ros/msg/StripLight.msg b/switchbot_ros/msg/StripLight.msg new file mode 100644 index 000000000..6fa8378ae --- /dev/null +++ b/switchbot_ros/msg/StripLight.msg @@ -0,0 +1,6 @@ +Header header # timestamp + +string power # ON/OFF state +string color # the color value, RGB "255:255:255" + +int64 brightness # the brightness value, range from 1 to 100 diff --git a/switchbot_ros/scripts/switchbot_state_publisher.py b/switchbot_ros/scripts/switchbot_state_publisher.py index d1cf4e740..f52adae54 100644 --- a/switchbot_ros/scripts/switchbot_state_publisher.py +++ b/switchbot_ros/scripts/switchbot_state_publisher.py @@ -1,16 +1,11 @@ #!/usr/bin/env python -# import actionlib import os.path from requests import ConnectionError import rospy -# from switchbot_ros.msg import SwitchBotCommandAction -# from switchbot_ros.msg import SwitchBotCommandFeedback -# from switchbot_ros.msg import SwitchBotCommandResult -from switchbot_ros.msg import Device -from switchbot_ros.msg import DeviceArray from switchbot_ros.switchbot import SwitchBotAPIClient from switchbot_ros.switchbot import DeviceError, SwitchBotAPIError +from switchbot_ros.msg import Meter, PlugMini, Hub2, Bot, StripLight class SwitchBotStatePublisher: @@ -38,21 +33,65 @@ def __init__(self): # Initialize switchbot client self.bots = self.get_switchbot_client() self.print_apiversion() - self.print_devices() - self.print_scenes() -# # Actionlib -# self._as = actionlib.SimpleActionServer( -# '~switch', SwitchBotCommandAction, -# execute_cb=self.execute_cb, auto_start=False) -# self._as.start() - # Topic - self.pub = rospy.Publisher('~devices', DeviceArray, queue_size=1, latch=True) - self.published = False -# self.status_publisher_list = [][] - self.status_pub = rospy.Publisher('~device_name/temperature', Temperature, queue_size=1, latch=True) + # Get parameters for publishing + self.rate = rospy.get_param('~rate', 0.1) + rospy.loginfo('Rate: ' + str(self.rate)) - rospy.loginfo('Ready.') + device_name = rospy.get_param('~device_name') + if device_name: + self.device_name = device_name + else: + rospy.logerr('None Device Name') + return + + self.device_type = None + self.device_list = sorted( + self.bots.device_list, + key=lambda device: str(device.get('deviceName'))) + for device in self.device_list: + device_name = str(device.get('deviceName')) + if self.device_name == device_name: + self.device_type = str(device.get('deviceType')) + + if self.device_type: + rospy.loginfo('deviceName: ' + self.device_name + ' / deviceType: ' + self.device_type) + else: + rospy.logerr('Invalid Device Name: ' + self.device_name) + return + + topic_name = '~' + self.device_name + topic_name = topic_name.replace('-', '_') + + # Publisher for each device type + if self.device_type == 'Remote': + rospy.logerr('Device Type: "' + self.device_type + '" has no status.') + return + else: + if self.device_type == 'Meter': + self.msg_class = Meter + elif self.device_type == 'MeterPlus': + self.msg_class = Meter + elif self.device_type == 'WoIOSensor': + self.msg_class = Meter + elif self.device_type == 'Hub 2': + self.msg_class = Hub2 + elif self.device_type == 'Plug Mini (JP)': + self.msg_class = PlugMini + elif self.device_type == 'Plug Mini (US)': + self.msg_class = PlugMini + elif self.device_type == 'Bot': + self.msg_class = Bot + elif self.device_type == 'Strip Light': + self.msg_class = StripLight + else: + rospy.logerr('No publisher process for "' + self.device_type + '" in switchbot_state_publisher.py') + return + + self.status_pub = rospy.Publisher(topic_name, self.msg_class, queue_size=1, latch=True) + + rospy.loginfo('Ready: SwitchBot Status Publisher for ' + self.device_name) + def get_switchbot_client(self): try: @@ -63,23 +102,66 @@ def get_switchbot_client(self): rospy.logwarn_once('Failed to connect to the switchbot server. The client would try connecting to it when subscribes the ActionGoal topic.') return None + def spin(self): - rate = rospy.Rate(1) + rate = rospy.Rate(self.rate) while not rospy.is_shutdown(): rate.sleep() if self.bots is None: self.bots = self.get_switchbot_client() - elif not self.published: - self.publish_devices() - self.published = True - self.get_status() + + if not self.device_type == 'Remote': + status = self.get_device_status(device_name=self.device_name) + + if status: + time = rospy.get_rostime() + if self.msg_class == Meter: + msg = Meter() + msg.header.stamp = time + msg.temperature = status['temperature'] + msg.humidity = status['humidity'] + msg.battery = status['battery'] + elif self.msg_class == Hub2: + msg = Hub2() + msg.header.stamp = time + msg.temperature = status['temperature'] + msg.humidity = status['humidity'] + msg.light_level = status['lightLevel'] + elif self.msg_class == PlugMini: + msg = PlugMini() + msg.header.stamp = time + msg.voltage = status['voltage'] + msg.weight = status['weight'] + msg.current = status['electricCurrent'] + msg.minutes_day = status['electricityOfDay'] + elif self.msg_class == Bot: + msg = Bot() + msg.header.stamp = time + msg.battery = status['battery'] + msg.power = status['power'] + msg.device_mode = status['deviceMode'] + elif self.msg_class == StripLight: + msg = StripLight() + msg.header.stamp = time + msg.power = status['power'] + msg.color = status['color'] + msg.brightness = status['brightness'] + else: + return + + if msg: + self.status_pub.publish(msg) + - def get_status(self): + def get_device_status(self, device_name=None): if self.bots is None: return - - - + elif device_name: + status = self.bots.device_status(device_name=device_name) + return status + else: + return + def print_apiversion(self): if self.bots is None: @@ -88,115 +170,12 @@ def print_apiversion(self): apiversion_str = 'Using SwitchBot API '; apiversion_str += self.bots.api_version; rospy.loginfo(apiversion_str) - - - def print_devices(self): - if self.bots is None: - return - - device_list_str = 'Switchbot Device List:\n' - device_list = sorted( - self.bots.device_list, - key=lambda device: str(device.get('deviceName'))) - device_list_str += str(len(device_list)) + ' Item(s)\n' - for device in device_list: - device_list_str += 'deviceName: ' + str(device.get('deviceName')) - device_list_str += ', deviceID: ' + str(device.get('deviceId')) - device_list_str += ', deviceType: ' + str(device.get('deviceType')) - device_list_str += '\n' - rospy.loginfo(device_list_str) - - remote_list_str = 'Switchbot Remote List:\n' - infrared_remote_list = sorted( - self.bots.infrared_remote_list, - key=lambda infrared_remote: str(infrared_remote.get('deviceName'))) - remote_list_str += str(len(infrared_remote_list)) + ' Item(s)\n' - for infrared_remote in infrared_remote_list: - remote_list_str += 'deviceName: ' + str(infrared_remote.get('deviceName')) - remote_list_str += ', deviceID: ' + str(infrared_remote.get('deviceId')) - remote_list_str += ', remoteType: ' + str(infrared_remote.get('remoteType')) - remote_list_str += '\n' - rospy.loginfo(remote_list_str) - - - def print_scenes(self): - if self.bots is None: - return - - scene_list_str = 'Switchbot Scene List:\n' - scene_list = sorted( - self.bots.scene_list, - key=lambda scene: str(scene.get('sceneName'))) - scene_list_str += str(len(scene_list)) + ' Item(s)\n' - for scene in scene_list: - scene_list_str += 'sceneName: ' + str(scene.get('sceneName')) - scene_list_str += ', sceneID: ' + str(scene.get('sceneId')) - scene_list_str += '\n' - rospy.loginfo(scene_list_str) - - - def publish_devices(self): - if self.bots is None: - return - - msg = DeviceArray() - - device_list = sorted( - self.bots.device_list, - key=lambda device: str(device.get('deviceName'))) - for device in device_list: - msg_device = Device() - msg_device.name = str(device.get('deviceName')) - msg_device.type = str(device.get('deviceType')) - msg.devices.append(msg_device) - - infrared_remote_list = sorted( - self.bots.infrared_remote_list, - key=lambda infrared_remote: str(infrared_remote.get('deviceName'))) - for infrared_remote in infrared_remote_list: - msg_device = Device() - msg_device.name = str(infrared_remote.get('deviceName')) - msg_device.type = str(infrared_remote.get('remoteType')) - msg.devices.append(msg_device) - - self.pub.publish(msg) - - def execute_cb(self, goal): - feedback = SwitchBotCommandFeedback() - result = SwitchBotCommandResult() - r = rospy.Rate(1) - success = True - # start executing the action - parameter, command_type = goal.parameter, goal.command_type - if not parameter: - parameter = 'default' - if not command_type: - command_type = 'command' - try: - if not self.bots: - self.bots = SwitchBotAPIClient(token=self.token, secret=self.secret) - feedback.status = str( - self.bots.control_device( - command=goal.command, - parameter=parameter, - command_type=command_type, - device_name=goal.device_name - )) - except (DeviceError, SwitchBotAPIError, KeyError) as e: - rospy.logerr(str(e)) - feedback.status = str(e) - success = False - finally: - self._as.publish_feedback(feedback) - r.sleep() - result.done = success - self._as.set_succeeded(result) if __name__ == '__main__': try: rospy.init_node('switchbot_state_publisher') - ssp = SwitchBotAction() + ssp = SwitchBotStatePublisher() ssp.spin() except rospy.ROSInterruptException: pass From 58f77f1cf3234595f4305416bdd53d55fb8f89e8 Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Fri, 15 Mar 2024 14:04:45 +0900 Subject: [PATCH 3/7] mod. some comments, messages and wrong writing style. --- .../scripts/switchbot_state_publisher.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/switchbot_ros/scripts/switchbot_state_publisher.py b/switchbot_ros/scripts/switchbot_state_publisher.py index f52adae54..11dde61af 100644 --- a/switchbot_ros/scripts/switchbot_state_publisher.py +++ b/switchbot_ros/scripts/switchbot_state_publisher.py @@ -23,7 +23,7 @@ def __init__(self): self.token = token # Switchbot API v1.1 needs secret key - secret = rospy.get_param('~secret', None ) + secret = rospy.get_param('~secret', None) if secret is not None and os.path.exists(secret): with open(secret, 'r', encoding='utf-8') as f: self.secret = f.read().replace('\n', '') @@ -42,13 +42,13 @@ def __init__(self): if device_name: self.device_name = device_name else: - rospy.logerr('None Device Name') + rospy.logerr('No Device Name') return - self.device_type = None + self.device_type = None self.device_list = sorted( self.bots.device_list, - key=lambda device: str(device.get('deviceName'))) + key=lambda device: str(device.get('deviceName'))) for device in self.device_list: device_name = str(device.get('deviceName')) if self.device_name == device_name: @@ -63,9 +63,9 @@ def __init__(self): topic_name = '~' + self.device_name topic_name = topic_name.replace('-', '_') - # Publisher for each device type + # Publisher Message Class for each device type if self.device_type == 'Remote': - rospy.logerr('Device Type: "' + self.device_type + '" has no status.') + rospy.logerr('Device Type: "' + self.device_type + '" has no status in specifications.') return else: if self.device_type == 'Meter': @@ -110,7 +110,9 @@ def spin(self): if self.bots is None: self.bots = self.get_switchbot_client() - if not self.device_type == 'Remote': + if self.device_type == 'Remote': + return + else: status = self.get_device_status(device_name=self.device_name) if status: @@ -151,7 +153,7 @@ def spin(self): if msg: self.status_pub.publish(msg) - + def get_device_status(self, device_name=None): if self.bots is None: From 78c3633d636534ca18f89d7aecff8aa1917497ec Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Mon, 18 Mar 2024 14:59:41 +0900 Subject: [PATCH 4/7] rename ..state.. to ..status.. --- switchbot_ros/launch/switchbot.launch | 2 +- switchbot_ros/scripts/control_switchbot.py | 4 ++-- ...t_state_publisher.py => switchbot_status_publisher.py} | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) rename switchbot_ros/scripts/{switchbot_state_publisher.py => switchbot_status_publisher.py} (97%) diff --git a/switchbot_ros/launch/switchbot.launch b/switchbot_ros/launch/switchbot.launch index 7351e01d4..db57da27e 100644 --- a/switchbot_ros/launch/switchbot.launch +++ b/switchbot_ros/launch/switchbot.launch @@ -15,7 +15,7 @@ token: $(arg token) diff --git a/switchbot_ros/scripts/control_switchbot.py b/switchbot_ros/scripts/control_switchbot.py index 1c04c2b73..3dede636e 100644 --- a/switchbot_ros/scripts/control_switchbot.py +++ b/switchbot_ros/scripts/control_switchbot.py @@ -9,7 +9,7 @@ devices = client.get_devices() print(devices) -client.control_device('pendant-light', 'turnOff') +client.control_device('pendant-light', 'turnOn', wait=True) -client.control_device('bot74a', 'turnOn') +client.control_device('bot74a', 'turnOn', wait=True) diff --git a/switchbot_ros/scripts/switchbot_state_publisher.py b/switchbot_ros/scripts/switchbot_status_publisher.py similarity index 97% rename from switchbot_ros/scripts/switchbot_state_publisher.py rename to switchbot_ros/scripts/switchbot_status_publisher.py index 11dde61af..ff7e84319 100644 --- a/switchbot_ros/scripts/switchbot_state_publisher.py +++ b/switchbot_ros/scripts/switchbot_status_publisher.py @@ -8,7 +8,7 @@ from switchbot_ros.msg import Meter, PlugMini, Hub2, Bot, StripLight -class SwitchBotStatePublisher: +class SwitchBotStatusPublisher: """ Publissh your switchbot status with ROS and SwitchBot API """ @@ -85,7 +85,7 @@ def __init__(self): elif self.device_type == 'Strip Light': self.msg_class = StripLight else: - rospy.logerr('No publisher process for "' + self.device_type + '" in switchbot_state_publisher.py') + rospy.logerr('No publisher process for "' + self.device_type + '" in switchbot_status_publisher.py') return self.status_pub = rospy.Publisher(topic_name, self.msg_class, queue_size=1, latch=True) @@ -176,8 +176,8 @@ def print_apiversion(self): if __name__ == '__main__': try: - rospy.init_node('switchbot_state_publisher') - ssp = SwitchBotStatePublisher() + rospy.init_node('switchbot_status_publisher') + ssp = SwitchBotStatusPublisher() ssp.spin() except rospy.ROSInterruptException: pass From 9a0e042c558ee6a9ce0f5581357b9de20fc85ca9 Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Mon, 18 Mar 2024 15:20:03 +0900 Subject: [PATCH 5/7] change switchbot.launch default of pub_status to false. --- switchbot_ros/launch/switchbot.launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/switchbot_ros/launch/switchbot.launch b/switchbot_ros/launch/switchbot.launch index db57da27e..cb9a68a96 100644 --- a/switchbot_ros/launch/switchbot.launch +++ b/switchbot_ros/launch/switchbot.launch @@ -2,7 +2,7 @@ - + From 261c36065678b0ea0d72d5deb1e2c1c81780600a Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Tue, 16 Apr 2024 15:22:52 +0900 Subject: [PATCH 6/7] mod. messages and wait_for_server() in switchbot_ros_client.py to set timeout. --- switchbot_ros/msg/Bot.msg | 6 +++++- switchbot_ros/msg/StripLight.msg | 6 ++++-- .../scripts/switchbot_status_publisher.py | 16 +++++++++++++--- .../src/switchbot_ros/switchbot_ros_client.py | 7 ++++--- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/switchbot_ros/msg/Bot.msg b/switchbot_ros/msg/Bot.msg index 92befda69..74955d462 100644 --- a/switchbot_ros/msg/Bot.msg +++ b/switchbot_ros/msg/Bot.msg @@ -1,6 +1,10 @@ +string DEVICEMODE_PRESS = "pressMode" +string DEVICEMODE_SWITCH = "switchMode" +string DEVICEMODE_CUSTOMIZE = "customizeMode" + Header header # timestamp float64 battery # the current battery level, 0-100 -string power # ON/OFF state +bool power # ON/OFF state True/False string device_mode # pressMode, switchMode, or customizeMode diff --git a/switchbot_ros/msg/StripLight.msg b/switchbot_ros/msg/StripLight.msg index 6fa8378ae..4164d184e 100644 --- a/switchbot_ros/msg/StripLight.msg +++ b/switchbot_ros/msg/StripLight.msg @@ -1,6 +1,8 @@ Header header # timestamp -string power # ON/OFF state -string color # the color value, RGB "255:255:255" +bool power # ON/OFF state True/False int64 brightness # the brightness value, range from 1 to 100 +int64 color_r # Red color value 0-255 +int64 color_g # Green color value 0-255 +int64 color_b # Blue color value 0-255 \ No newline at end of file diff --git a/switchbot_ros/scripts/switchbot_status_publisher.py b/switchbot_ros/scripts/switchbot_status_publisher.py index ff7e84319..6ed571728 100644 --- a/switchbot_ros/scripts/switchbot_status_publisher.py +++ b/switchbot_ros/scripts/switchbot_status_publisher.py @@ -140,14 +140,24 @@ def spin(self): msg = Bot() msg.header.stamp = time msg.battery = status['battery'] - msg.power = status['power'] + if status['power'] == 'on': + msg.power = True + else: + msg.power = False msg.device_mode = status['deviceMode'] elif self.msg_class == StripLight: msg = StripLight() msg.header.stamp = time - msg.power = status['power'] - msg.color = status['color'] + if status['power'] == 'on': + msg.power = True + else: + msg.power = False msg.brightness = status['brightness'] + rgb_string = status['color'] + r, g, b = map(int, rgb_string.split(':')) + msg.color_r = r + msg.color_g = g + msg.color_b = b else: return diff --git a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py index 9119c075a..a73527b87 100644 --- a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py +++ b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py @@ -9,7 +9,8 @@ class SwitchBotROSClient(object): def __init__(self, actionname='switchbot_ros/switch', - topicname='switchbot_ros/devices'): + topicname='switchbot_ros/devices', + timeout=5): self.actionname = actionname self.topicname = topicname @@ -17,8 +18,8 @@ def __init__(self, actionname, SwitchBotCommandAction ) - rospy.loginfo("Waiting for action server to start.") - self.action_client.wait_for_server() + rospy.loginfo("Waiting " + str(timeout) + "[sec] for action server to start .") + self.action_client.wait_for_server(timeout=rospy.Duration(timeout,0)) def get_devices(self, timeout=None): From f7543840a6d59f17f3273990dbcf74c8bcaf6b7c Mon Sep 17 00:00:00 2001 From: Yosuke Yamamoto Date: Tue, 16 Apr 2024 15:34:34 +0900 Subject: [PATCH 7/7] mod. loginfo sentence in switchbot_ros_client.py --- switchbot_ros/src/switchbot_ros/switchbot_ros_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py index a73527b87..df1a7b00a 100644 --- a/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py +++ b/switchbot_ros/src/switchbot_ros/switchbot_ros_client.py @@ -18,7 +18,7 @@ def __init__(self, actionname, SwitchBotCommandAction ) - rospy.loginfo("Waiting " + str(timeout) + "[sec] for action server to start .") + rospy.loginfo("Waiting for action server to start. (timeout: " + str(timeout) + "[sec])") self.action_client.wait_for_server(timeout=rospy.Duration(timeout,0)) def get_devices(self, timeout=None):