きっかけ
年末年始だ〜。まとまった時間がとれる〜なんて思っていたら、ムクムクと制作意欲が湧いてきました。
そんな折に、家の洗面台の電球が切れ、Amazonで買おうなんて検索していたら見つけたのがこれ!!
【Amazon Alexa認定 LED電球】OHLUXスマート電球
え、スマートLED 2個で2700円!?
アレクサとかにも繋がるし、ちょっと調べてみたらIFTTTとか、Tuya API(?)など利用して自動化もできそう。
「これは安いぞ」と思い大人の自由研究ということで、スマートホーム化で遊んでみることにしました。
なにを作るか
最初はアレクサのアプリを作って音で操作とかも考えましたが、正直ハードウェアスイッチの利便性には及ばないし、子供に遊ばれるのが目に見えてる。。。。
なんて思っていたら
朝起きて、洗面台で顔洗ってる時に、色で、今日の天気がしれたら最高じゃん」
ということに気付きました。
なので今回はそれを作ります。
どういう構成にするか
LEDの制御方法は主に3つあります。
1.LED操作スマホアプリ「SmartLife」での操作
SmartLifeアプリを用いることで、スマホから色とか変えられます。
また簡単な自動化レシピもつくることができます。
ただ、なぜかトリガーに設定できるのが「現在の天気」だけだったり、
色も選べなかったりと痒いところに手が届きません。
2. IFTTT連携での操作
購入時は、このIFTTT連携を採用しようと考えていました。
LEDはSmartLifeというアプリと連動でき、SmartLifeはIFTTTと連動できるためです。
しかし、いざレシピを作ろうとしてみるとIFTTTでのONトリガーが謎のエラーにより一向に作れませんでした。
ググっても、いまいちhitせず、うまく連携できていない様でした。
また、IFTTTは有料化して無料はかなりレスポンス悪くなってきてるとのこと。残念です。
3. Tuya APIでの操作
現在、中華製のスマートホームデバイスは多くがTuya APIのプロトコル採用(OEM?)しているらしく
自身の購入したものもそうでした。そのためこのTuya APIで操作することにしました。
また、Tuya APIで操作するためには、LEDと同一のwifiネットワーク上で操作元のプログラムが動作している必要があります。
そのため今回のLED操作プログラムを動かす家内サーバを用意する必要がありました。
調べたところ Node.js にて Tuya APIは動かせる様です。
ずっとノートPCをONにしとくわけには行かないと思っていたところ、
押入れの中に「RaspberryPi」が眠っていることに気付きました!!!これを使わない手はありません。
動作させるまで + 実際のコード
大きく3つのパートに別れます。
1. Tuya API動作させるまで
ここが今回一番特徴的なところでした。
とちゅう変なバグ(後述)を踏んでしまったのですが、それ以外は先人の方をならえばいけると思います。
めちゃ丁寧に書かれてる本家setup
https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md
参考記事
https://qiita.com/plageoj/items/dd2f1c8b55c39625d550
TuyAPI: これを使ってNode.jsからTuyaAPIを叩けます
https://github.com/codetheweb/tuyapi
大きな流れとしては
1. Tuya Iotのサイトでディベロッパー登録し、プロジェクトを作ってプロジェクトのAPI KEYとAPI SERCRETを取得
2. tuya-cli linkコマンドをつかって、LEDとリンクし、LED操作用のAPI IDとKEYを取得する
という流れです。
(自身が踏んでしまった変なバグ)
自分が踏んだのは、1でディベロッパー登録した後になぜか、認証を求められプロジェクトが作れないというバグ。
サポートに問い合わせても判然とせず、、、ググったら、同様の現状になっている人がいました。
アカウント再発行で行けたよって書いてあったので別のメアドでアカウント作り直したら行けました。謎です。w
2. 実際のプログラム本体を書く
ここが本体なのですが、実は一番さくっとできた部分かもしれません。w
動けばOKという思想で作られておりますので、コードはツッコミだらけかもしれませんがご了解ください。
本家のサンプルコードをいじって作りました
https://github.com/codetheweb/tuyapi
Yahoo RSSから天気を取得し、それにより表示される色を変えています。
また、雪(緑) => 雨(青) => 曇り(グレー) => 晴(オレンジ)
の順番で重要なステータスと判断し、それぞれの文字が含まれるかで判定してます。
ここら辺は改善の余地ありそうです。
// main.jsrequire('date-utils');constfs=require('fs');constclient=require('cheerio-httpcli');constTuyAPI=require('tuyapi');// 1時間以内に、LED色変更を行っている場合は何もしないで終了するtry{letlastOutputDate=fs.readFileSync('lastoutputdate.txt');if((newDate().getTime()-newDate(lastOutputDate).getTime())<60*60*1000){console.log("Exit because the last update is too soon. lastOutputDate:"+lastOutputDate);return;}}catch{console.log('lastoutputdate.txt not found!');}// 0:00 - 17:00以前なら今日の天気, 17:00 - 24:00なら明日の天気を取得するvartargetDay=newDate(newDate().getTime()+7*60*60*1000).toFormat("DD");vartargetDayReg=newRegExp(targetDay+"日")constdevice=newTuyAPI({id:'XXXXXXXXXXXXXXXXXX',key:'YYYYYYYYYYYYYYYYYY'});letstateHasChanged=false;// Find device on networkdevice.find().then(()=>{// Connect to devicedevice.connect();});// Add event listenersdevice.on('connected',()=>{console.log('Connected to device!');});device.on('disconnected',()=>{console.log('Disconnected from device.');});device.on('error',error=>{console.log('Error!',error);});device.on('data',data=>{console.log('Data from device:',data);//DPS MEMO://[dps 1]: switch ON/OFF(true/false)//[dps 2]: mode("white"/"colour")//[dps 5]: color code「RGB00HSV」形式 (ex. red=ff00000000ffff)if(!stateHasChanged){// Yahoo RSSから天気取得letRSS="https://rss-weather.yahoo.co.jp/rss/days/3610.xml";//福島県のYahoo天気RSSclient.fetch(RSS,{},function(err,$,res){if(err){console.log("error");return;}$("item > title").each(function(idx){vartitle=$(this).text();if(title.match(targetDayReg)){console.log(title);// 雪かどうかdevice.set({dps:2,set:'colour'});if(title.match(/雪/)){console.log("雪です")device.set({dps:5,set:'00ff00004511ff'});}elseif(title.match(/雨/)){console.log("雨です")device.set({dps:5,set:'0000ff004511ff'});}elseif(title.match(/曇/)){console.log("曇りです")device.set({dps:5,set:'808080004511ff'});}elseif(title.match(/晴/)){console.log("晴れです");device.set({dps:5,set:'ff4500004511ff'});}else{console.log("想定外の何か");device.set({dps:5,set:'660099004511ff'});}//LED変更を記録stateHasChanged=true;fs.writeFileSync("lastoutputdate.txt",newDate().toString());}});});}});// Disconnect after 10 secondssetTimeout(()=>{device.disconnect();},10000);
3. ラズパイでプログラムを走らせる
ここも結構苦労しました。ラズパイを触るのはほぼ初めてだったためと、
結構いろんな角度からの情報がネット上にあり、いいとこ取りするのに時間がかかったためです。w
やったことと参考にしたページを箇条書きします。
OSインストール
公式から、Raspberry Pi Imager使って、micro SDにOSを入れます。
https://www.raspberrypi.org/software/言語/wifi/ユーザパスワード設定(初期設定)
(参考): https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-setup/
(注)バグってて、初期の変更では聞かないみたい、確かにできてなかった。IP固定(SSHのため)
https://mugeek.hatenablog.com/entry/2019/05/27/230256SSH公開鍵設置
https://tool-lab.com/raspi-key-authentication-over-ssh/VNC接続(まだ未設定)
https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-vnc/nvmを利用したnodeのインストール
https://laboradian.com/how-to-use-nvm/RaspberryPi3で初めてcrontabを使う前に
https://qiita.com/Higemal/items/5a579b2701ef7c473062cronを秒単位で指定する方法
https://tech.mktime.com/entry/376
ちなみに上記を参考にcrontabは下記の様に設定しました。
15秒おきにスクリプト走らせています。
# crontabLANG=ja_JP.UTF-8
*****for i in`seq 0 15 59`;do(sleep${i}; /home/pi/.nvm/versions/node/v14.15.3/bin/node /home/pi/dev/weather-led/main.js >> /home/pi/dev/weather-led/log.txt;)& done;
動作の様子
0:00 - 17:00以前なら今日の天気, 17:00 - 24:00なら明日の天気を取得するようにしてあります。
そして写真の様に
雪(緑)
雨(青)
曇り(グレー)
晴(オレンジ)で光ります。
洗面台は普通にハードウェアスイッチでのON/OFFです。
明日は雪予報なので、今日夜は緑に光ってました!
実際に便利なの?
これは正直まだ未知数です。
- ラズパイ+LEDが安定動作するのか。
- 家族が受け入れてくれるか
- 自分が実際便利になるか(天気アプリを開く回数が減るのか)
こちらは一ヶ月ぐらい使ってみてわかってくると思います。
何か特筆事項がでてきたら追記します。
また、
- ラズパイの死活監視
- 実運用でのチューニング
- 現在はLED ONかどうかを頻繁に問い合わせ(ポーリング)形式になっている => LEDがONになった時点でイベント発火する形式にできれば良いのだが、、、
などはFuture Workですね。
まとめ
感想ですが、
- スマートLEDはすごい安くてびっくりした。Tuya API利用までは少し遠回りしたけど、わかってしまえばシンプルで使いやすいAPI
- 家に眠っていた「ラズパイ(Model3 B)」が大活躍した。数千円というこの値段で小型PCが買えてしまうというのが凄すぎる。まだまだ潜在能力を秘めていそう!
- 冬休み自由研究やることで、今まで触ったことのない新しい技術に触れられたのは良かった!!
- 先人の皆様のお力をお借りしまくり ました。ありがとうございました!!!
是非良かったら皆さまも、冬休みの自由研究してみてください〜!!!
あと、お年玉としてLGTMいただけたら嬉しいです。m(_ _)m 良いお年を〜〜。