4ch手作りスマートプラグというのを作った。
Youtubeで見かけて自分でもいずれ作りたいなあと思っていたがとうとうできた。動作も完璧だし、物理ボタンでも操作できる。
外部サービスも使っているがサブスクはかからないので心置きなく使い倒せる。
では作り方とプログラムコードを公開する。
4chスマートプラグに必要な機器
1chタイプとの差分
先日1チャンネルのスマートプラグを作って記事にしたのでそれも参考にしてほしい。そしてそのハードウェアの差分のみをここに述べておく。
- コンセントメス+3個
4チャンネルなのでコンセントのアウトレットが4口になり当然ながら全部で4口必要になる
- ワンタッチコネクター5口
これは元線から来たAC電源を4個に分岐させるのを簡単に実現させるための材料で必ずしもこれを使わなくてもできる
- 4chリレー
これがないと始まらない。これを手に入れるのに結構日数がかかった。AliExpressで注文したのがなかなか入らなかったしいざ入荷して使ってみたら不良品だったので結局Amazonで買った。Amazonならやや高いが注文して翌日入手できる
- 一応機能を完璧にするためにプッシュスイッチもつけた。スマホやスマートスピーカーでオンオフ制御するだけではなく物理スイッチでも制御できたほうが便利なのは間違いない。もちろん物理スイッチを切り替えてもスマホのほうには反映されるようにプログラミングする。4個
- ケースは大きめ
前回の1チャンネルタイプよりかなり材料を使うのでケースはかなり大きめになってはっきりいって格好は良くない。仕方ない。市販のプラグではなく自分専用なので我慢だ。 - Raspberry Piをサーバーとして待機させる
これが一番差分としてはヘヴィだと思うんだけどこれがハードル高すぎてだいたいの人が断念してしまうのではなかろうか。かくいう自分もおそらく1年前ぐらいは軽く断念していた案件だが1年近く勉強すると結構わかるようになる。
- ブレッドボードの電源供給部
直結してしまうとかほかで代用する手段はあるが可逆的に作っておくならこういうので接続しておくほうがいいともいえる。
4チャンネル自作スマートプラグ構想
1chの自作スマートプラグとの違い
1チャンネルのときはSinric Proというスマートデバイス管理サービスを使ったが、あれは無料では3個までデバイス登録ができ、4個目からは年間3ドルだったかのサブスクが必要になる。
年間3ドルならそんなに高くはないが一生払い続けるかと思うとためらってしまう。
なのでSinric Proとは決別することにし、Blynkを使うことにした。
Blynkも完全無料のスマートデバイス管理サービスではないがデバイス1個というかウィジェット買い切り、しかも作り直してウィジェットを削除すると別のことに使えるので大変助かる。
–追記–
Blynkもウィジェット(ボタンとかスライダーとかの部品)が有料なので無料で使い放題を実現するべく自宅ラズパイにBlynkサーバーをインストールして成功した。
【Blynk】自前サーバーはサブスクなしでウィジェット使い放題ホームオートメーションできる
–追記ここまで–
アレクサからもGoogleアシスタントからも操作可能
Blynkにデバイスを登録するがAlexaやGoogleAssistantからも使えなければ面白くない。
幸いBlynkに登録したデバイスはそんなに複雑なことをしなくともAlexaやGoogleからも呼び出しできる。
4チャンネル自作スマートプラグ作成手順
ハードを組み立てる
▼まずはハードの仕上がりを見てもらおう。といっても冒頭画像と一緒だが。
Blynkアプリでピン番号決める
Blynkアプリを開きボタンウィジェットを4個配置する。
それぞれのバーチャルピン番号を決め、オフで1,オンで0という信号を送るよう設定する。
ArduinoIDEでプログラム(スケッチ)つくる
#define PUSH_BUTTON
#include <BlynkSimpleEsp8266.h>
#define BAUD_RATE 115200
#define DEBOUNCE_TIME 500
// define the GPIO connected with Relays and switches
#define DEVICES 4 // デバイス数
#define RELAYPIN_1 5 //D1
#define RELAYPIN_2 4 //D2
#define RELAYPIN_3 14 //D5
#define RELAYPIN_4 12 //D6
#define SWITCHPIN1 2 //D4
#define SWITCHPIN2 13 //D7
#define SWITCHPIN3 1 //D10 TX
#define SWITCHPIN4 3 //D9 RX
#define VPIN_1 V1 // Blynk vertual PIN
#define VPIN_2 V2
#define VPIN_3 V3
#define VPIN_4 V8
int wifiFlag = 0;
const char* ssid = "text";
const char* passphrase = "text";
BlynkTimer timer;
#define IRQ_TIME 3000L
#define TOGGLE_ON 0 //←機械式リレーのときはONが0、秋月電子に代表されるSSRではONが1
#define TOGGLE_OFF 1
#define AUTH "*****************" // You should get Auth Token in the Blynk App.
int VPIN[] = {VPIN_1,VPIN_2,VPIN_3,VPIN_4};
bool toggleState[DEVICES]; // リレー状態
bool lastSwitchState[DEVICES]; // 直前のスイッチ状態
unsigned long lastSwitchChange[DEVICES]; // 直前のスイッチ変更時間
int relayPINs[] = {RELAYPIN_1,RELAYPIN_2,RELAYPIN_3,RELAYPIN_4};
int switchPINs[] = {SWITCHPIN1,SWITCHPIN2,SWITCHPIN3,SWITCHPIN4};
/*
* リレーを反転させる処理 relay=0オリジン
*/
void relayOnOff(int relay)
{
bool toggleStateX = !toggleState[relay];
digitalWrite(relayPINs[relay], toggleStateX); // turn on relay
toggleState[relay] = toggleStateX;
delay(100);
}
/*
* リレーピンの初期化
*/
void setupRelays()
{
for(int i = 0;i<DEVICES;i++){
pinMode(relayPINs[i], OUTPUT);
digitalWrite(relayPINs[i], TOGGLE_OFF); //
toggleState[i] = TOGGLE_OFF;
}
}
/*
* スイッチピンの初期化
*/
void setupFlipSwitches()
{
for(int i = 0;i<DEVICES;i++){
lastSwitchChange[i] = 0;
lastSwitchState[i] = HIGH;// INPUT_PULLUPの場合デフォルトはHIGH
pinMode(switchPINs[i], INPUT_PULLUP);
}
}
/* ループで毎回呼び出される
* スイッチが押されていたらリレーを反転させトグルステート変数も反転させている
*/
void with_internet()
{
for(int i=0;i<DEVICES;i++){
unsigned long actualMillis = millis(); // get actual millis
unsigned long lastSwitchChangeX = lastSwitchChange[i]; // get the timestamp when flipSwitch was pressed last time (used to debounce / limit events)
if (actualMillis - lastSwitchChangeX > DEBOUNCE_TIME){ // if time is > debounce time...
bool lastSwitchStateX = lastSwitchState[i]; // get the lastSwitchState
bool flipSwitchStateX = digitalRead(switchPINs[i]); // read the current flipSwitch state
if (flipSwitchStateX != lastSwitchStateX) { // if the Switch has changed...
#ifdef PUSH_BUTTON
if (!flipSwitchStateX) { // if the tactile button is pressed
lastSwitchState[i] = !flipSwitchStateX;//2022-03-28修正 スイッチがプッシュかシーソーで動きが違うので変えた
#else
lastSwitchState[i] = flipSwitchStateX;
#endif
lastSwitchChange[i] = actualMillis; // update lastSwitchChange time
relayOnOff(i);
Blynk.virtualWrite(VPIN[i], toggleState[i]); // Update Button Widget
#ifdef PUSH_BUTTON
}
#endif
}
}
}
}
/* Blynkがつながったら一度だけ呼ばれる処理
* ここの処理はいろいろやっていないのであれば
* setup()内に入れてしまってもよい
*/
BLYNK_CONNECTED()
{
for(int i=0;i<DEVICES;i++){
// Request the latest state from the server
Blynk.virtualWrite(VPIN[i],toggleState[i]);
}
}
// When App button is pushed - switch the state
/* V? アプリで対応するバーチャルピンのボタンが押されたとき起動がかかる
* 渡されるパラメータが1か0なのでそれをそのままリレーを叩くのに使ってしまっている
*/
BLYNK_WRITE(VPIN_1)
{
toggleState[0] = param.asInt();
digitalWrite(relayPINs[0], toggleState[0]);
}
BLYNK_WRITE(VPIN_2)
{
toggleState[1] = param.asInt();
digitalWrite(relayPINs[1], toggleState[1]);
}
BLYNK_WRITE(VPIN_3)
{
toggleState[2] = param.asInt();
digitalWrite(relayPINs[2], toggleState[2]);
}
BLYNK_WRITE(VPIN_4) {
toggleState[3] = param.asInt();
digitalWrite(relayPINs[3], toggleState[3]);
}
/*
* 3秒ごとに割り込みしてBlynkサーバーとつながっているかチェックしている
* 本当はつながってなかったらほかにもやることあると思うけど省略
*/
void checkBlynkStatus() // called every 3 seconds by SimpleTimer
{
bool isconnected = Blynk.connected();
if (isconnected == false) {
wifiFlag = 1;
}
if (isconnected == true) {
wifiFlag = 0;
}
}
/*
* Wi-FiつなげてBlynkサーバーにつなげる
* 3秒ごとのタイマー割り込み処理いれる
*/
void setup()
{
Serial.begin(BAUD_RATE);
setupRelays();
setupFlipSwitches();
////// Wi-Fi接続処理 //////
WiFi.begin(ssid, passphrase );
timer.setInterval(IRQ_TIME, checkBlynkStatus); // check if Blynk server is connected every 3 seconds
// タイマー割り込みのプロシージャを定義できる
Blynk.config(AUTH);
}
/*
* メインループ内ではWi-Fiがつながっていなければエラーメッセージをシリアルポートに出力する
* ブリンクループ
* タイマー処理
* スイッチピン監視
*/
void loop()
{
if (WiFi.status() != WL_CONNECTED){
Serial.println("WiFi Not Connected");
}else{
Blynk.run();
}
timer.run(); // Initiates SimpleTimer
with_internet();
}
上記プログラムの中で個別のチューニング要素を書いておくと、
SSIDとパスワード | 個別のWi-Fi環境に応じて |
Blynkトークン | アプリで割り当てられたもの |
DEVICES | チャンネル数 |
VPIN_1~4 | Blynkアプリで既に使ってるのがあったら変える |
BLYNK_WRITE(VPIN_?) | チャンネル数に応じて増減させる |
TOGGLE_ON/TOGGLE_OFF | リレーの性質で0か1か変える |
IRQ_TIME | 3000L(3秒)ごとに割り込み処理呼ぶ |
DEBOUNCE_TIME | 物理スイッチ押されたときのチャタング防止タイマー時間 |
自分はあまり複雑なプログラムは書けないので参考になるものからかなり簡易に変えたつもり。多少の経験があれば誰でも理解できるようなプログラムだと思うんだけどどうかな。
いろいろなグローバル変数を扱っているが性質ごとに全部配列にしてしまって処理がすっきりできた。
これならデバイス数がさらに増えても減っても改造が簡単なのでデバイス32個とかにも挑戦してもいいんじゃないかな。やらんけど。
Node-RED Alexa home skill bridgeへの登録
Node-RED Alexa Home Skill Bridge
Node-REDでの登録については別の記事で述べているので参考にしてほしい。
Node-RED Google Assistant Bridgeへの登録
Node-RED Google Assistant Bridge
Googleアシスタントから認識できるようにNode-RED Google Assistant Bridgeというのにも登録するが、サイトが違うだけでAlexaとほぼ似たような登録方法なので詳細説明は省略する。
Raspberry PiでNode-REDに登録する
上記画像はだいたい入れてみればわかるがポイントとして
- 最初はAlexaのノードが左のパレット一覧に現れないのでnode-red-contrib-alexa-home-skillというのをパレットの管理から登録しておく
- 同じくGoogleアシスタントのノードも最初は一覧にないのでnode-red-contrib-googlehomeというのを登録しておく
- あとはだいたいデフォルトで含まれているがmsg.payloadというノードはDEBUGノード
- curl云々というノードはEXECノード
- 右の方にあるグレーのやつはAlexaでの動作をGoogleアシスタントにも反映させるためのもの
- functionノードの中身は下記
▼これでtrueかfalseかと書き換えるとAlexaに司令したものがGoogleにも反映されるようなんだけどいまいちうまく行かないのはおそらく理解が不十分でなにかしら間違っているからだと思う。
if (!msg.payload) {
msg.payload = {
command: "action.devices.commands.OnOff",
params: {
on: true
}
};
delete msg._confId;
return msg;
} else {
return;
}
Alexaでのデバイス検出
上記Node-RED Bridgeに登録するとGoogleアシスタント(Google Homeアプリ)では自動でデバイスが出てきた。
Alexaのアプリではデバイスを探すっていう操作をすることによってデバイスがアプリに認識される。
あとはBlynkアプリから操作するもよし、AlexaアプリやGoogleHomeアプリから操作するもよしだ。
Alexaアプリならスケジュールを決めて時間になったらONやらOFFやらできるぞ。ちなみにGoogleHomeアプリのほうでは声によるトリガーが必要だからいきなりプラグがONになるとかって設定できないのが残念。
記事中で出てきた部品
ワンタッチコネクター
記事中のものとは違うが、こちらのほうがスリムで良い。たまたまホームセンターであったので使ったができればこのスリムな方がよかった。繰り返し使えるので作り直したいときに便利。趣味の電子工作なら作り直しできるタイプがおすすめ。
ワゴジャパン WFRシリーズ ワンタッチコネクター ブリスターパック 電線数5本 5個入 WFR-5BP 透明
¥570 (¥114 / 個)(2022/03/23 20:44時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
あとこの手のコネクターを使う場合はケーブルは単芯タイプじゃないと抜けてしまう危険があるので要注意。
一応撚線でも使えるらしいけど自分の場合、単芯と撚線をいちいちはんだ付けしてリード線を作って作業した。
4チャンネルリレー
AliexpressよりAmazonのほうが割高ではあるが最短で翌日届くのと万一不具合があったらすぐ対応してもらえるのでやはりAmazonがよい。
waves リレーモジュール 5V 4回路
¥650(2022/03/23 20:46時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
プッシュスイッチ
どんなんでもいいがAliExpressで買っておいたのが役に立った。
193円と安かったが時間はかかる。
ESP8266 NodeMCUボード
建前としてなるべく技適を取得しているものを買おう。ただAmazonでも技適未取得品が数多く売られているので気にしすぎたらぜんぜん買えなくなるという現実も知っておこう。ちなみに見た目が違うものがいろいろあるがピン数が同じならどれも同じようにプログラムを書き込めるようであまり気にする必要はなさそう。
Rasbee New バージョン NodeMcu Lua ESP8266 CP2102 WIFI インターネット 開発ボード 並行輸入品
¥394(2022/03/23 20:54時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す