ホーム » 「SwitchBot」タグがついた投稿 (ページ 2)
タグアーカイブ: SwitchBot
Switchbot APIが急に動かなくなった
Switchbot のデータを、OpenWonderLabs / Switchbot API v1.1 を使って munin でグラフ化していたが、2024/12/16,16:35(JST) から急にデータが取れなくなっている。
自作の Shell Script の問題かと思ったが、Python のコードでも Forbidden が表示されるので、原因は別かな。
api.switch-bot.com のトラブルかなぁ…
t=1734352549278
nonce=83e7a2f9-7ece-4971-9157-9aac14cd229f
sign=Frytn5FFDK0dUYE9XUEQF+v30V1WhAGKIo4qHAMiy7I=
{
"message": "Forbidden"
}
(2024-12-17追記)
2024/12/17(火) 12:00 に復旧した様子。こっちで特に何かしたわけでもなく、勝手に復帰した。
やっぱりサーバの問題だろうな。
復帰状態でブラウザで https://api.switch-bot.com/ にアクセスすると、Forbidden じゃなく { “message”:”Missing Authentication Token” } が表示される。(昨日トラブル時は Forbiddenだった)
Switchbot さんには、先日 温度計の battery 項目が 100% で正しい値が取れないって報告してるし、その辺の修正が利いてないかと期待したけど、相変わらず 100% だな。
MuninでSwitchBot CO2センサーのプラグイン
Muninで、Switchbot の CO2 センサーをモニタリングするためのプラグイン
#!/bin/bash
#%# family=auto
#%# capabilities=autoconf
available="yes"
#
# SwitchBot
#
token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
secret="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
swbot_url="https://api.switch-bot.com"
# for v1.1
url_list_v11="${swbot_url}/v1.1/devices"
t=$(/bin/date +%s%3N) # time = Epoch time 13 digits
nonce=$(/usr/bin/uuidgen) # uuid
sign=$(echo -n "$token$t$nonce" | /usr/bin/openssl dgst -sha256 -hmac "$secret" -binary | /usr/bin/base64 -w 0)
# SwitchBot meter CO2センサーのデバイスID
deviceId="xxxxxxxxxxxx"
function status() {
url_list_v11_meter="${url_list_v11}/${deviceId}/status"
/usr/bin/curl -s --request GET \
-H "Content-Type: application/json" -H "Authorization: ${token}" \
-H "sign: ${sign}" -H "nonce: ${nonce}" -H "t: ${t}" \
"${url_list_v11_meter}" \
| /usr/bin/jq -r '.body | "temperature.value " + (.temperature|tostring) + "\nhumidity.value " + (.humidity\
|tostring) + "\nCO2.value " + (.CO2|tostring)'
}
case $1 in
autoconf )
if [ "$available" = "yes" ]; then
echo "yes"
exit 0
fi
;;
config)
echo "graph_title SWBOT Meter CO2 温度/湿度/CO2 (リビング)"
echo "graph_category sensors"
echo "graph_vlabel 温度[C]/湿度[%]/CO2[ppm]"
echo "graph_args -l 0 -u 70"
echo "temperature.label 温度[C]"
echo "temperature.draw LINE2"
echo "temperature.colour 00FF00"
echo "temperature.warning 30"
echo "humidity.label 湿度[%]"
echo "humidity.draw LINE2"
echo "humidity.colour 00E0FF"
echo "CO2.label CO2[ppm]/100"
echo "CO2.draw LINE2"
echo "CO2.cdef CO2,0.01,*"
#echo "CO2.warning 25"
exit 0
;;
esac
status
Muninで取得した値を、nagios4 で確認するためのプラグイン。
#!/usr/bin/perl
use strict ;
use warnings ;
use Net::Telnet ;
my $telnet = new Net::Telnet( Host => "127.0.0.1" , Port => 4949 , Timeout => 30 ) ;
$telnet->open() or die( "Can't connect" ) ;
$telnet->waitfor( '/#.*$/' ) ;
# munin で読み込む項目を指定
$telnet->print( "fetch switchbot_meter_co2\n" ) ;
my $flag = 0 ;
my %value = () ;
# データを読み込む
while( my $line = $telnet->getline() ) {
last if ( $line =~ /^\.$/ ) ;
if ( $line =~ /^([0-9a-zA-Z_]+)\.value\s+([\.0-9]+)\s*$/ ) {
$value{$1} = $2 ;
$flag = 1 ;
}
}
# nagios プラグインとして範囲を確認
my $st = 0 ;
my $item = "-" ;
my %status = ( 0 => "OK" , 1 => "Warning" , 2 => "Critical" , 3 => "Unknown" ) ;
if ( exists( $value{'temperature'} ) ) {
if ( $value{'temperature'} > $ARGV[1] ) {
$st = 2 ; $item = "temperature" ;
} elsif ( $value{'temperature'} > $ARGV[0] ) {
$st = 1 ; $item = "temperature" ;
}
}
if ( exists( $value{'CO2'} ) ) {
if ( $value{'CO2'} > $ARGV[3] ) {
$st = 2 ; $item = "CO2" ;
} elsif ( $value{'CO2'} > $ARGV[2] ) {
$st = 1 ; $item = "CO2" ;
}
}
if ( !$flag ) {
$st = 3 ; $item = "Error" ;
}
# 最終結果の出力
printf( "SBMT_MeterCO2 %s %s %2.1f[C] %2.0f[%%] %4.0f[ppm]\n" ,
$status{$st} , $item ,
$value{'temperature'} , $value{'humidity'} , $value{'CO2'} ) ;
exit $st ;
Nagios のプラグインを Perl で書いておいたけど、少しでも軽い処理にしたいので lua(lua50) で書き直し
#!/usr/bin/lua
local temp , hum , co2 ;
local temp_w_max , temp_c_max = 25 , 30
local hum_w_max , hum_c_max = 11 , 22
local co2_w_max , co2_c_max = 2500 , 5000
function find_value( str , pattern )
local p_start , p_end = string.find( str , pattern )
local s_val = string.sub( str , p_end + 1 )
local p_nl = string.find( s_val , "\n" )
local val = string.sub( s_val , 1 , p_nl )
return tonumber( val )
end
-- 温度条件
if table.getn(arg) >= 2 then
temp_w_max = tonumber( arg[1] )
temp_c_max = tonumber( arg[2] )
end
-- 湿度条件
-- if table.getn(arg) >= 2 then
-- hum_w_max = tonumber( arg[1] )
-- hum_c_max = tonumber( arg[2] )
-- end
-- CO2条件
if table.getn(arg) >= 4 then
co2_w_max = tonumber( arg[3] )
co2_c_max = tonumber( arg[4] )
end
fh = assert( io.popen( "/usr/bin/echo -e 'fetch switchbot_meter_co2\nQUIT\n' | /bin/nc 127.0.0.1 4949" , "r" ) )
lines = fh:read("*a")
fh:close()
temp = find_value( lines , "temperature.value" )
hum = find_value( lines , "humidity.value" )
co2 = find_value( lines , "CO2.value" )
if temp >= temp_c_max then
mes = "Critical temperature"
ret = 2
elseif temp >= temp_w_max then
mes = "Warning temperature"
ret = 1
elseif co2 >= co2_c_max then
mes = "Critical CO2"
ret = 2
elseif co2 >= co2_w_max then
mes = "Warning CO2"
ret = 1
else
mes = "OK -"
ret = 0
end
-- 結果を返す
print( string.format( "SWBT_MeterCO2 %s %3.1f[C] %2.0f[%%] %3.0f[ppm]" , mes , temp , hum , co2 ) )
os.exit( ret )
比較検証
「/usr/bin/time -v コマンド」を用いて、各プログラムのメモリ使用量などで比較してみた。lua で書いたものが一番軽量。luac でコンパイルも試したけど、luac で生成されたバイトコードを起動するために、lua コマンドを使うため、コンパイルの効果は薄かった。
Munin の Shell を使った SwitchBot 参照 -- 最大メモリ使用量 17,960 kB nagios4 の Munin 参照の Perl プログラム -- 最大メモリ使用量 10,176 kB nagios4 の Munin 参照の lua5.0 プログラム -- 最大メモリ使用量 2,604 kB
Switchbot 温湿度CO2センサー
最初の確認
{
"statusCode": 100,
"body": {
"version": "V1.5",
"temperature": 24.9,
"battery": 100,
"humidity": 58,
"CO2": 999,
"deviceId": "xxxxxxxxxxxx",
"deviceType": "MeterPro(CO2)",
"hubDeviceId": "000000000000"
},
"message": "success"
}
Munin, nagios4 でモニタリング
先に、温湿度モニタで実験してあったから、CO2も含めた Munin でのモニタリング、nagios4 での監視も早々に動き出す。
半日ほどモニタリングした状況だと、朝寒く暖房をかけると、1500[ppm]程から、6000[ppm]まで一度に増えている。CO2モニターを販売している製品の資料を見ると、1000[ppm]を越えると眠気や不快感といった記載もあるし、2500[ppm]を越えると健康被害が予想されるといった記載もある。でもストーブ付けたら、簡単に越えてしまっている。
定常状態(部屋に猫1匹)だと500[ppm]ほどか。

