【ついに自動換気システム完成!】SwitchBotプラグミニをつかってGAS(Google Apps Script)からUSBファンを制御する
こんにちは、えぬ(@nmukineer)です!
SwichBotプラグミニを使ってUSBファンをWiFi経由でON/OFFできるようにしてみました!今回で自動換気システムの製作が完了です!
SwitchBotとは?
SwitchBotシリーズ
「SwitchBot(スイッチボット)」はスイッチやボタンをON/OFFすることができるIoTデバイスです。外出先からエアコンをつけたり、決められた時間に電気をつけたり消したりするようなこと(いろんなシリーズがあるので、多種多様な使い方があります)ができる、超便利なガジェットです。
SwitchBotプラグミニについて
「SwitchBotプラグミニ」は、コンセント(AC100Vが通っている)部分を、WiFi経由でON/OFFすることができるSwitchBotです。
照明や扇風機のような生活家電を接続しておき、音声操作やスマホ操作によってON/OFFすることでスマートライフを実現できます。
今回は、この「SwitchBotプラグミニ」を実際に購入して、M5Stackで測定したCO2濃度に連動させてUSBファンをON/OFFするプログラムをGAS(Google Apps Script)で作ってみました。
SwichBot APIをGASから制御してみる
SwitchBotはAPIを使うことができるため自分で作ったプログラムからSwitchBotを制御することができます!
APIトークンの取得方法
SwitchBot APIのAPIトークンは非常にわかりづらいですが、答えはGithubにあります!
GASのスクリプトプロパティにAPIトークンを設定
スクリプトを書いていく前に、GASのスクリプトプロパティにSwitchBot APIのトークンとシークレット、および、使用するSwitchBotのデバイスID(※)を登録しておきます。(スクリプトプロパティへの登録方法については以下の記事も参照してください)
※デバイスIDの取得方法については次の章を参照してください
SwitchBotのデバイスID取得方法
順番が前後しますが、GASを使ってSwitchBotのデバイスIDを取得する方法を書いておきます。
SwitchBotアプリでSwitchBotをWiFiに接続します。
GASで以下のスクリプトを実行します。
const SWITCHBOT_API_TOKEN = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_API_TOKEN');
const SWITCHBOT_API_SECRET = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_API_SECRET');
const SWITCHBOT_API_HOST = "https://api.switch-bot.com";
const SWITCHBOT_API_HEADERS = {
'Authorization': SWITCHBOT_API_TOKEN,
'Content-Type': 'application/json; charset=utf8'
}
function getDeviceIds() {
const url = `${SWITCHBOT_API_HOST}/v1.0/devices`;
const options = {
'headers': SWITCHBOT_API_HEADERS
}
const res = UrlFetchApp.fetch(url, options);
const json = JSON.parse(res.getContentText());
console.log(json['body']['deviceList']);
}
実行すると、実行ログ画面に以下のようにdeviceId
が現れますので、メモっておきましょう。
自動換気システムのスクリプト遂に完成!
これまでコツコツ作ってきた自動換気システムのスクリプトが完成します!
SwitchBotをコントロールするメソッド(controlSwitchBot)を作成
まずはSwitchBotを制御するメソッドを書きます。引数にコマンド(「turnOn」または「turnOff」という文字列にします)を指定し、その通りにSwitchBotを操作するものとなります。
const SWITCHBOT_API_TOKEN = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_API_TOKEN');
const SWITCHBOT_API_HOST = "https://api.switch-bot.com";
const SWITCHBOT_API_HEADERS = {
'Authorization': SWITCHBOT_API_TOKEN,
'Content-Type': 'application/json; charset=utf8'
}
const SWITCHBOT_DEVICE_ID = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_DEVICE_ID');
function controlSwitchBot(command) {
const url = `${SWITCHBOT_API_HOST}/v1.0/devices/${SWITCHBOT_DEVICE_ID}/commands`;
const data = {
'command': `${command}`,
'parameter': 'default',
'commandType': 'command'
}
const options = {
'method': 'post',
'headers': SWITCHBOT_API_HEADERS,
'payload': JSON.stringify(data)
}
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
console.log(json);
}
SwitchBotを制御するメソッドを使いやすくする
今回、ONまたはOFFの二値制御ですので、controlSwitchBot
メソッドをラップして使いやすくしておきます。
const COMMANDS = {
'turnOn': 'turnOn',
'turnOff': 'turnOff'
}
function turnOn() {
controlSwitchBot(COMMANDS.turnOn);
}
function turnOff() {
controlSwitchBot(COMMANDS.turnOff);
}
このようにしておくことで、
- ONするとき:
turnOn()
- OFFするとき:
turnOff()
と1行書けばSwitchBotを制御できます!
テスト用メソッドを書く
testControlSwitchBotというテスト用メソッドを書いてみます。
function testControlSwitchBot() {
turnOn();
Utilities.sleep(2000);
lineNotify('2秒ONします');
PropertiesService.getScriptProperties().setProperty("VENTILATION", "ON");
Logger.log(PropertiesService.getScriptProperties().getProperty("VENTILATION"));
turnOn();
Utilities.sleep(2000);
turnOff();
lineNotify('OFFします');
PropertiesService.getScriptProperties().setProperty("VENTILATION", "OFF");
Logger.log(PropertiesService.getScriptProperties().getProperty("VENTILATION"));
}
VENTILATION
というスクリプトプロパティを利用して、現在SwitchBotがONなのかOFFなのかを管理するようにしています。
動きは「2秒ONしたあと、OFFする」という単純なものです。このテストメソッドにより、
- SwitchBotとうまく通信できているか
- ON/OFFの動きに問題がないか
- スクリプトプロパティの書き込み、読み出しに問題ないか
ということをテストすることができます。
実行ログは以下です。
lineNotifyメソッドの正体については、以下の記事に書いてますのでご参照下さい。
CO2センサからデータを受信したときにSwitchBotを制御する
さて、いよいよCO2センサとの連携部分を書いていきます!
…と言っても、ほとんど必要な部品は出来上がっているので、あとはそれを組み合わせてロジックを作っていくだけです。
実装する前に、実装したいロジックについて簡単に説明しておきます。
- 1000ppm以上になったら、SwitchBotをONする
- 600ppm以下になったら、SwitchBotをOFFする
これだけです!図にするとこちらのようになります。
行きと帰りの閾値を別々にすることによって、「ヒステリシス」的な特性になっていますね。
ということで、上記のロジックを実装したものが以下のGASコードとなります。(前回までのコードも含んだものになります)
const SWITCHBOT_API_TOKEN = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_API_TOKEN');
const SWITCHBOT_API_HOST = "https://api.switch-bot.com";
const SWITCHBOT_API_HEADERS = {
'Authorization': SWITCHBOT_API_TOKEN,
'Content-Type': 'application/json; charset=utf8'
}
const SWITCHBOT_DEVICE_ID = PropertiesService.getScriptProperties().getProperty('SWITCHBOT_DEVICE_ID');
const COMMANDS = {
'turnOn': 'turnOn',
'turnOff': 'turnOff'
}
const LINE_NOTIFY_API = 'https://notify-api.line.me/api/notify';
const LINE_NOTIFY_TOKEN = PropertiesService.getScriptProperties().getProperty('LINE_NOTIFY_TOKEN');
const AMBIENT_CHANNEL_ID = PropertiesService.getScriptProperties().getProperty('AMBIENT_CHANNEL_ID');
const AMBIENT_WRITE_KEY = PropertiesService.getScriptProperties().getProperty('AMBIENT_WRITE_KEY');
const AMBIENT_API = `http://ambidata.io/api/v2/channels/${AMBIENT_CHANNEL_ID}/data`;
const CO2_THRESHOLDS = {
'lineNotify': 1000,
'turnOn': 1000,
'turnOff': 600
};
const LINE_NOTIFY_TEXT = `【集中力低下注意!】CO2濃度が${CO2_THRESHOLDS.lineNotify}ppmを超えました。今すぐ換気しましょう!`;
function doPost(e) {
const body = JSON.parse(e.postData.contents)
const co2 = body.co2;
const temp = body.temp;
console.log(`CO2濃度: ${co2}ppm`);
console.log(`温度:${temp}℃`)
if(co2 >= CO2_THRESHOLDS.lineNotify) {
lineNotify(LINE_NOTIFY_TEXT + `現在のCO2濃度は${co2}ppmです。`);
}
ambientSend(co2, temp);
if (co2 >= CO2_THRESHOLDS.turnOn) {
setVentilationOn();
} else if (co2 <= CO2_THRESHOLDS.turnOff) {
setVentilationOff();
}
}
function setVentilationOn() {
turnOn();
if (PropertiesService.getScriptProperties().getProperty("VENTILATION") == 'OFF') {
lineNotify(`CO2濃度が${CO2_THRESHOLDS.turnOn}ppmを上回ったため自動換気システムが作動しました`);
PropertiesService.getScriptProperties().setProperty("VENTILATION", "ON");
}
}
function setVentilationOff() {
turnOff();
if (PropertiesService.getScriptProperties().getProperty("VENTILATION") == 'ON') {
lineNotify(`CO2濃度が${CO2_THRESHOLDS.turnOff}ppmを下回ったため自動換気システムが停止しました`);
PropertiesService.getScriptProperties().setProperty("VENTILATION", "OFF");
}
}
function lineNotify(text) {
const options = {
"method" : "post",
"payload": {"message": text},
"headers": {"Authorization":"Bearer " + LINE_NOTIFY_TOKEN}
}
UrlFetchApp.fetch(LINE_NOTIFY_API, options)
}
function ambientSend(co2, temp) {
const data = {
"writeKey": AMBIENT_WRITE_KEY,
"d1": Number(co2),
"d2": Number(temp)
}
const options = {
"method" : "post",
"contentType": "application/json",
"payload": JSON.stringify(data)
}
UrlFetchApp.fetch(AMBIENT_API, options)
}
function testLineNotify() {
lineNotify('テスト通知じゃあああああああああああい!')
}
function testAmbientSend() {
ambientSend(500, 23);
}
function testControlSwitchBot() {
lineNotify('2秒ONします');
PropertiesService.getScriptProperties().setProperty("VENTILATION", "ON");
Logger.log(PropertiesService.getScriptProperties().getProperty("VENTILATION"));
turnOn();
Utilities.sleep(2000);
turnOff();
lineNotify('OFFします');
PropertiesService.getScriptProperties().setProperty("VENTILATION", "OFF");
Logger.log(PropertiesService.getScriptProperties().getProperty("VENTILATION"));
}
function turnOn() {
controlSwitchBot(COMMANDS.turnOn);
}
function turnOff() {
controlSwitchBot(COMMANDS.turnOff);
}
function controlSwitchBot(command) {
const url = `${SWITCHBOT_API_HOST}/v1.0/devices/${SWITCHBOT_DEVICE_ID}/commands`;
const data = {
'command': `${command}`,
'parameter': 'default',
'commandType': 'command'
}
const options = {
'method': 'post',
'headers': SWITCHBOT_API_HEADERS,
'payload': JSON.stringify(data)
}
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
console.log(json);
}
function getDeviceIds() {
const url = `${SWITCHBOT_API_HOST}/v1.0/devices`;
const options = {
'headers': SWITCHBOT_API_HEADERS
}
const res = UrlFetchApp.fetch(url, options);
const json = JSON.parse(res.getContentText());
console.log(json['body']['deviceList']);
}
デプロイ・動作確認
先ほどのスクリプトをデプロイして、動作確認してみましょう!(デプロイ方法については以下の記事を参照)
今回は、M5StackからのPOSTを待つのではなく、M5Stackを模擬した信号をPCから送ってみます。
curlコマンドが使える環境を用意し、下記のコマンドを送信します。(「デプロイID」の部分に自分のGASのデプロイIDを入れて下さい。)
curl -i -X POST 'https://script.google.com/macros/s/デプロイID/exec' -H 'Content-Type:application/json' -d '{"co2":"1000"}'
うまく動きましたか?
動いた場合はLINE通知が来て、SwitchBotがONになります。
次に、SwitchBotをOFFにするコマンドを送ってみます。CO2濃度が600以下だと停止するはずなので、CO2の値を「600」に設定して送ります。
curl -i -X POST 'https://script.google.com/macros/s/デプロイID/exec' -H 'Content-Type:application/json' -d '{"co2":"600"}'
USBファンを接続し、自動換気システムの完成!
SwitchBotの制御もできるようになったので、あとはUSBファンを接続し、ファンを壁の通気口に向けます。
筆者の自宅はマンションなのですが、部屋にこのような通気口がついています。
これに…USBファンを、くっつけます!(ガムテープ!!!)
USBファンはこういったものを買ってます。
ということで、完成しました!
実際の換気能力は今後検証していきます!
自動換気システムの全貌はこちらです。
まとめ
SwitchBotプラグミニを使用して、CO2センサから受けたデータを基にしてGASからUSBファンの動きを制御するプログラムを作ってみました。
ハードウェア、ファームウェア、Web APIと、一連のIoTプロトタイピングを学ぶことができるので、トライしてみてはいかがでしょうか?
ここまでお読みいただきありがとうございました!