1個のIPアドレスで4個のコンセントを制御できる4チャンネルスマートプラグ自作の記録

4ch自作スマートプラグ 4ch手作りスマートプラグというのを作った。

Youtubeで見かけて自分でもいずれ作りたいなあと思っていたがとうとうできた。動作も完璧だし、物理ボタンでも操作できる。

外部サービスも使っているがサブスクはかからないので心置きなく使い倒せる。

では作り方とプログラムコードを公開する。

スポンサーリンク

4chスマートプラグに必要な機器

1chタイプとの差分

4ch自作スマートプラグ

先日1チャンネルのスマートプラグを作って記事にしたのでそれも参考にしてほしい。そしてそのハードウェアの差分のみをここに述べておく。

  • コンセントメス+3個
    4チャンネルなのでコンセントのアウトレットが4口になり当然ながら全部で4口必要になる
    4ch自作スマートプラグ
  • ワンタッチコネクター5口
    これは元線から来たAC電源を4個に分岐させるのを簡単に実現させるための材料で必ずしもこれを使わなくてもできる
    4ch自作スマートプラグ
  • 4chリレー
    これがないと始まらない。これを手に入れるのに結構日数がかかった。AliExpressで注文したのがなかなか入らなかったしいざ入荷して使ってみたら不良品だったので結局Amazonで買った。Amazonならやや高いが注文して翌日入手できる
    4ch自作スマートプラグ
  • 一応機能を完璧にするためにプッシュスイッチもつけた。スマホやスマートスピーカーでオンオフ制御するだけではなく物理スイッチでも制御できたほうが便利なのは間違いない。もちろん物理スイッチを切り替えてもスマホのほうには反映されるようにプログラミングする。4個
    4ch自作スマートプラグ
  • ケースは大きめ
    前回の1チャンネルタイプよりかなり材料を使うのでケースはかなり大きめになってはっきりいって格好は良くない。仕方ない。市販のプラグではなく自分専用なので我慢だ。
  • Raspberry Piをサーバーとして待機させる
    これが一番差分としてはヘヴィだと思うんだけどこれがハードル高すぎてだいたいの人が断念してしまうのではなかろうか。かくいう自分もおそらく1年前ぐらいは軽く断念していた案件だが1年近く勉強すると結構わかるようになる。
    SwitchBotスイッチみたいにスケジュールでスイッチ入れるラズベリーパイ
  • ブレッドボードの電源供給部
    直結してしまうとかほかで代用する手段はあるが可逆的に作っておくならこういうので接続しておくほうがいいともいえる。
    4ch自作スマートプラグ

4チャンネル自作スマートプラグ構想

4ch自作スマートプラグ

1chの自作スマートプラグとの違い

1チャンネルのときはSinric Proというスマートデバイス管理サービスを使ったが、あれは無料では3個までデバイス登録ができ、4個目からは年間3ドルだったかのサブスクが必要になる。

年間3ドルならそんなに高くはないが一生払い続けるかと思うとためらってしまう。

なのでSinric Proとは決別することにし、Blynkを使うことにした。

Blynkも完全無料のスマートデバイス管理サービスではないがデバイス1個というかウィジェット買い切り、しかも作り直してウィジェットを削除すると別のことに使えるので大変助かる。

アレクサからもGoogleアシスタントからも操作可能

Blynkにデバイスを登録するがAlexaやGoogleAssistantからも使えなければ面白くない。

幸いBlynkに登録したデバイスはそんなに複雑なことをしなくともAlexaやGoogleからも呼び出しできる。

4チャンネル自作スマートプラグ作成手順

ハードを組み立てる

▼まずはハードの仕上がりを見てもらおう。

 

Blynkアプリでピン番号決める

Blynkアプリを開きボタンウィジェットを4個配置する。

それぞれのバーチャルピン番号を決め、オフで1,オンで0という信号を送るよう設定する。