Switchbot CO2センサーようやく配送
10/20に注文した SwitchBot の 温湿度 CO2 センサーだけど、かなり待たされた。

今日は急遽宿直になったし、黒猫なら宿直明けに配送分配所に受け取りに行こうとおもったけど、黒猫のトラッキングIDがない。よくよく見ると 配送 Amazon になってる。そっか、”宅配”じゃないんだ。
Switchbot 温湿度計のファームウェアが更新できない
Switchbot API を使って温湿度計のデータを取得できるようにはなったけど、バッテリー状態は常に 100% 表示。

Switchbot の OpenWonderLabs / SwitchBotAPI の README だと、Swichbot 温湿度計の最新は V4.2 と書いてあるけど、アプリで確認するけど、V0.8 の表示。これが原因かと温湿度計のファームウェアの更新をかける(裏ボタンを押しながら乾電池ONでアプリから更新を行う)けど、ファームウェア更新の表示はでるけど、バージョンは相変わらず V0.8 のまま。
原因不明だなぁ…
curl で switchbot API v1.1 を呼出す
Amazon タイムセールで、SwitchBot CO2 センサー付き温湿度計の割引がでていたので、Hub mini セットで発注。CO2センサーは以前 CCS811 でモニタリングしていたけど、もともと精度が悪かったし異常値がでるようになってモニタリングをやめてるので、SwitchBot で復活させたくて、買ってしまった。だけど、CO2センサーは発送が始まらず、Hub mini だけが届く。ということで、ひとまず Hub mini で遊ぶ。
curl で switchbot API の情報を取得する
Python などで API をたたく記事が多いけど、もう少しシンプルにできないかということで、手抜き curl で試してみる。
まずは、最もシンプルな、v1.0 で取得する方法。
最初の token, secret には、SwitchBot スマホアプリで入手したものを書き込む。(v1.0では secret 使ってないけど)
#!/bin/bash
token="xxxxxx....xxxxxxx"
secret="yyyy...yyy"
url_list_v10="https://api.switch-bot.com/v1.0/devices"
curl -s -H "Authorization:${token}" "${url_list_v10}"
switchbot API v1.1 で取得する
ちょっと面倒だけど、セキュリティ的には v1.1 で取得するのが定番。最初は Unauthorized で失敗して色々と試行錯誤したけど、openssl … -binary がキモだった。(こちらの記事を見て、sha256 のハッシュの形式が違うのに気づけた。)
#!/bin/bash
token="xxxxxx....xxxxxxx"
secret="yyyy...yyy"
t="$(/usr/bin/date +%s%3N)" # time = Epoch time 13桁
nonce="$(/usr/bin/uuidgen)" # uuid
sign=$(echo -n "$token$t$nonce" \
| /usr/bin/openssl dgst -sha256 -hmac "$secret" -binary \
| /usr/bin/base64 -w 0)
url_list_v11="https://api.switch-bot.com/v1.1/devices"
curl -s --request GET \
-H "Content-Type: application/json" \
-H "Authorization: ${token}" \
-H "sign: ${sign}" -H "nonce: ${nonce}" -H "t: ${t}" \
"${url_list_v11}"
取得した json コンテンツから特定のデバイスの情報を抜粋する
結果は、JSON 形式なので、jq を使って必要な場所だけ抜粋する。
$ bash swbot.sh \ | jq '.body.deviceList[] | select( .deviceId == "ZZZZZZZZZZZZZZZZ")'
Switchbot meter plus から温度,湿度を表示
Switchbot Hub mini が無い時は、温湿度計(meter plus)からのデータ取得は Bluetooth 経由で動かしていたので、Raspberry Pi で温度を取得していたが、この方法であれば LAN 接続であればどこからでも取得可能なので便利。
(略)
swbot_meter="ZZZZZZZZZZZZZZZZ"
url_list_v11_meter="${url_list_v11}/${swbot_meter}/status"
curl -s --request GET \
-H "Content-Type: application/json" \
-H "Authorization: ${token}" \
-H "sign: ${sign}" -H "nonce: ${nonce}" -H "t: ${t}" \
"${url_list_v11_meter}" \
| jq -r '.body | "Temperature: " + (.temperature|tostring) + "C\n" \
+ "Humidity: " + (.humidity|tostring) + "%"'
これで、温度、湿度がとれる。これなら munin 用のスクリプトも shell で簡単に書けそう。だけど、バッテリー残量(.battery)は 60% 台まで落ちているはずだけど、100% なんだよな。他の SwitchBot Plug でも、電力値が取れなかったりと SwitchBotAPI は、全機能を網羅していない様子。
Switchbot Plug の制御
電気毛布が必要な時期、外出時の電源を切り忘れるのを防ぐために、昨年導入していた Switchbot Plug 。
スマホの SwitchBot アプリのタイマー機能で朝に強制オフの制御していたけど、寝る時にスイッチを入れるのは、自分が不在の時だとムダだし、homebridge や cron で制御するのも面白そう。
switchbot-utility のインストール
ということで、Raspberry-Pi に、switchbot-utility をインストール。
((( 事前にSwitchbot アプリは設定済み ))) $ sudo pip3 install switchbot-utility $ cd /usr/local/lib/python3.9/dist-packages/switchbot_utility
制御するには、Switchbot アプリのトークンと秘密鍵が必要なので、アプリを起動して「プロフィール」、「設定」の画面を開いて、「アプリバージョン」の表示を 10 回連打すると、「開発者向けオプション」を表示できる。この画面を開いてトークンとクライアントシークレットをコピーし、上記の switchbot_utility のフォルダ内に、settings.json のファイル名で保存。

