4-3.スマホで家電操作(屋内)

2019年6月25日

スマホで操作する家電リモコン概要

スマホで家電を操作ができる電子工作を行います。ただし、屋外からの家電操作はできません。(屋外からのアクセス方法は5-2で説明しています。)。
今まで学習してきた赤外線リモコンの送受信やWebサーバ機能などを活かし実現していきます。

電気回路と電子工作

今回利用するのは、LED制御とリモコン送受信を実施するために今までに学習した2-1,2-5,2-6の回路を、一つにまとめた回路となります。まとめた回路図とブレッドボード配線図を以下に示します。


【ESP32-DevKitCの入出力端子はこちらを参照下さい】

関連フォルダ及びスケッチ、HTML関連ファイル

利用するファイル構成を以下に示します。

スケッチは「4_3_remocon.ino」と「irRecvSend.ino」です。また、dataフォルダ内はSPIFFSデータとして本体に書き込み、WebサーバでHTMLファイル等を送信することでWebブラウザの画面表示に利用しています。

そのため、関連ファイルは以下の大きく2種類となります。
1)スケッチ(Arduino制御プログラム)
 ファイル名:4_3_remocon.ino, irRecvSend.ino
2)HTML関連(HTMLとJavascriptファイル)
 ファイル名:top.html, set.html, rem.js

スケッチでLED制御やリモコンの送受信、また、データ保存や読出などの制御を行います。スマホへの画面表示や制御に関してHTML関連ファイルで実現しています。
各ディレクトリとファイルについて説明します。

(1)4_3_remocon(ディレクトリ)

スケッチのディレクトリです。本電子工作で利用するスケッチが格納されています。

(2)data(ディレクトリ)

SPIFFSアップローダーで利用するディレクトリです。
HTML関連ファイルが格納されており、ディレクトリ内のファイルが全て本体に書き込まれ、SPIFFSで読み込みできます。

(3)4_3_remocon.ino

スケッチの全体・共通部分のプログラムで内容は以下となります。

