-
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
Add switchbot status publisher #505
Merged
k-okada
merged 9 commits into
jsk-ros-pkg:master
from
y-yosuke:add-switchbot-status-publisher
Jul 10, 2024
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
d7b924a
1st commit for adding switchbot_status_publisher.
y-yosuke 07a0164
add processes to publish SwitchBot device status with Bot, Hub 2, Met…
y-yosuke 58f77f1
mod. some comments, messages and wrong writing style.
y-yosuke 78c3633
rename ..state.. to ..status..
y-yosuke 9a0e042
change switchbot.launch default of pub_status to false.
y-yosuke c567159
Merge branch 'master' into add-switchbot-status-publisher
y-yosuke 261c360
mod. messages and wait_for_server() in switchbot_ros_client.py to set…
y-yosuke f754384
mod. loginfo sentence in switchbot_ros_client.py
y-yosuke d0465ce
Merge branch 'master' into add-switchbot-status-publisher
k-okada File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +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 | ||
|
||
bool power # ON/OFF state True/False | ||
string device_mode # pressMode, switchMode, or customizeMode | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Header header # timestamp | ||
|
||
float64 temperature # temperature in celsius | ||
float64 humidity # humidity percentage | ||
float64 battery # the current battery level, 0-100 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Header header # timestamp | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
#!/usr/bin/env python | ||
|
||
import os.path | ||
from requests import ConnectionError | ||
import rospy | ||
from switchbot_ros.switchbot import SwitchBotAPIClient | ||
from switchbot_ros.switchbot import DeviceError, SwitchBotAPIError | ||
from switchbot_ros.msg import Meter, PlugMini, Hub2, Bot, StripLight | ||
|
||
|
||
class SwitchBotStatusPublisher: | ||
""" | ||
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() | ||
|
||
# Get parameters for publishing | ||
self.rate = rospy.get_param('~rate', 0.1) | ||
rospy.loginfo('Rate: ' + str(self.rate)) | ||
|
||
device_name = rospy.get_param('~device_name') | ||
if device_name: | ||
self.device_name = device_name | ||
else: | ||
rospy.logerr('No 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 Message Class for each device type | ||
if self.device_type == 'Remote': | ||
rospy.logerr('Device Type: "' + self.device_type + '" has no status in specifications.') | ||
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_status_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: | ||
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(self.rate) | ||
while not rospy.is_shutdown(): | ||
rate.sleep() | ||
if self.bots is None: | ||
self.bots = self.get_switchbot_client() | ||
|
||
if self.device_type == 'Remote': | ||
return | ||
else: | ||
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'] | ||
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 | ||
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 | ||
|
||
if msg: | ||
self.status_pub.publish(msg) | ||
|
||
|
||
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: | ||
return | ||
|
||
apiversion_str = 'Using SwitchBot API '; | ||
apiversion_str += self.bots.api_version; | ||
rospy.loginfo(apiversion_str) | ||
|
||
|
||
if __name__ == '__main__': | ||
try: | ||
rospy.init_node('switchbot_status_publisher') | ||
ssp = SwitchBotStatusPublisher() | ||
ssp.spin() | ||
except rospy.ROSInterruptException: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Could you add candidates constants of this field to this message like https://docs.ros.org/en/noetic/api/visualization_msgs/html/msg/Marker.html ?
or something like that.
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.
I added 3 candedate constants as