WROOM02を使った赤外線リモコン その2

概要

前回の、WROOM02を使った赤外線リモコン その1 でIrLEDを使った回路や、家電用リモコンのコマンドコードの送出がうまくいった(ようである)。ただ、いちいちリモコンのコマンドデータをリクエストパラメータに書いて送信するのでは面倒この上ないので、ボタンをそれらしく並べたhtmlファイルを作成し、それをWROOM02上で動作するwebサーバーから読み出して使えるようにした。

ブラウザに表示されるボタンを押すと、IrLEDからコマンドコードを送出するためのURIにリクエストを送るようにする。そうしておけば、PCでもスマホでも、WIFI接続が可能なデバイスから操作できる。

WROOM02のSPIFFSの利用

あまりhtmlファイルに凝ってもしょうがないので、あっさりしたものにした。ただ、以前やったようにhtmlファイル全体を文字列にしてスケッチに埋め込むのでは芸がないので、WROOM02のSPIFFSという機能を利用し、対象の家電製品ごとにhtmlファイルを作り、WROOM02内部に格納することにした。表示したいhtmlファイル名をブラウザから指定することで、対象としたい家電用のリモコンもどきが表示されるわけである。

WROOM02には合計4MBytesのフラッシュメモリが積まれているが、今まで作ったような構成では、スケッチ用の領域が1MBytes弱で、残りはほとんど使われていない。この空いている領域を使ったファイルシステムのことを、SPIFFS (SPI Flash File System) と呼んでいる。
Arduino IDEでマイコンボードとして Generic ESP8266 Module を選択している場合、Flash Size を指定しておく必要があるので 4M(1M SPIFFS) としているが、これはSPIFFS用に1MBytes確保します、という意味だろう。

SPIFFS領域へのファイルの転送は、Arduino IDEに組み込む、ESP8266 Sketch Data Uploader というプラグインを用いて行う(詳しくはリンク先を参照)。
このプラグインの機能は、スケッチディレクトリ( スケッチ.ino ファイルがあるディレクトリ)に “data” という名前のサブディレクトリがあれば、その中身をそっくりフラッシュメモリ内のイメージに変換し、シリアルポートを経由してWROOM02に送り込みますよ、というもの。プラグインが作成するフラッシュメモリイメージは、dataディレクトリにおいたファイルサイズではなく、SPIFFS領域の大きさ(うちの場合は1M SPIFFSなので約1MBytes)になるようだ。

mkspiffs

SPIFFSに転送する際には、WROOM02側をプログラム転送待ちにした状態で、ツールメニューから ESP8266 Sketch Data Upload を選択するだけでよい。なお、シリアルモニタが開いていると失敗するので注意。

スケッチからSPIFFS内のファイルにアクセスする際には“FS.h“をインクルードする。使い方については、 …\esp8266\2.3.0\libraries\ESP8266WebServer\examples\FSBrowser を参考にした。
なお、転送前のdata ディレクトリが、SPIFFSでのルートディレクトリ (“/”) となる。data内にサブディレクトリがある場合、ディレクトリ構造を維持したままイメージファイルを作成してくれる。Windowsでスケッチを書いている場合も、SPIFFS内でのディレクトリセパレータは”/”となる。まあ、”\” ってことはないでしょう。

今回はリモコン機能のテストの続きということで、テレビ用とエアコン用の2つのhtmlファイルと、共通のjavaScriptファイルを作成し、すべてdataディレクトリ直下(SPIFFSでの”/”直下)に配置することにした。

スケッチについて

WROOM02に送り込むスケッチは、SPIFFSからの指定のファイルを読みだす部分を追加した程度で、前回のものとあまり変わらない。おもな相違点は以下のとおり。

#include <FS.h> を追加。SPIFFSを使うから。
void setup(void)内
  • 最初の方に、 SPIFFSの使用を開始するための、 SPIFFS.begin(); を追加。
  • server.on(…) で指定していないURIがリクエストされたとき、SPIFFS内からファイルを探すので、
server.onNotFound([](){
if(!handleFileRead(server.uri()))
server.send(404, "text/plain", "FileNotFound");
});