4ch自作スマートプラグ4ch自作スマートプラグ

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~4Blynkアプリで既に使ってるのがあったら変える
BLYNK_WRITE(VPIN_?)チャンネル数に応じて増減させる
TOGGLE_ON/TOGGLE_OFFリレーの性質で0か1か変える
IRQ_TIME3000L(3秒)ごとに割り込み処理呼ぶ
DEBOUNCE_TIME物理スイッチ押されたときのチャタング防止タイマー時間

自分はあまり複雑なプログラムは書けないので参考になるものからかなり簡易に変えたつもり。多少の経験があれば誰でも理解できるようなプログラムだと思うんだけどどうかな。

いろいろなグローバル変数を扱っているが性質ごとに全部配列にしてしまって処理がすっきりできた。

これならデバイス数がさらに増えても減っても改造が簡単なのでデバイス32個とかにも挑戦してもいいんじゃないかな。やらんけど。

Node-RED Alexa home skill bridgeへの登録

Node-RED Alexa Home Skill Bridge
Node-REDでの登録については別の記事で述べているので参考にしてほしい。

【Node-RED】自宅のパソコンをAlexaから起動するしもちろん出先からも起動できる
IoTばかり最近(2021年後半〜2022年初)ハマりすぎていてそればかり考えている。まさに若い頃とある神社で言われた「あなたは最初に就いた仕事が合ってるわよ」という言葉どおりで自分でも還暦近くなって天職を見つけた(職にはなってない...

Node-RED Google Assistant Bridgeへの登録

Node-RED Google Assistant Bridge
Googleアシスタントから認識できるようにNode-RED Google Assistant Bridgeというのにも登録するが、サイトが違うだけでAlexaとほぼ似たような登録方法なので詳細説明は省略する。

Raspberry PiでNode-REDに登録する

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になるとかって設定できないのが残念。

記事中で出てきた部品

ワンタッチコネクター

記事中のものとは違うが、こちらのほうがスリムで良い。たまたまホームセンターであったので使ったができればこのスリムな方がよかった。繰り返し使えるので作り直したいときに便利。趣味の電子工作なら作り直しできるタイプがおすすめ。

B01E577T1Q
ワゴジャパン WFRシリーズ ワンタッチコネクター ブリスターパック 電線数5本 5個入 WFR-5BP 透明

¥570 (¥114 / 個)(2022/03/23 20:44時点の価格)
平均評価点:5つ星のうち4.4
>>楽天市場で探す
>>Yahoo!ショッピングで探す

あとこの手のコネクターを使う場合はケーブルは単芯タイプじゃないと抜けてしまう危険があるので要注意。

一応撚線でも使えるらしいけど自分の場合、単芯と撚線をいちいちはんだ付けしてリード線を作って作業した。

4チャンネルリレー

AliexpressよりAmazonのほうが割高ではあるが最短で翌日届くのと万一不具合があったらすぐ対応してもらえるのでやはりAmazonがよい。

B07CKTJ8RF
waves リレーモジュール 5V 4回路

¥650(2022/03/23 20:46時点の価格)
平均評価点:5つ星のうち4.0
>>楽天市場で探す
>>Yahoo!ショッピングで探す

プッシュスイッチ

どんなんでもいいがAliExpressで買っておいたのが役に立った。

Aliexpressのプッシュスイッチ

193円と安かったが時間はかかる。

ESP8266 NodeMCUボード

建前としてなるべく技適を取得しているものを買おう。ただAmazonでも技適未取得品が数多く売られているので気にしすぎたらぜんぜん買えなくなるという現実も知っておこう。ちなみに見た目が違うものがいろいろあるがピン数が同じならどれも同じようにプログラムを書き込めるようであまり気にする必要はなさそう。

B01LW038VO
Rasbee New バージョン NodeMcu Lua ESP8266 CP2102 WIFI インターネット 開発ボード 並行輸入品

¥394(2022/03/23 20:54時点の価格)
平均評価点:5つ星のうち4.0
>>楽天市場で探す
>>Yahoo!ショッピングで探す

 

タイトルとURLをコピーしました