3-2,4-2で学習したWebサーバとSPIFFS利用の内容と基本は同じですので、変更したところを中心に説明します。
⑯〜⑱でアクセスされるURLを設定しています。以下の3つは関数を呼びたしdataフォルダにあるファイルを送信する処理を実施しています。
webServer.on ( “/”, HTTP_GET, … // 制御画面を送信
webServer.on ( “/rem.js”, HTTP_GET, … // 制画面のJavascriptを送信
webServer.on ( “/set”, HTTP_GET, … // 設定画面を送信
⑲はEEPROM内にあるボタン名をJSON形式で送信しています。
webServer.on ( “/getrem”, HTTP_GET, … // 画面のボタン情報送信
⑳、㉑の2つはリモコン送受信処理をするための関数を呼び出しています。
webServer.on ( “/setrem”, HTTP_GET, … // リモコン受信
webServer.on ( “/cntrem”, HTTP_GET, … // リモコン送信
次にgetRemocon関数はEEPROM内のボタン名情報をJSON形式で送信する処理を実施しています。JSON形式は多くのプログラム言語で容易に扱うことができる機能が提供されてため多くのシステムで利用されています。{}内に名前に対する値をコロンで区切り表記し、データの間をカンマで区切り、以下のように表記することができます。配列などの表記も可能ですが今回は以下のシンプルな表記のみ利用しています。
{“name1”:”value1”,”name2”:”value2”}
㉕で送信データを保存する変数senddataを宣言し最初の”{”を代入しています。㉗0から9までのボタン名を順次処理し、㉘でEEPROMの保存しているメモリ位置が0から9で異なるため計算し㉚でEEPROMからメモリ位置のデータを取得しています。
㉛でデータの最初の2文字が”O:”の場合のみ情報があるとしています(データ保存時に設定)ので、チェックし存在すればsenddataに追加します。㉜は2つ目以降のデータは”,”を追加しデータ間には”,”で区切ります。㉞のgetirname.substring(2,getirname.length())はString型のメソッドsubstringを使い、0から始まるので0と1文字”O:”を含めず、2文字目から最後までの文字列を切り取っています。
㉟でデータの最後に”}”を追加し、㊱で作成したJSONデータを返送します。

(4)irRecvSend.ino

リモコン送受信を処理する関数についてファイルを分けて作成します。同じファイルで作成しても特に何も変わりませんが、プログラムを見やすく、また開発しやすくするためにファイルを分けて作成します。
ArduinoIDEでタブを分けることでファイルを分けることができます。下図のように一番右上の「▼」マークをクリックし「新規タブ」を作成しファイル名を入力することでファイルが分かれて作成されます。

作成したファイル(タブ)にリモコン送受信に関するプログラムを記載します。

setRemocon関数は2-5のリモコン受信処理で学習した内容と基本は同じですが、完了時にボタン名とリモコン信号を受信する処理⑨などを追加しています。
saveIr関数でボタン名をEEPROMへ書き込み、リモコンデータをファイルへ保存しています。EEPROMの書き込みは㉒から㉘で処理しボタン名を保存しています。また、SPIFSを利用してリモコン信号のファイルへの書き込みは㉙から㉝で処理します。
㉒はHTTPのGETで送信された値を取得しています。送信される値はアクセスURLに「?name1=value1&name2=value2」のようにデータが付加されて要求されます。”?”のあとはデータとなりデータ間は”&”で繋がれます。データ(value)は「webServer.arg(“name1″)」のように取得することができます。
㉕でボタン名が存在していることを明示するため”O:”を追加し㉘で該当ボタンのメモリ位置で保存します。ボタン名のByte数は65なのでメモリ位置も65Byte毎にボタン名を0から保存しています。例えば、ボタン番号が2の場合は65*2=130Byteの位置に保存することになります。
リモコン信号のファイル保存は㉙でボタン番号をファイル名で作成し㉛で最初の行に信号長さ(0,1の信号数)を保存し㉜で2行目から0,1の信号長さを書き込みます。また、「fw.println( String( irLength, HEX ) );」のHEXは扱うデータを小さくするため16進数で保存しています。
リモコン送信処理のcontRemocon関数は2-6で学習した内容と同じですが、ファイルから読み込み送信する処理として㊲から㊷までを追加して変更しています。㊵は0,1の信号数の最初の1行のみ読み込んでいます。㊶は数値型にしていますが16進数で保存していたので10進数に戻すため「strtol(snum.c_str(), NULL, 16);」で16(進数)を指定しています。
㊷から2行目以降を同様にファイルから読み出しirDataに保存し、㊸から読み出したirDataデータの通りリモコン信号を送信しています。

(5)top.html

top.htmlはWebアクセス時に表示される制御画面です。HTMLファイルの内容は以下の通りです。

画面表示を綺麗にするため②Styleタグでカスケーディング・スタイルシート:CSS(Cascading Style Sheet)を設定しています。CSSにより画面の見栄えを細かく指定しています。
CSSはセレクタで該当の文字列を指定し{}でプロパティと値を指定します。セレクタは先頭文字でHTMLの指定する属性が変更され以下のようになっています。
・ “半角英数字” : HTMLタグ
・ ”#” : HTMLタグのid属性
・ ”.” : HTMLタグのclass属性
例えば「#contents { width: 100%; max-width: 320px; }」HTMLタグ属性のidが”contents”の場合にこの規定に従い、Width(画面幅)は100%で表示し、max-width(最大画面幅)を320pxと指定しています。
セレクタ「.autumn」はHTMLタグのclass属性が”automn”の場合に適用され、バックグランドのグラデーション表記をプロパティと値で指定しています。
③でJavascriptのソール(元)ファイルを指定しており、”/rem.js” にアクセスしてJavascriptファイルをダウンロードします。
⑧のbuttonタグはクリックした場合にonclick属性でJavascriptのsend関数を呼び出しますが、Javascriptはダウンロードして読み込むため、「top.html」にJavascriptは記載されていません。
⑨のdivタグのIDが”dipsstatus”はJavascriptで状態が動的に書き込まれます。
top.htmlをWebブラウザで画面表示すると以下のように表示されます。

(6)set.html

設定画面を表示するHTMLファイルで内容は以下の通りです。

top.html(制御画面)と同じ内容が多くありますので、異なる内容を中心に説明します。
⑧の部分で、inputタグでボタン名を入力し設定することができるようになっています。buttonタグはクリックした場合にonclick属性でJavascriptのrcv関数を呼び出し、inputタグ内の入力値も取得し設定しています。
set.htmlをWebブラウザで画面表示すると下図のように表示されます。

(7)rem.js

制御・設定画面では操作性を向上させるためJavascriptで通信したりHTML画面を動的に変更したりします。HTMLでは実現できないページを遷移せずにHTMLを書き換えルことができるので操作性の高いUIを実現できます。
具体的にJavascriptの内容についてプログラムを用いて説明していきます。

最初の「window.onload = function () {}」は画面が読み込まれた後に{}内が実行される関数となります。もう少し詳細に説明するとDOMツリー構造及び関連リソースが読み込まれた後となります。DOMとはDocument Object Modelの略でJavasriptがHTMLを扱うために各タグやid、nameなどを識別することと理解してもらえればと思います。
①のwindow.onloadは画面が読み込まれた時に実施する処理になります。②でリモコンボタン情報の更新「updateIr()」を呼び出しています。③updateIr()関数で本体よりボタン情報を取得し画面に表示する処理を行っています。最初に XMLHttpRequestを利用できるように「new XMLHttpRequest()」を宣言し変数xhrに格納しています。XMLHttpRequestはJavascriptでHTTPアクセスを実現できるための機能となります。利用方法はプログラムの通り、④でアクセスするURLを作成しOpenで設定、SendすることでWebアクセスします。アクセスURLは④でアクセスしているURLをベースにパスのみ変更(”/getrem”を追加)して作成しています。
「xhr.ontimeout」でアクセス時に応答がない場合のタイムアウトについて処理を記載しています。「addEventListener」で応答があった場合の処理について記載し「var gtRecv = JSON.parse(resGtStr);」で受信データをJSONデータとして扱えるように変換し変数gtRecvに格納しています。
⑥についてはボタンデータが存在する場合はif文内を処理しデータがない場合はelse文内を処理します。ボタンデータが存在した場合において”spn”のidをチェックし存在する場合は制御画面のため⑦でボタン名を表示し、存在しない場合は設定画面のため⑧でボタン名を表示しています。また、ボタンデータが存在しない場合は⑨でbuttonタグを無効化します。
次にリモコン送受信処理ですが、⑩でグローバル変数を定義しています。これは文字を点滅させるためsetTimeout関数でをsetMsgTenmetuを呼び出して実現していますがグローバル変数で値を保持することで、現在のカウント数(繰り返し回数)や状態を管理しています。
⑪リモコン送信処理は制御画面でbuttonをクリック(buttonタグのonclickで呼び出される)した場合に実行されます。同様にXMLHttpRequestを利用し本体のリモコン送信用URLにアクセスすることでリモコン送信を実現します。⑮で送信用URLを作成しますがどのボタンを送信するかのボタン番号を「”/cntrem?n=” + setNum」で設定しています。送信完了の可否は⑯の本体からの応答が文字列”OK”を確認し正常完了としています。
⑱の受信処理ですが同様にXMLHttpRequestで本体のリモコン受信用URLにアクセスしますが、タイマーを15秒に設定しています。また、㉒でsetMsgTenmetu関数を呼び出して、「リモコン受信中」の赤文字表示を点滅させています。setMsgTenmetu関数では㉙で受信完了していない。かつ、タイムアウト前の場合に、flgRedの変数の値に応じて1秒毎にIf文内とelse文内を交互に表示し㉝でsetTimeoutを1秒後に再度読み出すことで点滅を実現しています。タイムアウトしている場合は㉞dispfail関数を呼び出します。
㉞dispfail関数ではタイムアウトしている状態に変数を設定し、画面に赤字で失敗表示を行い処理を終了しています。

本体への書き込みと実行

本体の配線が完了し、スケッチなどプログラムファイルの作成が完了したら本体への書き込みを実施してください。
書き込むデータは以下の通り2種類あります。書き込み方法については既に説明していますので不明な場合は以下のリンクから参照ください。

(1)SPIFFSデータの書き込み(4-2参照
(2)スケッチの書き込み(1-3参照

上記2つを書き込みが完了し、本体LEDが点灯(無線接続完了)したら、Webブラウザで「http://192.168.1.123」(設定を変更している場合は変更内容に修正して下さい)をアクセスし制御画面が表示されることを確認して下さい。

屋外からの利用

本工作のWebアクセスを屋外から利用できるようにするには、宅内ルータにポート開放設定を行えば技術的には可能です。
ただし、セキュリティ対策を行わずにポート開放を行うと外部から誰でもアクセス可能になってしまいますので本サイトでは紹介していません。
ポート開放を行う場合は適切なセキュリティ対策(ID,パスワード認証やポート番号変更など)を実施する必要があります。
近年のIoT端末はクラウドに常時接続し端末を管理し屋外からもアクセスすることが主流となっています。そのため、屋外からアクセスする方法は5-3にて紹介していますので、そちらを参照して下さい。