Wi-Fi(wifi)モジュールESP8266の内、NodeMCU開発ボードを使ってWiFi越しに動く電動ロールスクリーン(スマートスクリーン?スマートロールカーテン?)を作ってみるページ。
以前、作ったArduino+ステッピングモータ28BYJ-48製電動ロールカーテンを無線化したもの。
無線版としては、MQTT版ロールスクリーンと併行して、今回は、操作にあたり、HTML5実装のWebSocketを介すことにしました。
MQTT同様、非同期通信できますが、MQTTと違ってWebSocketには、ブローカーといったものは、存在しません。
端末(≒ターミナル)からではなく、ブラウザから手軽にできるのでPCでもスマホやタブレットでも操作可能、スクリプトでも対応できるため、デスクトップ版操作パネルからブラウザ操作パネルを表示したり、スマートスピーカーからの音声操作もできます。
WebSocketの接続(ws://、SSL対応はwss://で始まるドメインやアドレスへのアクセス)には、JavaScriptやPython3.xを使いました。
仮設のまま常用していましたが、重い腰を上げて、ガジェット筐体として、すっかり、お気に入りの100均セリアでトレカケース、キャンドゥで名刺ケースとして売っているケースに入れることにしました。
というか、当該ケースに入れてはいた、というより、はみ出した状態のまま放置していたものを配線用に切り欠きを入れてミニブレッドボード版のまま、これを機にESP8266から入れ替えたESP32ボードと降圧モジュールを放り込んだだけですが、引火しても危ないですし、ホコリまみれにならずに済み、めでたしめでたしということで。
ESP32ボードのピンヘッダも場所によっては、降圧モジュールと接触すると危ないかもしれないので、これでも一応、注意して入れてます。
写真手前にあるのは、ステッピングモータドライバULN2003、モータ位置とジャンパワイヤの長さの関係もあり、外に出しておくことにしました。
おかげでデスクから見上げれば、モータドライバのLEDの点灯で動いているのが一目瞭然です。
一応、Fritzing。
完成後は不要かもしれませんが、モノがモノ、場所が場所だけにAruduinoOTAを使ってOTA(Over The Air/無線)アップデートできるようにしました。
そうそう要らないでしょ...と思っていたのですが、今回のケースでは、超絶便利でした。
これに伴い、3通りほどあるらしき、実装方法の内、Arduino IDEを使う前提のmDNS機能を必要とするものを選びました。
ほとんどは、Arduino版やMQTT版に書いた通りですが、材料については、個々の環境に合わせて適宜用意していただければ。
mDNS機能を持つパッケージアプリケーションとしてLinuxならAvahi、Mac/WindowsならBonjourがインストール済みであること(macOSはBonjourはプリインストール済みのはず)。
Arduino IDEが利用できることは、もちろん、ESP8266やESP32をArduino IDEで使えるようにしておくこと。
ESP-01やESP-02〜ESP14などのESP8266チップなら、Arduino IDEの[ツール] => [ボード]から[Generic ESP8266 Module]を選択、ESPモジュールにスケッチをアップロードできる状態であること。
ESP32なら、[espressif/arduino-esp32]の要領でESPモジュールにスケッチをアップロードできる状態であること。
ちなみにこれらArduino IDEの環境設定で追加する方法の場合、カンマ区切りで複数指定可能。
回路については、ほぼ、Arduino版のArduinoが、ESPボードに変わっただけです。
実のところ、今回は、逆流防止のダイオードは入れなかったのですが、少なくともスクリーンの上限下限の位置決めが終わるまでは、シャフトを手動で回すことがあったりし、発電機のような状態になるので各モーターピン用にいるかもなと思った次第です。
また、操作は、物理スイッチではなく、後述の通り、同じネットワーク上にいるPCやタブレット、スマホなどのブラウザを介し、遠隔操作するだけです。
電源は、十分な電流を供給できるACアダプタなどを降圧して使えば、5V程度(今回は、ブレッドボード用電源やDC/DC降圧コンバータ+DCジャック端子台アダプタ)でもESPボードのVIN/GNDとモーター用5V/GNDを共用しても、もちろん、モーター用と分けても十分機能します。
尚、共有する場合の電源が、モバイルバッテリーだと(機能時、電流を要するため、自動OFFはしないものの、)特に巻き上げ時、トルク不足と勘違いするような状況で稀にしかうまくいきません。
また、モーターを別電源とし、ESPボードへの電源供給専用としてならモバイルバッテリーでも十分ですが、別電源によってスクリーン動作中であってもESPボードには供給(充電)不要と判断され、自動OFFしてしまいます。
よって強力な電源で共用するか、ESPボードは、電源タップに挿したAC充電アダプタから供給するかの何れかになるでしょう。
いろいろやってみた中で、これをしなくてもできたのですが...。
一からやってみたら、これをしないとできなかったので基本に忠実にWiFi SSIDとパスフレーズのみ環境に合わせたBasicOTAをNodeMCUボードにアップロード。
AruduinoOTAを使うスケッチを無線アップデートできているESPボードであれば、この必要はありません。
初めてArduinoOTAを使うボードの場合、BasicOTAの、既に他スケッチで機能していた場合、OTA用の内容を網羅したオリジナルスケッチをNodeMCUボードにアップロード。
こうすることでOTAアップデートできるようになります。
今回のWebsocketサーバとなるESPボード側のスケッチは、こんな感じ。
WebSocket communicationプロジェクトのスケッチとMQTT版(Arduino版ロールスクリーンで使ったスケッチ、Stepper、ArduinoOTA、ESP8266mDNS各ライブラリ)の合作です。
便利なもので後述のように(今回は、JavaScriptから)WebSocketのパスが呼ばれるとESP8266/ESP32にアップロードしたスケッチのwebSocketEvent関数がコールされ、payload引数にその値が入ってきます。
WebScokets.hは、複数のライブラリで利用可能なようですが、今回は、arduinoWebSocketsライブラリを使用しました。
このスケッチ、ブラウザ上でのスケッチやSPIFFS内ファイルのアップデート機能までありますが、これらについては未検証で、ここでは、Arduino IDEからOTAアップデートしました。
マルチアクセスポイント対応でアクセスポイントモードでしたが、ステーションモードに変更しました。
なぜか、元のスケッチだと4つの内、一部は、モータードライバのLEDが点灯するものの、全点灯せず、モーターが回わらなかったため、既に動作確認がとれているスケッチからコードを取り込みました。
モーターを回すためのループが完了した後もモータードライバ上のランプが点灯したままとなるため、これを消灯させるべく、停止を入れています。
ESP32を使う場合、ESP8266と異なり、SPIFFS実装には、SPIFFS.hを明示的にinclude、ESP8266WiFi.h、ESP8266WebServer.h、ESP8266mDNS.hに代えて、それぞれ、WiFi.h、ESP32WebServer.h、ESPmDNS.hをinclude、これに伴い、ESP8266WebServer server ( 80 );は、ESP32WebServer server(80);に変更、モーター用出力ピンには、ESP32相応のピンを指定、また、loop()内のスリープ関数もESP32用にする必要があります。
それ以外でコンパイルが通らない場合、きっと、コメントアウトでしのげるでしょう...。
ちなみにそのままだと.gzファイルにも対応しているため、それを残したまま解凍・展開して編集しても反映されない!と慌てないよう要注意。
なぜか、外部CSSは適用されるのに外部JavaScript(WebSocket.js)は適用されなかったのでJavaScript部分は、HTMLに埋め込みました。
(ん?CSSのHTML内のクオートがシングル、かたやダブルだけど、まさかそれ?)
押下ボタンを判別、送信するメソッド・関数sendCtrl(btn){}以外は、参照させて頂いたプロジェクト同様です。
テキスト(input type=text)は、外部スクリプトでうまくいかなかった際のボタン押下時のvalue値確認用です。
また、なぜか、CSSにおいてSPIFFSでも日本語表示を確認できているfont-familyに変更してもコメントアウトしても日本語が文字化けしたのでtitleやヘッダ、ボタン名は、とりあえず、英文字としました(が、<head></head>内に<meta charset="utf-8">を入れておけば日本語も文字化けしないと当サイト別ページに...)。
index.htmlのhead内は、必要な行のみ使い、外部CSSにも手は加えましたが、ちょっと雑さが目立ちますし、なくても機能確認には十分なので割愛します。
ブラウザにmDNS名でmDNS.local/index.htmlか、IPアドレスで***.***.***.***/index.htmlにアクセスすれば、UP、STOP、DOWNボタン付きの操作パネルが表示されます。
これなら、別途、ESP8266/ESP32で作って運用中の集中操作パネルとしているブラウザ版スマートホーム操作パネルに簡単に統合できます。
流用させて頂いたスケッチについては、アクセス時index.htmlを省略する方法がいまいちわかりませんでした...。
押下ボタンがわかると言えばわかるのでテキストボックスである必要はないものの、あってもよいですが、前述の通り、確認用なのでテキストボックスはなくても構いません。
例えば、Python(Python3)だと、まず、WebSocketクライアント(今回は、pipでwebsocket-client-py3)をインストール、スクリプトをこんな風に書けば、引数を渡して操作できます。
このようにスクリプトから操作できるということは、自作スマートスピーカーからでも操作できます。
というわけでブラウザからの操作に加え、自作ラズパイスマートスピーカーでロールスクリーンを音声操作できるようにしてみました。
また、先のロールスクリーン用含め、ブラウザ版操作パネルをデスクトップ版操作パネルから呼ぶこともできます。
非同期通信なのでスクリーン動作中であってもHTTP TCP/IP同期通信のようにフリーズすることなく、ボタン操作自体は受け付けますが、今のところ、割り込み方法を思いつかず、途中での逆転や停止はしません(よってSTOPボタンは実質意味がありません)。
ただ、端末で操作したMQTTと異なり、プログラム上UP/DOWN後に停止を入れているからか、なんだかカッコいい気もする一方、意味を見いだせるのか見い出せないのか、非同期の副産物としてUP後DOWNを、DOWN後UPを続けてクリック・タップすると全開→全閉、全閉→全開を自動で行ってくれます。
ということは、間違えて続けて押してしまうと開けたつもりなのに閉まってる!とか、その逆もあり得るという話。
が、UP/DOWNをそれぞれ続けてクリック・タップしても直後にメインメニューに戻る(ロールスクリーンのメニューを抜ける)と最初の動作だけ行って2つめ含む以降の動作はしないことがわかりました。
ロールスクリーンのメニューも各操作もロールスクリーン用に割り当てたESPチップのフラッシュメモリ上に展開されたパスにアクセスすることで表示・操作できるようになっており、フラッシュメモリ内にアクセス中は、操作における値を保持、アクセスしなくなる(=ロールスクリーン用に割り当てたESPチップのスケッチを抜ける・スケッチの範囲外になる)と即、値も破棄されるということなのでしょう。
同様に、ここで作ったロールスクリーンにとって良き値を検証し、FullOpenCloseNum = 5000としてループさせており、リミットスイッチがなくとも上限、下限に達すると自動で停止しますが、リミットスイッチがないため、UPやDOWNなど同じ操作ボタンを続けて2回以上押してしまうとスクリーン長とは無関係に巻き上げ・巻下げしてしまうので注意(運用でカバー)。