タグアーカイブ co2

著者:yamamoto.yosuke

SwitchBot を ROS から利用する – データ取得デバイスの追加方法

本シリーズ前回の記事 SwitchBot を ROS から利用する – データ取得編 掲載以降,手元にある SwitchBot デバイスの種類が増えてきました.

そこで今回の記事では switchbot_ros でまだ対応していないデバイスのデータを取得・パブリッシュするためにコードを追加する様子を紹介します.追加例としてデバイス「SwitchBot CO2センサー(温湿度計)」のデータを取得して ROS Topic としてパブリッシュできるようにします.

SwitchBot API の確認

追加したいデバイスが SwitchBot API で対応していないと switchbot_ros 側でも対応はできないので最初に SwitchBot API のドキュメントを調べます.

SwitchBot API v1.1 ドキュメント にデバイスのリスト取得とステータス取得の項目に「Meter Pro CO2」の記述があり,これが今回追加してみたデバイス「SwitchBot CO2センサー(温湿度計)」に対応したものとなっていました.

制御コマンドの一覧には CO2 センサーらしき記述が(少なくとも本記事執筆時には)ありませんので「SwitchBot CO2センサー(温湿度計)」には取得系コマンドのみが対応していて,制御系コマンドは無いようです.

SwitchBot API ドキュメントにある「SwitchBot CO2センサー(温湿度計)」のステータス取得で返されるデータの表を下に抜粋しましたので確認してみます.

Meter Pro 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_ros に機能追加したいデバイス「SwitchBot CO2センサー(温湿度計)」について SwitchBot API が対応していることと API により取得できる測定値が分かりましたので実装してゆきます.もう少し具体化すると「SwitchBot CO2センサー(温湿度計)」から API 経由で得られた

  • 温度
  • 湿度
  • バッテリーレベル
  • CO2濃度

の4つの値を ROS Topic としてパブリッシュします.

SwitchBot API によるデータの取得と ROS Topic のパブリッシュプロセスは switchbot_ros にある既存のルーチンをそのまま利用できますので今回新たに実装する部分は大まかには次の2つです.

  • 「SwitchBot CO2センサー(温湿度計)」に対応したメッセージ型の定義
  • 「SwitchBot CO2センサー(温湿度計)」メッセージ型に取得データを代入

先に結論としてコードの追加部分を下に記載してしまいます.ファイルとしては3点,追加箇所としては5点です.

  1. switchbot_ros / msg / MeterProCO2.msg (ファイル追加)
    • 「SwitchBot CO2センサー(温湿度計)」に対応したメッセージ型の定義
  2. switchbot_ros / CMakeLists.txt (記述追加)
    • MeterProCO2.msg の add_message_files() への追加
  3. switchbot_ros / scripts / switchbot_status_publisher.py (記述追加)
    • インポートクラス MeterProCO2 の追加
    • パブリッシャーのメッセージクラス設定においてデバイスタイプ MeterPro(CO2) の場合のメッセージクラス MeterProCO2 を追加
    • MeterProCO2 の場合のメッセージクラス各要素への取得データ代入処理の追加

追加デバイス用メッセージの定義

今回追加する「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 内で利用するためにメッセージクラス MeterProCO2import しておきます.

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_ros に追加した機能の動作確認

まず利用可能な SwitchBot デバイス名リストを取得・確認してから,得られた新規追加したデバイス名を指定して SwitchBot デバイスのステータスデータの取得と ROS Topic へのパブリッシュを行い,実際にパブリッシュされているかを ROS Topic を表示して確認します.

実行方法は今回機能追加するより前の方法と同じで,launch 時にオプション指定するデバイス名を変えるだけです.

利用可能な SwitchBot デバイス名の取得

ターミナル 1 : switchbot_ros の実行

SwitchBot API 経由で今回追加した「SwitchBot CO2センサー(温湿度計)」の「デバイス名」と「デバイスタイプ」が取得できることを確認します.ユーザの SwitchBot アカウントで登録されているデバイスの「デバイス名」と「デバイスタイプ」は switchbot.launch を実行すると表示されます.

(下記 launch オプションの YOUR_TOKENYOUR_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 デバイスのステータスデータの取得・パブリッシュ

「SwitchBot CO2センサー(温湿度計)」のステータスデータを取得してパブリッシュされている ROS Topic を表示して確認してみます.前述の switchbot.launch の実行出力例からデバイス名が co2sensor-ba1 となっています.

ステータスデータを取得する場合は switchbot.launch 実行時に次の2つのオプションを追加します.

  • pub_status:=true ステータスを取得・パブリッシュを実行するオプション true/false
  • pub_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
  • 注1) 上記テキストボックスの横スクロールで全 launch オプションが表示されます.
  • 注2) 各 launch オプションについて
    • YOUR_TOKENYOUR_SECRET は各々の SwitchBot アカウントのトークンとシークレットに置き換えて実行してください.
    • pub_status:=true でステータスを取得・パブリッシュを実行します.
    • pub_device_name:=co2sensor-ba1co2sensor-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 にパブリッシュされている様子が見て取れるかと思います.

今回の記事はここまでです.