本シリーズ前回の記事 SwitchBot を ROS から利用する – データ取得編 掲載以降,手元にある SwitchBot デバイスの種類が増えてきました.
そこで今回の記事では switchbot_ros でまだ対応していないデバイスのデータを取得・パブリッシュするためにコードを追加する様子を紹介します.追加例としてデバイス「SwitchBot CO2センサー(温湿度計)」のデータを取得して ROS Topic としてパブリッシュできるようにします.
追加したいデバイスが SwitchBot API で対応していないと switchbot_ros 側でも対応はできないので最初に SwitchBot API のドキュメントを調べます.
SwitchBot API v1.1 ドキュメント にデバイスのリスト取得とステータス取得の項目に「Meter Pro CO2」の記述があり,これが今回追加してみたデバイス「SwitchBot CO2センサー(温湿度計)」に対応したものとなっていました.
制御コマンドの一覧には CO2 センサーらしき記述が(少なくとも本記事執筆時には)ありませんので「SwitchBot CO2センサー(温湿度計)」には取得系コマンドのみが対応していて,制御系コマンドは無いようです.
SwitchBot API ドキュメントにある「SwitchBot CO2センサー(温湿度計)」のステータス取得で返されるデータの表を下に抜粋しましたので確認してみます.
| Key | Value Type | Description |
|---|---|---|
| deviceId | String | device ID |
| deviceType | String | device type. MeterPro(CO2) |
| hubDeviceId | String | device’s parent Hub ID |
| battery | Integer | the current battery level, 0-100 |
| version | String | the current firmware version, e.g. V4.2 |
| temperature | Float | temperature in celsius |
| humidity | Integer | humidity percentage |
| CO2 | Integer | CO2 ppm value, 0-9999 |
二酸化炭素濃度が単位 [ppm](百万分率)で範囲 0〜9999 の整数型データとして返されることが分かります.他は SwitchBot の温湿度計と同じように各測定値が得られるようです.
switchbot_ros に機能追加したいデバイス「SwitchBot CO2センサー(温湿度計)」について SwitchBot API が対応していることと API により取得できる測定値が分かりましたので実装してゆきます.もう少し具体化すると「SwitchBot CO2センサー(温湿度計)」から API 経由で得られた
の4つの値を ROS Topic としてパブリッシュします.
SwitchBot API によるデータの取得と ROS Topic のパブリッシュプロセスは switchbot_ros にある既存のルーチンをそのまま利用できますので今回新たに実装する部分は大まかには次の2つです.
先に結論としてコードの追加部分を下に記載してしまいます.ファイルとしては3点,追加箇所としては5点です.
今回追加する「SwitchBot CO2センサー(温湿度計)」に対応したメッセージ型 MeterProCO2.msg を定義します.
パブリッシュする4つのデータ「温度」「湿度」「バッテリーレベル」「CO2濃度」のうち3つ 温度,湿度,バッテリーレベル は Meter.msg と同じなので Meter.msg を複製してファイル名を MeterProCO2.msg に変更して CO2濃度 のデータ型を追加する方法で作成しました.
switchbot_ros / msg / MeterProCO2.msg
Header header # timestamp float64 temperature # temperature in celsius float64 humidity # humidity percentage float64 battery # the current battery level, 0-100 int64 co2ppm # CO2 ppm value, 0-9999
新しいメッセージ型を定義した場合はパッケージの CMakeLists.txt 内の add_message_files() に追記する必要があります.
switchbot_ros / CMakeLists.txt
add_message_files( FILES Device.msg DeviceArray.msg Meter.msg MeterProCO2.msg PlugMini.msg Hub2.msg Bot.msg StripLight.msg )
新しいメッセージ型 MeterProCO2.msg の準備ができましたので取得データの代入などの機能をパブリッシャーの Python のプログラムファイル switchbot_ros / scripts / switchbot_status_publisher.py に追加記述します.
追加した MeterProCO2.msg を switchbot_status_publisher.py 内で利用するためにメッセージクラス MeterProCO2 を import しておきます.
switchbot_ros / scripts / switchbot_status_publisher.py
#!/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, MeterProCO2
初期化関数定義 def __init__(self): 内のパブリッシャーのメッセージクラス設定を行う部分にデバイスタイプ MeterPro(CO2) の場合の条件分岐を追加して MeterProCO2 をメッセージクラスとして設定します.
switchbot_ros / scripts / switchbot_status_publisher.py
# 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
elif self.device_type == 'MeterPro(CO2)':
self.msg_class = MeterProCO2
else:
rospy.logerr('No publisher process for "' + self.device_type + '" in switchbot_status_publisher.py')
return
繰り返し関数定義 def spin(self): 内のパブリッシュするメッセージクラスごとの場合分けに MeterProCO2 を追加して SwitchBot API により取得した各データを MeterProCO2 メッセージの各要素に代入します.
switchbot_ros / scripts / switchbot_status_publisher.py
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
elif self.msg_class == MeterProCO2:
msg = MeterProCO2()
msg.header.stamp = time
msg.temperature = status['temperature']
msg.humidity = status['humidity']
msg.battery = status['battery']
msg.co2ppm = status['CO2']
else:
return
今回の「SwitchBot CO2センサー(温湿度計)」のデータ取得とその ROS Topic へのパブリッシュに関するファイルの追加・コード変更は以上です.
今回の変更で新しいメッセージ型を定義して導入していますのでパッケージのビルドを行い,環境設定を改めて行います.
switchbot_ros を含む jsk_3rdparty のビルド
$ source /opt/ros/noetic/setup.bash $ cd ~/switchbot_ws $ catkin build $ source ~/switchbot_ws/devel/setup.bash
まず利用可能な SwitchBot デバイス名リストを取得・確認してから,得られた新規追加したデバイス名を指定して SwitchBot デバイスのステータスデータの取得と ROS Topic へのパブリッシュを行い,実際にパブリッシュされているかを ROS Topic を表示して確認します.
実行方法は今回機能追加するより前の方法と同じで,launch 時にオプション指定するデバイス名を変えるだけです.
ターミナル 1 : switchbot_ros の実行
SwitchBot API 経由で今回追加した「SwitchBot CO2センサー(温湿度計)」の「デバイス名」と「デバイスタイプ」が取得できることを確認します.ユーザの SwitchBot アカウントで登録されているデバイスの「デバイス名」と「デバイスタイプ」は switchbot.launch を実行すると表示されます.
(下記 launch オプションの YOUR_TOKEN と YOUR_SECRET をそれぞれユーザアカウントのトークンとシークレットに置き換えて実行)
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET
switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/999f113c-b07d-11ef-9b82-a11b8fd4bdd2/roslaunch-robotuser-PC-7718.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:43087/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.17.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
auto-starting new master
process[master]: started with pid [7726]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to 999f113c-b07d-11ef-9b82-a11b8fd4bdd2
process[rosout-1]: started with pid [7736]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [7743]
[INFO] [1733123900.102425]: Switchbot API Client initialized.
[INFO] [1733123900.104175]: Using SwitchBot API v1.1
[INFO] [1733123900.106131]: Switchbot Device List:
9 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: cam-entrance01, deviceID: (固有のID番号が表示), deviceType: None
deviceName: co2sensor-ba1, deviceID: (固有のID番号が表示), deviceType: MeterPro(CO2)
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
deviceName: trackcard01, deviceID: (固有のID番号が表示), deviceType: None
[INFO] [1733123900.107799]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1733123900.109488]: Switchbot Scene List:
2 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1733123900.139015]: Ready.
追加した「SwitchBot CO2センサー(温湿度計)」のデバイス名 co2sensor-ba1 がコンソール出力されたので一旦 Ctrl-C にて switchbot.launch を終了します.
「SwitchBot CO2センサー(温湿度計)」のステータスデータを取得してパブリッシュされている ROS Topic を表示して確認してみます.前述の switchbot.launch の実行出力例からデバイス名が co2sensor-ba1 となっています.
ステータスデータを取得する場合は switchbot.launch 実行時に次の2つのオプションを追加します.
pub_status:=true ステータスを取得・パブリッシュを実行するオプション true/falsepub_device_name:= デバイス名の指定(今回の例 co2sensor-ba1)ターミナル 1 : switchbot_ros の実行
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET pub_status:=true pub_device_name:=co2sensor-ba1 pub_status_rate:=0.016666
YOUR_TOKEN と YOUR_SECRET は各々の SwitchBot アカウントのトークンとシークレットに置き換えて実行してください.pub_status:=true でステータスを取得・パブリッシュを実行します.pub_device_name:=co2sensor-ba1 の co2sensor-ba1 は各ユーザ利用のデバイス名に変更してください.pub_status_rate:=0.016666 でステータスを取得・パブリッシュする周波数 [Hz] を設定します.(本例では 0.016666[Hz] = 約60秒に1回)switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/e454822a-b07d-11ef-9b82-a11b8fd4bdd2/roslaunch-robotuser-PC-7804.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:36557/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.17.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
* /switchbot_status_publisher/device_name: co2sensor-ba1
* /switchbot_status_publisher/rate: 0.016666
* /switchbot_status_publisher/secret: (シークレットの上位数桁が表示)...
* /switchbot_status_publisher/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
switchbot_status_publisher (switchbot_ros/switchbot_status_publisher.py)
auto-starting new master
process[master]: started with pid [7812]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to e454822a-b07d-11ef-9b82-a11b8fd4bdd2
process[rosout-1]: started with pid [7822]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [7829]
process[switchbot_status_publisher-3]: started with pid [7830]
[INFO] [1733124025.952044]: Switchbot API Client initialized.
[INFO] [1733124025.953872]: Using SwitchBot API v1.1
[INFO] [1733124025.955817]: Switchbot Device List:
9 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: cam-entrance01, deviceID: (固有のID番号が表示), deviceType: None
deviceName: co2sensor-ba1, deviceID: (固有のID番号が表示), deviceType: MeterPro(CO2)
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
deviceName: trackcard01, deviceID: (固有のID番号が表示), deviceType: None
[INFO] [1733124025.957387]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1733124025.959085]: Switchbot Scene List:
2 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1733124025.981926]: Ready.
[INFO] [1733124026.191206]: Switchbot API Client initialized.
[INFO] [1733124026.192948]: Using SwitchBot API v1.1
[INFO] [1733124026.195299]: Rate: 0.016666
[INFO] [1733124026.197702]: deviceName: co2sensor-ba1 / deviceType: MeterPro(CO2)
[INFO] [1733124026.200537]: Ready: SwitchBot Status Publisher for co2sensor-ba1
ターミナル 2 : ROS Topic の確認
rostopic list の実行入力
$ source ~/switchbot_ws/devel/setup.bash $ rostopic list
rostopic list の実行出力例
/rosout /rosout_agg /switchbot_ros/devices /switchbot_ros/switch/cancel /switchbot_ros/switch/feedback /switchbot_ros/switch/goal /switchbot_ros/switch/result /switchbot_ros/switch/status /switchbot_status_publisher/co2sensor_ba1
rostopic echo 実行入力
$ rostopic echo /switchbot_status_publisher/co2sensor_ba1
rostopic echo の実行出力例
header:
seq: 1
stamp:
secs: 1733124088
nsecs: 5677223
frame_id: ''
temperature: 25.4
humidity: 35.0
battery: 100.0
co2ppm: 562
---
header:
seq: 2
stamp:
secs: 1733124147
nsecs: 910016298
frame_id: ''
temperature: 25.4
humidity: 35.0
battery: 100.0
co2ppm: 562
---
「SwitchBot CO2センサー(温湿度計)」のステータスデータとして CO2濃度 などが取得されて ROS Topic にパブリッシュされている様子が見て取れるかと思います.
今回の記事はここまでです.
本シリーズ前回の記事 SwitchBot を ROS から利用する – コマンド操作編2 では SwitchBot を ROS から利用する switchbot_ros のサンプルのソースコードで扱われていた SwitchBot デバイス以外のものを ROS から操作するために SwitchBot API のコマンドセットを調べて control_switchbot.py に実装する過程について紹介しました.
今回は SwitchBot デバイスのステータスデータの取得と ROS トピックへのパブリッシュを行ってみます.
前回の記事 SwitchBot を ROS から利用する – コマンド操作編2 を公開した後に GitHub 上の switchbot_ros が更新されて SwitchBot デバイスのステータスデータの取得とパブリッシュを行うソフトウェアソースコードが追加されました.
更新された switchbot_ros を実際に動作させる Ubuntu PC 内の switchbot_ros に適用してビルドします.
既に前回の記事の時点の switchbot_ros を含む jsk_3rdparty をクローンして利用している場合は次の手順で更新された GitHub 上の jsk_3rdparty を git でプル(ダウンロード更新)してビルドします.
switchbot_ros を含む jsk_3rdparty の更新とビルド
$ source ~/switchbot_ws/devel/setup.bash $ cd ~/switchbot_ws/src/jsk_3rdparty $ git checkout master $ git pull origin master $ catkin build $ source ~/switchbot_ws/devel/setup.bash
ターミナル 1 : switchbot_ros の実行
前回記事と同じですがユーザの SwitchBot アカウントで登録されているデバイスの「デバイス名」と「デバイスタイプ」は switchbot.launch を実行すると表示されます.
(下記 launch オプションの YOUR_TOKEN と YOUR_SECRET をそれぞれユーザアカウントのトークンとシークレットに置き換えて実行)
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET
switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f/roslaunch-robotuser-PC-62866.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:40731/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.16.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
auto-starting new master
process[master]: started with pid [62874]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to 87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f
process[rosout-1]: started with pid [62884]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [62891]
[INFO] [1706861436.195243]: Switchbot API Client initialized.
[INFO] [1706861436.199678]: Using SwitchBot API v1.1
[INFO] [1706861436.204957]: Switchbot Device List:
6 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
[INFO] [1706861436.208853]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1706861436.214168]: Switchbot Scene List:
3 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1706861436.254126]: Ready.
利用可能なデバイス名がコンソール出力されたので一旦 Ctrl-C にて switchbot.launch を終了します.
上記の switchbot.launch 実行出力例にある SwitchBot デバイスのうち取得するステータスがない Remote 以外の次のデバイスタイプは switchbot_ros にてステータスデータを取得することができます.
また上記リスト以外のデータ取得 API 提供がされている SwitchBot デバイスについては switchbot_ros のコードに組み込まれていませんが適宜情報をコードに加えれば switchbot_ros からもデータ取得できるようになると思います.
実行例として今回は SwitchBot の温湿度計(デバイスタイプ Meter)のステータスデータを取得してパブリッシュされている ROS トピックを表示してみます.先述の switchbot.launch の実行出力例から読み取ると,該当するデバイス名が thermo-hygrometer-f7a となっています.
ステータスデータを取得する場合は switchbot.launch 実行時に次の2つのオプションを追加します.
pub_status:=true ステータスを取得・パブリッシュを実行するオプション true/falsepub_device_name:=thermo-hygrometer-f7a デバイス名の指定(本例では thermo-hygrometer-f7a)ターミナル 1 : switchbot_ros の実行
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET pub_status:=true pub_device_name:=thermo-hygrometer-f7a
YOUR_TOKEN と YOUR_SECRET は各々の SwitchBot アカウントのトークンとシークレットに置き換えて実行してください.pub_status:=true でステータスを取得・パブリッシュを実行します.pub_device_name:=thermo-hygrometer-f7a の thermo-hygrometer-f7a
は各ユーザ利用のデバイス名に変更してください.switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/81bc64b6-faf2-11ee-8dad-e57ee950b51d/roslaunch-robotuser-PC-28197.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:35371/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.16.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
* /switchbot_status_publisher/device_name: thermo-hygrometer...
* /switchbot_status_publisher/rate: 0.1
* /switchbot_status_publisher/secret: (シークレットの上位数桁が表示)...
* /switchbot_status_publisher/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
switchbot_status_publisher (switchbot_ros/switchbot_status_publisher.py)
auto-starting new master
process[master]: started with pid [28205]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to 81bc64b6-faf2-11ee-8dad-e57ee950b51d
process[rosout-1]: started with pid [28215]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [28222]
process[switchbot_status_publisher-3]: started with pid [28223]
[INFO] [1713163000.937913]: Switchbot API Client initialized.
[INFO] [1713163000.938005]: Switchbot API Client initialized.
[INFO] [1713163000.940084]: Using SwitchBot API v1.1
[INFO] [1713163000.940382]: Using SwitchBot API v1.1
[INFO] [1713163000.942545]: Switchbot Device List:
6 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
[INFO] [1713163000.944131]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1713163000.944268]: Rate: 0.1
[INFO] [1713163000.945732]: Switchbot Scene List:
2 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1713163000.947428]: deviceName: thermo-hygrometer-f7a / deviceType: Meter
[INFO] [1713163000.951801]: Ready: SwitchBot Status Publisher for thermo-hygrometer-f7a
[INFO] [1713163000.966800]: Ready.
ターミナル 2 : ROS トピックの確認
rostopic list の実行入力
$ source ~/switchbot_ws/devel/setup.bash $ rostopic list
rostopic list の実行出力例
/rosout /rosout_agg /switchbot_ros/devices /switchbot_ros/switch/cancel /switchbot_ros/switch/feedback /switchbot_ros/switch/goal /switchbot_ros/switch/result /switchbot_ros/switch/status /switchbot_status_publisher/thermo_hygrometer_f7a
rostopic echo 実行入力
$ rostopic echo /switchbot_status_publisher/thermo_hygrometer_f7a
rostopic echo の実行出力例
header:
seq: 1
stamp:
secs: 1713163093
nsecs: 412018775
frame_id: ''
temperature: 26.9
humidity: 36.0
battery: 100.0
---
header:
seq: 2
stamp:
secs: 1713163103
nsecs: 447003364
frame_id: ''
temperature: 26.9
humidity: 36.0
battery: 100.0
---
header:
seq: 3
stamp:
secs: 1713163113
nsecs: 380291700
frame_id: ''
temperature: 26.9
humidity: 36.0
battery: 100.0
SwitchBot 温湿度計 Meter のステータスデータとして温度・湿度などが取得されて ROS トピックにパブリッシュされている様子がわかるかと思います.
ステータスの取得とパブリッシュの間隔は switchbot.launch のデフォルト設定で 0.1 [Hz] = 10秒間隔 になっています.これを変更する場合には switchbot.launch のオプションで pub_status_rate:=0.05 のように追加します.温湿度のように急に変化しなさそうなデータの場合はもっと長めの間隔でも良いかもしれません.
今回の記事はここまでです.
本シリーズ前回の記事 SwitchBot を ROS から利用する – コマンド操作編1 では SwitchBot を ROS から利用する switchbot_ros の導入とサンプル Python コードの実行の様子を紹介しました.
今回は前回の記事の続きとしてサンプルのソースコードで扱われていた SwitchBot デバイス以外のものを ROS から操作するために SwitchBot API のコマンドセットを調べて control_switchbot.py に実装する過程について紹介します.
switchbot_ros のサンプル Python コード control_switchbot.py においてボット(スイッチ)をオンにする命令は次のようになっていて「デバイス名」とそれに対する「コマンド」の2つを指定する必要があります.
client.control_device('bot74a', 'turnOn')
client.control_device('デバイス名', 'コマンド')
このうち「コマンド」は SwitchBot API にてデバイスタイプごとに設定されているので「デバイスタイプ」が何かを知る必要があります.
ユーザのアカウントで登録されているデバイスの「デバイス名」と「デバイスタイプ」は switchbot.launch を実行すると表示されます.
(下記 launch オプションの YOUR_TOKEN と YOUR_SECRET をそれぞれユーザアカウントのトークンとシークレットに置き換えて実行)
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET
switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f/roslaunch-robotuser-PC-62866.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:40731/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.16.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
auto-starting new master
process[master]: started with pid [62874]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to 87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f
process[rosout-1]: started with pid [62884]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [62891]
[INFO] [1706861436.195243]: Switchbot API Client initialized.
[INFO] [1706861436.199678]: Using SwitchBot API v1.1
[INFO] [1706861436.204957]: Switchbot Device List:
6 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
[INFO] [1706861436.208853]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1706861436.214168]: Switchbot Scene List:
3 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1706861436.254126]: Ready.
switchbot.launch 実行出力から次の1行を例にとると「デバイス名」が plugmini7a1 で「デバイスタイプ」が Plug Mini (JP) です.
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
操作したい SwitchBot デバイスタイプが分かればそのコマンドセットを調べます.SwitchBot API のコマンドセットは下記の Web ページで知ることができます.
今回はデバイスタイプ Plug Mini (JP) と Strip Light のデバイスを操作したいのでそれらのコマンドセットについて調べます.
電源プラグの On/Off を行う SwitchBot デバイスである Plug Mini (JP) のコマンドセットの説明は次のリンク先にあります.
上記 Web ページの Plug Mini (JP) コマンドセットの表をそのまま貼り付けたものが次の表です.
| deviceType | commandType | Command | command parameter | Description |
|---|---|---|---|---|
| Plug Mini (JP) | command | turnOn | default | set to ON state |
| Plug Mini (JP) | command | turnOff | default | set to OFF state |
| Plug Mini (JP) | command | toggle | default | toggle state |
デバイスの機能どおりに電源入 turnOn,電源切 turnOff,電源入切の切替 toggle の3つのコマンドにより構成されています.
テープライト形状の SwitchBot デバイスである Strip Light のコマンドセットの説明は次のリンク先にあります.
上記 Web ページの Strip Light コマンドセットの表をそのまま貼り付けたものが次の表です.
| deviceType | commandType | Command | command parameter | Description |
|---|---|---|---|---|
| Strip Light | command | turnOn | default | set to ON state |
| Strip Light | command | turnOff | default | set to OFF state |
| Strip Light | command | toggle | default | toggle state |
| Strip Light | command | setBrightness | {1-100} |
set brightness |
| Strip Light | command | setColor | "{0-255}:{0-255}:{0-255}" |
set RGB color value |
点灯 turnOn,消灯 turnOff,明滅切替 toggle,輝度設定 setBrightness,色設定 setColor の5つのコマンドにより構成されていて,そのうち輝度設定では{1-100} の範囲で輝度設定, "{0-255}:{0-255}:{0-255}" の値で RGB 色設定を行います.
デバイス名 plugmini7a1 の Plug Mini (JP) を操作します. ROS からコマンドを送って On/Off の切り替え toggle をしてみます.
サンプルコード control_switchbot.py に client.control_device('plugmini7a1', 'toggle') を追加します.(下記ソースコードの 16行目)
control_switchbot.py
#!/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', 'turnOn')
# client.control_device('bot74a', 'turnOn')
client.control_device('plugmini7a1', 'toggle')
ここでは元々サンプルコードにあったペンダントライトとボット(スイッチ)の操作をする行(上記ソースコードの12,14行目)は行頭に # を入れてコメントアウトして実行されないようにしています.
変更を加えた control_switchbot.py ファイルを保存してから実行します.
ターミナル 1 : switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET
ターミナル 2 : control_switchbot.py 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ rosrun switchbot_ros control_switchbot.py
デバイス名 tapelight7a1 の Strip Light (テープライト)を操作します. ROS からコマンドを送って次の動作をしてみます.
'255:255:255' に設定'255:0:0' に設定'0:255:0' に設定'0:0:255' に設定サンプルコード control_switchbot.py に下記ソースコードの18行目以降を追加します.
値を設定する setBrightness や setColor といったコマンドでは各数値を control_device() の引数 parameter に文字列として渡します.
また control_device() の中ではコマンドを Action サーバにゴールとして送っているので新しいコマンドが前のコマンドに置き換わらないように1つ1つのコマンド実行を終えるのを待つように引数 wait に True を渡しています.
control_switchbot.py
#!/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', 'turnOn')
# client.control_device('bot74a', 'turnOn')
# client.control_device('plugmini7a1', 'toggle')
client.control_device('tapelight7a1', 'turnOff', wait=True)
client.control_device('tapelight7a1', 'turnOn', wait=True)
client.control_device('tapelight7a1', 'setBrightness', parameter='100', wait=True)
client.control_device('tapelight7a1', 'setColor', parameter='255:255:255', wait=True)
client.control_device('tapelight7a1', 'setColor', parameter='255:0:0', wait=True)
client.control_device('tapelight7a1', 'setColor', parameter='0:255:0', wait=True)
client.control_device('tapelight7a1', 'setColor', parameter='0:0:255', wait=True)
client.control_device('tapelight7a1', 'setBrightness', parameter='1', wait=True)
client.control_device('tapelight7a1', 'turnOff', wait=True)
前述の Plug Mini (JP) のときと同様に変更を加えた control_switchbot.py ファイルを保存してから実行します.
筆者が試した範囲では時々 client.control_device() が実行されない不具合が見受けられ,それが SwitchBotROSClient インスタンス作成時 client = SwitchBotROSClient() に Action サーバの起動やサーバへの接続が不十分であることが原因のように思われました.
そこで下記の switchbot_ros_client.py の21行目のように self.action_client.wait_for_server() を入れて Action サーバが起動して接続されるのを待つようにしたところ,現状では安定して client.control_device() が実行されているように感じます.
switchbot_ros_client.py
import rospy
import actionlib
from switchbot_ros.msg import SwitchBotCommandAction
from switchbot_ros.msg import SwitchBotCommandGoal
from switchbot_ros.msg import DeviceArray
class SwitchBotROSClient(object):
def __init__(self,
actionname='switchbot_ros/switch',
topicname='switchbot_ros/devices'):
self.actionname = actionname
self.topicname = topicname
self.action_client = actionlib.SimpleActionClient(
actionname,
SwitchBotCommandAction
)
rospy.loginfo("Waiting for action server to start.")
self.action_client.wait_for_server()
def get_devices(self, timeout=None):
return rospy.wait_for_message(
self.topicname,
DeviceArray,
timeout=timeout
)
def control_device(self,
device_name,
command,
parameter='',
command_type='',
wait=False
):
goal = SwitchBotCommandGoal()
goal.device_name = device_name
goal.command = command
goal.parameter = parameter
goal.command_type = command_type
self.action_client.send_goal(goal)
if wait:
self.action_client.wait_for_result()
return self.action_client.get_result()
今回の記事はここまでです.
本記事では SwitchBot を ROS から利用できるソフトウェア switchbot_ros の使い方を紹介します.
SwitchBot は多くの IoT スマートホームデバイス製品を提供しているブランドで,既にそれらを日常生活の中で活用されている方も多いのではないでしょうか.
SwitchBot からはソフトウェアインターフェースとして WebAPI が提供されていて,2024年2月はじめの時点での最新バージョンが v1.1 となっています.
SwitchBot の WebAPI を ROS から利用する switchbot_ros は下記のリポジトリで公開されていて SwitchBot API v1.1 にも対応しています.
SwitchBot の機器を ROS のシステムに組み込むことによりロボットとスマートホームデバイスを組み合わせた動作システムを簡単に実現することが可能となります.
今回は switchbot_ros を含む jsk_3rdparty リポジトリを Ubuntu PC 内の ROS ワークスペースにクローン・ビルドして ROS から SwitchBot デバイスを動作させます.
本記事では次の環境で switchbot_ros を利用しています.
Ubuntu や ROS のインストールが済んだ状態で次のように switchbot_ros を利用するためのワークスペースを作成して jsk_3rdparty リポジトリをクローンしてビルドします.
$ source /opt/ros/noetic/setup.bash $ mkdir -p ~/switchbot_ws/src $ cd ~/switchbot_ws $ catkin build $ source ~/switchbot_ws/devel/setup.bash $ cd ~/switchbot_ws/src $ git clone https://github.com/jsk-ros-pkg/jsk_3rdparty.git $ cd ~/switchbot_ws $ rosdep install -y -r --from-paths src --ignore-src $ catkin build $ source ~/switchbot_ws/devel/setup.bash
switchbot_ros は SwitchBot API を利用していますので SwitchBot API にアクセスするための SwitchBot アカウント各々に固有の「トークン(token)」と「シークレット(secret)」の2つの情報が必要になります.
SwitchBot Magazine – 【API】新バージョンAPI v1.1を公開しました にトークンとシークレットの取得方法などが書かれています.この記事から引用・まとめをするとトークンとシークレットの取得方法はつぎのようになっています.
switchbot_ros の中にあるコマンドを発する Python コード例 control_switchbot.py を実行して ROS から SwitchBot デバイスのハブの赤外線リモコン発信で部屋の電気を点灯した後にボット(スイッチ)を動作させます.
control_switchbot.py の中身はシンプルで 12行目 で照明を点灯させて,14行目 でボット(スイッチ)を On しています.
control_switchbot.py
#!/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')
client.control_device('pendant-light', 'turnOff') で 'turnOff' となっているのに点灯?と思いますが筆者のペンダントライトのリモコンを SwitchBot アプリで登録する際に電源の On/Off ボタンが1つのものとして扱われていて 'turnOn' も 'turnOff' も On/Off の切り替えボタンとして機能してしまっているためです. ( = もう一度 client.control_device('pendant-light', 'turnOff') を実行すると消灯になる) このように特に登録するリモコンについてはどのようにマッピングができたかに挙動が依存するのでコマンドに対する各々のデバイスの挙動を確認してから利用する必要があります.
操作コマンドの SwitchBot デバイスに至るまでの大まかな流れは次のようになっています.
それでは実際に実行してみます. SwitchBot ROS アクションサーバを起動してから別ターミナルで control_switchbot.py を実行します.
ターミナル 1 : SwitchBot ROS アクションサーバの起動
下記コマンドの SwichBot ROS アクションサーバの起動実行時に launch オプションの token:=YOUR_TOKEN の YOUR_TOKEN を SwitchBot アプリで取得したトークンに置き換えて, secret:=YOUR_SECRET の YOUR_SECRET を取得したシークレットに置き換えて書いて実行します.
switchbot.launch 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ roslaunch switchbot_ros switchbot.launch token:=YOUR_TOKEN secret:=YOUR_SECRET
switchbot.launch 実行出力例
... logging to /home/robotuser/.ros/log/87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f/roslaunch-robotuser-PC-62866.log
Checking log directory for disk usage. This may take a while.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
started roslaunch server http://robotuser-PC:40731/
SUMMARY
========
PARAMETERS
* /rosdistro: noetic
* /rosversion: 1.16.0
* /switchbot_ros/secret: (シークレットの上位数桁が表示)...
* /switchbot_ros/token: (トークンの上位数桁が表示)...
NODES
/
switchbot_ros (switchbot_ros/switchbot_ros_server.py)
auto-starting new master
process[master]: started with pid [62874]
ROS_MASTER_URI=http://localhost:11311
setting /run_id to 87b6e5c8-c1a2-11ee-bce7-1d89a9d14e1f
process[rosout-1]: started with pid [62884]
started core service [/rosout]
process[switchbot_ros-2]: started with pid [62891]
[INFO] [1706861436.195243]: Switchbot API Client initialized.
[INFO] [1706861436.199678]: Using SwitchBot API v1.1
[INFO] [1706861436.204957]: Switchbot Device List:
6 Item(s)
deviceName: bot74a, deviceID: (固有のID番号が表示), deviceType: Bot
deviceName: hub2a, deviceID: (固有のID番号が表示), deviceType: Hub 2
deviceName: plugmini7a1, deviceID: (固有のID番号が表示), deviceType: Plug Mini (JP)
deviceName: remote-button10a, deviceID: (固有のID番号が表示), deviceType: Remote
deviceName: tapelight7a1, deviceID: (固有のID番号が表示), deviceType: Strip Light
deviceName: thermo-hygrometer-f7a, deviceID: (固有のID番号が表示), deviceType: Meter
[INFO] [1706861436.208853]: Switchbot Remote List:
2 Item(s)
deviceName: air-conditioner, deviceID: (固有のID番号が表示), remoteType: Air Conditioner
deviceName: pendant-light, deviceID: (固有のID番号が表示), remoteType: DIY Light
[INFO] [1706861436.214168]: Switchbot Scene List:
3 Item(s)
sceneName: turnoff-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
sceneName: turnon-all-lights, sceneID: (固有のID番号が表示)
[INFO] [1706861436.254126]: Ready.
ターミナル 2 : control_switchbot.py の実行
ターミナル1 の switchbot.launch を起動したままの状態で別のターミナルで control_switchbot.py を実行します.
control_switchbot.py 実行入力
$ source ~/switchbot_ws/devel/setup.bash $ rosrun switchbot_ros control_switchbot.py
control_switchbot.py 実行出力例
devices:
-
name: "bot74a"
type: "Bot"
-
name: "hub2a"
type: "None"
-
name: "plugmini7a1"
type: "Plug Mini (JP)"
-
name: "remote-button10a"
type: "Remote"
-
name: "tapelight7a1"
type: "Strip Light"
-
name: "thermo-hygrometer-f7a"
type: "Meter"
-
name: "air-conditioner"
type: "Air Conditioner"
-
name: "pendant-light"
type: "DIY Light"
control_switchbot.py 実行出力時の SwitchBot デバイス動作の様子
SwitchBot を ROS から操作する感じが伝わりましたでしょうか?
今回の記事はここまでです.
本シリーズ次回の記事では今回実行した Python コード例で扱われていたもの以外の SwitchBot デバイスを ROS から操作するために SwitchBot API を調べて control_switchbot.py にコマンドを追加する様子についてお伝えする予定です.