Python で以下のスクリプトを実行すると、switchbot-utility で扱えるデバイスの一覧 deviceList.txt が作られる。
((( settings.json )))
// Switchbot アプリで取得したトークンとシークレットを、
// switchbot_utilitiy のフォルダに settings.json で保存しておく
{
"token": "xxxxx....",
"secret": "yyyyy...."
}
((( devicelist.py )))
// Python で以下のスクリプトを実行すると、deviceList.txt が作られる。
// 以下を devicelist.py で保存し、python3 devicelist.py で実行!
from switchbot_utility.switchbot import Switchbot
switchbot = Switchbot()
switchbot.devicelist()
((( deviceList.txt )))
441793xxxxxx, 電気毛布, Plug, 000000000000
C5B496xxxxxx, エアコン, Bot, 000000000000
実際に、Switchbot Plug を動かすために、下記のscriptでスイッチを制御できるようにしてみた。
#!/usr/bin/python3
# -*- mode: python; coding: utf-8; tab-width: 4 ; -*-
# SwitchBot をON/OFFする
import sys
import time
import os
from switchbot_utility.switchbot_plug import SwitchbotPlug
# ~~~~~~~~~~~~~~ ~~~~~~~~~~~~~
# 制御するSwitchBot に合わせて、上記~~~ を書き換える。
sb_dir = '/usr/local/lib/python3.9/dist-packages/switchbot_utility'
# Switch Bot Plug MAC ADDR
# deviceList.txt 調べた MACアドレスを記入
sb_plug_macaddr = '441793xxxxxx'
# コマンドライン引数プロセス名
script_file_name = sys.argv.pop( 0 )
# コマンドライン引数 -d <デバイスID>
while len( sys.argv ) >= 2 and sys.argv[0] == '-d' :
sys.argv.pop( 0 )
sb_plug_macaddr = sys.argv.pop( 0 )
# setting.jsonを読み込むため
os.chdir( sb_dir )
# SwitchBot Plug に接続
sb_plug = SwitchbotPlug( sb_plug_macaddr )
# ~~~~~~~~~~~~~ この部分に制御対象用のコンストラクタを書けばいい
if len( sys.argv ) == 0 :
# 引数なしは、状態を表示
print( sb_plug.get_power() )
elif len( sys.argv ) == 1 :
# status | on | off | toggle or turn
arg = sys.argv.pop()
if arg == 'status' :
# exitでスイッチ状態を返す
sys.exit( 0 if sb_plug.get_power() == 'on' else 1 )
elif arg == 'on' :
sb_plug.turn_on() # ON
elif arg == 'off' :
sb_plug.turn_off() # OFF
elif arg == 'toggle' or arg == 'turn' :
# スイッチを反転
pw = sb_plug.get_power()
if pw == 'on' :
sb_plug.turn_off()
elif pw == 'off' :
sb_plug.turn_on()
このプログラムを、homebridge-cmdswitch2 の設定に加える。
{
"platform": "cmdSwitch2",
"name": "cmdSwitch2",
"switches": [
{
"name": "電気毛布",
"on_cmd": "/usr/local/bin/switchbot-plug.py on",
"off_cmd": "/usr/local/bin/switchbot-plug.py off",
"state_cmd": "/usr/local/bin/switchbot-plug.py status"
}
]
}
ということで、「OK Google, 電気毛布を点ける」でON、朝は起床時間にあわせたタイマーでOFF完成。
SwitchBot プラグを使ってみた
SwitchBot プラグを使ってみた。スマホのSwitchBot アプリで初期化を行うけど、SwitchBot-XXXX の WiFi につながるけど初期化ができない。原因が分からず四苦八苦したけど、SwitchBot のホームページで確認したら、SwichBot アプリのローカルネットワークの接続権限が Off になっていた。

ただ、Raspberry-Pi で動かしている Homebridge では対応していない様子。
SwitchBot プラグに電気毛布をつなげたので、ひとまずスマホアプリにて「ON/OFFタイマー」を設定する。