を追加。handleFileRead() の中身については、サンプルの FSBrowser.ino を参照のこと。

リモコン風htmlファイル

テレビ用

以下に、今回とりあえず書いたテレビ用リモコンを表示するためのhtmlファイル(regza.html) を示す。

<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="funcs.js"></script>
<script>
window.onload=function(){ return setup('N'); }

var params = {
	'電源' : '40 bf 12 ed',
	'地デジ' : '40 bf 7a 85',	
	'BS' : '40 bf 7c 83',	
	'CH1' : '40 bf 01 fe',	
	'CH2' : '40 bf 02 fd',	
	'CH3' : '40 bf 03 fc',	
	'CH4' : '40 bf 04 fb',	
	'CH5' : '40 bf 05 fa',	
	'CH6' : '40 bf 06 f9',	
	'CH7' : '40 bf 07 f8',	
	'CH8' : '40 bf 08 f7',	
	'CH9' : '40 bf 09 f6',	
	'CH10' : '40 bf 0a f5',	
	'CH11' : '40 bf 0b f4',	
	'CH12' : '40 bf 0c f3',
	'C_UP' : '40 bf 1b e4',
	'V_UP' : '40 bf 1a e5',
	'a1' : '',
	'C_DOWN' : '40 bf 1f e0',
	'V_DOWN' : '40 bf 1e e1',
	'a2' : '',
	'画面表示' : '40 bf 1c e3',
	'消音' : '40 bf 10 ef'
};

</script>
<style>
button { font-size:16px; width: 100px;   }
div { width:330px; border: 2px solid coral; margin-left: 10px; padding-top: 10px; text-align:center; line-height: 200%;}
</style>
</head>
<body>
<h1>ESP_IR_SERVER(TV)</h1>
<div id='main' />
</body></html>

リモコンとして機能するのかどうかのテストが第一なので、前回取得したデータを使った連想配列と、リモコン用領域の<div>タグで構成した。<div>タグ内への要素の追加はjavaScript (funcs.js)内で行っている。

var params

赤外線リモコンを調査するスケッチでは、リモコンのボタンを押すごとに、送出されるコマンドコードを16進表記の文字列でシリアルモニタに表示していた。その内容をコピペして連想配列の値部分としている。連想配列のキーには、対応するボタン表面に表示する内容を使っている。

なお、キー名が’a’で始まるデータは、画面に改行(<br>)を挿入するためのもの。

window.onload=function(){ return setup(‘N’); }

window.onload イベントが起きると、funcs.js 内のsetup(); という関数を呼ぶ。引数としてリモコンの信号フォーマットを指定している。

regza

PCのブラウザに表示するこんな感じ。よく使いそうなボタンに絞った。

エアコン用

エアコン用のリモコンをちゃんと作るならば、ボタンに単純に対応する信号を送出するのではなく、リモコン側にエアコンの状態(運転モード、温度、風力、タイマーなど)をしっかり維持し、ボタンの操作時には内部状態に基づいたコードを送るようにする必要があるが、今回は単純なものにした。

<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="funcs.js"></script>
<script>
window.onload=function(){ return setup('A'); }

var params = {
'停止' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 38 30 00 a0 00 00 06 60 00 00 c1 80 00 c1',
'冷房開始' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 a0 00 00 06 60 00 00 c1 80 00 c2',
'風量自動' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 a0 00 00 06 60 00 00 c1 80 00 c2',
'風量静' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 b0 00 00 06 60 00 00 c1 80 00 d2',
'風量1' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 30 00 00 06 60 00 00 c1 80 00 52',
'風量2' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 40 00 00 06 60 00 00 c1 80 00 62',
'風量3' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 50 00 00 06 60 00 00 c1 80 00 72',
'風量4' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 60 00 00 06 60 00 00 c1 80 00 82',
'風量5' : '11 da 27 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 $t 11 da 27 00 00 39 30 00 70 00 00 06 60 00 00 c1 80 00 92'
};
</script>
<style>
button { font-size:18px; width: 100px; }
div { width:330px; border: 2px solid coral; margin-left: 10px; padding-top: 10px; padding-bottom: 10px; text-align:center; line-height: 200%;}
</style>
</head>
<body>
<h1>ESP_IR_SERVER(AIR-CON)</h1>
<div id='main' />
</div></body></html>

構造はテレビ用と同じ。信号フォーマットがAEHAなので、setup()を呼ぶ際に’A’を指定している。

daikin

こちらは、冷房開始を押すと運転を開始する(24℃、風量自動)。風量を6種類用意した。温度に比べて、風量が変化したことはすぐに分かるから。風量ボタンを押すと必ず24℃の冷房運転になる。

共通のjavsScriptファイル(funcs.js)

/** support functions */
function http_request(uri) {
	var request = new XMLHttpRequest();
	request.open('GET', uri, false)
	request.send();
	if (request.status != 200)
		alert('error');
}

function setup(tx_format) {
	var div = document.getElementById('main');
	var i = 0;
	for(key in params) {
		if (key[0] != 'a') {
			var button = document.createElement('button');
			button.innerHTML = key;
			let code = '$' + tx_format + ' ' + params[key];
			button.onclick = function(){
				code = '/ircmd?cmd=' + code.replace(/\s/g, '%20');
				http_request(s);
				// alert(code);
				return false;
			}
			div.appendChild(button);
			div.appendChild(document.createTextNode('\u0020'));
		}
		if (++i % 3 == 0)
			div.appendChild(document.createElement('br'));
	}
	if (i % 3 != 0)
		div.appendChild(document.createElement('br'));
	return true;
}
function http_request(uri)

引数で指定されるuriに同期的にリクエストを実行する。

function setup(tx_format)

各htmlのwindow.onload() で実行される。id=’main’ で示される<div>内にどんどん<button>タグを追加していく。追加するときに、htmlがもつ連想配列paramsのキーをボタンのinnerHTMLとし、値からリクエストパラメータを作ってonclick時のリクエスト先としている。

いずれのhtmlファイルも、WEBサーバーとして動作しているWROOM02に対して、ブラウザから /regza.html や /daikin.html といった名前を指定することで開く。

きょうのまとめ

WROOM02と赤外線受信モジュールで得た赤外線リモコンの送信コード利用し、WROOM02とIrLEDを組み合わせ、なおかつWiFiアクセスポイントやWEBサーバー機能も利用しつつ家電用リモコンが実現できそうなことは分かった。
エアコン用をちゃんとやるならば、エアコンが出してくるコードをちゃんと解析し、運転種別ビット、温度用ビット、風量用ビット、運転用ビット、チェックサム生成方法などを洗い出していけばよいだろう。常にリモコン用のブラウザを開いておくわけにもいかないので、仮想的な?エアコンの状態をWROOM02内部に維持しながら、javaScriptでそれを問い合わせ、状態に応じた対象製品ごとのコマンドデータを組み立てるのがよさそうである。

今回はWEBサーバーとして構成したが、自動運転を考えるならば、インターネット上のWEBサーバーに温度や湿度を報告した応答として、エアコン用のコマンドを持って帰ってくる、というのもあるだろう。当初はそういうつもりで始めたのだけど、涼しくなってきたのでやる気にならない。寒くなって雪が降るようになる前に、帰宅のころあいを見計らって自動的に暖房が開始しているような仕組みは作ってみてもいいかもしれない。

ちょうど赤外線リモコン関係で遊んでいるときに、自宅のシャワートイレのリモコンが壊れてしまった。リモコンがダメになると、本来の機能をまったく果たしてくれないのは困りものである。
分解してテスターで調べてみると、タクトスイッチが一つ壊れており、常に導通状態になって押下されたキーが識別不能、かつ、電流も流れ続けていたようだった。手持ちのスイッチと交換したことで治ったのだけど、赤外線で送出されるコマンドコードも調べておいたので、いつでも代わりが作れるようにはなった。
ただ、場所柄からしてブラウザで操作するわけにもいかないから、8つくらいのボタンをもつ専用機でも作っておこなうかな、とか思っているところ。