これまでのあらすじ
最後の鬼門、「8.ブラウザによる操作」です。
ブラウザによる操作
ユーザーインターフェイスはどうするか?もう答えは2つしかないわけで
- 専用アプリを開発
- Webベースで開発
専用アプリのほうが色々実装で来て楽しいんだけど、iOS、android、windowsとプラットフォーム毎に分けて作らないとだしプライベートで使うにはどうも気が進まないんですね。かといって、Webベースで作ろうにも・・・
ぼくCSS大嫌いなんすよ・・・
なぜって?CSSに限らず、全般的にレイアウトとかもあんま好きじゃないんです。センスがないからなんですけど。だって、SpriteKitとかUnityとか2Dエンジンでスプライトポンポン配置したほうが楽じゃないですか?(オイ)
CSSが嫌いなんで、必然的にJavaScriptも避けてきたわけなんです(笑)。ブラウザ毎に表示も動作もちょくちょく違いますし…。けど結局、葛藤した結果
Webベースのほうがコード量すくないかな?
という理由でWebベースにしました。
頑張ってこのセンスww
僕の頭は2000年ぐらいでHTMLのことは止まってます。とのあえず、トップのindex.htmlとbutton.css。button.cssといってもボタン以外のcssも入ってます。名前変えるのめんどくさかったです。というか、急速にやる気がそがれました。最後にGistからのリンクとコードを貼っておきます。
見てもらうとわかるかと思うんですが・・・ESP8266へのリクエストも XMLHttpRequest()を使ってみたりajaxを使ってみたり
どっちかにしろや!!
そう思います。JQueryのajaxのほうが使いやすそうですので統一したほうがいいです。両方知っとくためにもめんどくさいのでこのままにしときますw。これをESP8266のSPIFFに書き込んでサーバーとして開放します。
リモコン操作時に連続タップすると、Safariでは拡大表示されてしまうのでCSSに
touch-action: manipulation;
を入れたんですけど、どうも効かないです。というか、効いてたり効かなかったりです。調べたんですが、解決できませんでした。どなたか知りませんか・・・?
別記事でスケッチもだしますがポート80はfauxmoESPでアレクサが使っているので81ポートとしています。ほかのリモコン画面も、これとほぼ一緒です。これをSPIFFSに転送しておきます。SPIFFSの転送方法については下の記事を参考にしてください。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html lang="ja"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> | |
<link rel="stylesheet" type="text/css" href="button.css" /> | |
<title>エアコンリモコン</title> | |
</head> | |
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script> | |
<script> | |
//温度変更のみに利用するグローバル変数 | |
before_ac_mode = 0; | |
before_ac_act = 'off'; | |
function get_ac_state(){ | |
if(before_ac_act=='off'){ | |
return ['停止中','#808080']; | |
}else{ | |
if(before_ac_mode == 0) return ['自動運転中','#00FF00']; | |
if(before_ac_mode == 1) return ['除湿運転中','#00FF00']; | |
if(before_ac_mode == 2) return ['冷房運転中','#668ad8']; | |
if(before_ac_mode == 3) return ['暖房運転中','#ff7f50']; | |
return ['運転中','#00FF00']; | |
} | |
} | |
$(function() { | |
/* スライダーバーの現在値表示 */ | |
// 初期 | |
var ret_st = get_ac_state(); | |
|
|
$('#temp').css('color',ret_st[1]); | |
$('#bar').on('input change', function() { | |
// 変動 | |
var ret_st = get_ac_state(); | |
|
|
$('#temp').css('color',ret_st[1]); | |
}); | |
}); | |
// エアコン温度変更時処理 | |
function ac_change_temp(){ | |
//数値変更でもしエアコン運転中なら前の命令を参考に温度変更 | |
if(before_ac_act=='on'){ | |
var params = {}; | |
params["act"] = before_ac_act; | |
params["mode"] = before_ac_mode; | |
params["temp"] = $('#bar').val(); | |
$.ajax({ | |
type: 'GET', | |
url: 'ac', | |
data:params, | |
dataType: 'html', | |
success: function(data) { | |
}, | |
error: function(data) { | |
} | |
}); | |
} | |
} | |
// エアコン制御リクエスト | |
function ac_send(act_st = 'off',mode = 0,temp = 25){ | |
var params = {}; | |
params["act"] = act_st; | |
params["mode"] = mode; | |
params["temp"] = temp; | |
$.ajax({ | |
type: 'GET', | |
url: 'ac', | |
data:params, | |
dataType: 'html', | |
success: function(data) { | |
before_ac_mode = mode; | |
before_ac_act = act_st; | |
//運転状況表示 | |
var ret_st = get_ac_state(); | |
|
|
$('#temp').css('color',ret_st[1]); | |
}, | |
error: function(data) { | |
} | |
}); | |
} | |
</script> | |
<body> | |
<center> | |
<h1>居間エアコンリモコン</h1> | |
<div style="width: 900px; margin-top:55px;"> | |
<input type="range" id="bar" onchange="ac_change_temp();" style="margin-bottom:30px;" min="15" max="30" step="1" value="25"> | |
<span class='slide_temp' id='temp'></span> | |
</div> | |
<div class="one_btn_frame" style="margin-top:20px"> | |
<a href="javascript:void(0)" onClick="ac_send();" class="btn-square-shadow btn-gray" style="width:900px;height:250px;font-size: 9.0em;">停止</a> | |
</div> | |
<div class="one_btn_frame"> | |
<a href="javascript:void(0)" onClick="ac_send('on',2,$('#bar').val());" class="btn-square-shadow btn-blue" style="width:900px;height:250px;font-size: 9.0em;">冷房</a> | |
</div> | |
<div class="one_btn_frame"> | |
<a href="javascript:void(0)" onClick="ac_send('on',3,$('#bar').val());" class="btn-square-shadow btn-orange" style="width:900px;height:250px;font-size: 9.0em;">暖房</a> | |
</div> | |
<div class="one_btn_frame" style="margin-top:30px"> | |
<a href="index.html" class="btn-square-shadow btn-green" style="width:900px;height:200px;font-size: 8.0em;">ホームに戻る</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;margin-top:30px"> | |
</center> | |
</body> | |
</html> |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html lang="ja"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> | |
<link rel="stylesheet" type="text/css" href="button.css" /> | |
<title>ホームセキュリティ状態</title> | |
</head> | |
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script> | |
<script> | |
$(function() { | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'temp' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#temp').html(data + '℃'); | |
}, | |
error: function(data) { | |
$('#temp').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'humi' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#humi').html(data + '%'); | |
}, | |
error: function(data) { | |
$('#humi').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'cds' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#cds').html(data); | |
}, | |
error: function(data) { | |
$('#cds').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'security' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#security').html(data); | |
}, | |
error: function(data) { | |
$('#security').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'alarm' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#alarm').html(data); | |
}, | |
error: function(data) { | |
$('#alarm').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'line' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#line').html(data); | |
}, | |
error: function(data) { | |
$('#line').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'sb412' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#sb412').html(data); | |
}, | |
error: function(data) { | |
$('#sb412').html('<span class="red">N/A</span>'); | |
} | |
}); | |
$.ajax({ | |
type: 'GET', | |
url: 'get', | |
data:{ inf:'time' }, | |
dataType: 'html', | |
success: function(data) { | |
$('#time').html(data + ' 時点の状態'); | |
}, | |
error: function(data) { | |
$('#time').html('<span class="red">N/A</span>'); | |
} | |
}); | |
/* スライダーバーの現在値表示 */ | |
// 初期 | |
|
|
$('#bar').on('input change', function() { | |
// 変動 | |
|
|
}); | |
// アラーム発報のイベント | |
$('#beep_on').click(function() { | |
if (!confirm($('#bar').val()+'秒間のアラーム発報を行いますか?')) { | |
return false; | |
} else { | |
$.ajax({ | |
type: 'GET', | |
url: 'beep', | |
data:{ act:'on',sec:$('#bar').val() }, | |
dataType: 'html', | |
success: function(data) { | |
}, | |
error: function(data) { | |
} | |
}); | |
} | |
}); | |
}); | |
/* セキュリティセット */ | |
function set_security_request(state_st) { | |
if(!state_st) return; | |
var url = "./set?inf=security&state=" + state_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.onload = function () { | |
if (request.readyState === request.DONE) { | |
if (request.status === 200) { | |
location.reload(); | |
} | |
} | |
}; | |
request.send(null); | |
} | |
/* アラームセット */ | |
function set_alarm_request(state_st) { | |
if(!state_st) return; | |
var url = "./set?inf=alarm&state=" + state_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.onload = function () { | |
if (request.readyState === request.DONE) { | |
if (request.status === 200) { | |
location.reload(); | |
} | |
} | |
}; | |
request.send(null); | |
} | |
/* ライン・セットとラインテスト送信 */ | |
function send_line_request(state_st) { | |
if(!state_st) return; | |
var url = "./set?inf=line&state=" + state_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.onload = function () { | |
if (request.readyState === request.DONE) { | |
if (request.status === 200) { | |
location.reload(); | |
} | |
} | |
}; | |
request.send(null); | |
} | |
</script> | |
<body> | |
<center> | |
<h1>居間リモコン・セキュリティ</h1> | |
<div class="some_btn_frame" style="height:90px;"> | |
<a href="tv_remo.html" class="btn-square-shadow btn-green" style="width:440px;">テレビ</a> | |
<a href="light_remo.html" class="btn-square-shadow btn-green" style="width:440px;">照明</a> | |
</div> | |
<div class="some_btn_frame" style="height:90px;"> | |
<a href="ac_remo.html" class="btn-square-shadow btn-green" style="width:440px;">エアコン</a> | |
<a href="" class="btn-square-shadow btn-green" style="width:440px;">予備</a> | |
</div> | |
<table> | |
<tr> | |
<th colspan="2"><span id='time'></span></th> | |
</tr> | |
<tr> | |
<td>警備</td> | |
<td><span id="security"></span></td> | |
</tr> | |
<tr> | |
<td>アラーム</td> | |
<td><span id="alarm"></span></td> | |
</tr> | |
<tr> | |
<td>ライン通知</td> | |
<td><span id='line'></span></td> | |
</tr> | |
<tr> | |
<td>明るさ</td> | |
<td><span id='cds'></span></td> | |
</tr> | |
<tr> | |
<td>室温</td> | |
<td><span id='temp'></span></td> | |
</tr> | |
<tr> | |
<td>湿度</td> | |
<td><span id='humi'></span></td> | |
</tr> | |
<tr> | |
<td>人感センサ</td> | |
<td><span id='sb412'></span></td> | |
</tr> | |
</table> | |
<div class="some_btn_frame" style="height:110px;"> | |
<a href="javascript:void(0)" onClick="set_security_request('switch');return false;" class="btn-square-shadow btn-blue" style="width:440px;">警備切替</a> | |
<a href="javascript:void(0)" onClick="set_alarm_request('switch');return false;" class="btn-square-shadow btn-blue" style="width:440px;">アラーム切替</a> | |
</div> | |
<div class="some_btn_frame" style="height:110px;"> | |
<a href="javascript:void(0)" onClick="send_line_request('switch');return false;" class="btn-square-shadow btn-blue" style="width:440px;">LINE通知切替</a> | |
<a href="javascript:void(0)" id="beep_on" class="btn-square-shadow btn-red" style="width:440px;">アラーム発報</a> | |
</div> | |
<div style="width: 900px; margin-top:45px;"> | |
<input type="range" id="bar" style="margin-bottom:15px;" min="5" max="60" step="5" value="10"> | |
<span class='slide' id='beep_sec'></span> | |
</div> | |
</center> | |
</body> | |
</html> |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html lang="ja"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> | |
<link rel="stylesheet" type="text/css" href="button.css" /> | |
<title>照明リモコン</title> | |
</head> | |
<script> | |
/* 照明用サーバーに押したボタンに応じてリクエストを送る */ | |
function light_ir_request(action_st) { | |
if(!action_st) return; | |
var url = "./light?act=" + action_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.send(null); | |
} | |
/* 押したボタンに応じてリクエストを送る */ | |
function ir_request(action_st) { | |
if(!action_st) return; | |
var url = "./" + action_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.send(null); | |
} | |
</script> | |
<body> | |
<center> | |
<h1>居間照明リモコン</h1> | |
<div class="one_btn_frame" style="margin-top:20px"> | |
<a href="javascript:void(0)" onClick="light_ir_request('on');return false;" class="btn-square-shadow btn-red" style="width:900px;height:200px;font-size: 7.0em;">全灯(ON)</a> | |
</div> | |
<div class="one_btn_frame"> | |
<a href="javascript:void(0)" onClick="light_ir_request('off');return false;" class="btn-square-shadow btn-gray" style="width:900px;height:200px;font-size: 7.0em;">消灯(OFF)</a> | |
</div> | |
<div class="one_btn_frame"> | |
<a href="javascript:void(0)" onClick="light_ir_request('like');return false;" class="btn-square-shadow btn-orange" style="width:900px;height:200px;font-size: 7.0em;">お好み調光</a> | |
</div> | |
<div class="one_btn_frame"> | |
<a href="javascript:void(0)" onClick="light_ir_request('lamp');return false;" class="btn-square-shadow btn-blue" style="width:900px;height:200px;font-size: 7.0em;">弱調光</a> | |
</div> | |
<div class="some_btn_frame" style="height:200px;"> | |
<a href="javascript:void(0)" onClick="light_ir_request('up');return false;" class="btn-square-shadow btn-blue" style="width:440px;font-size: 9.0em;">明▲</a> | |
<a href="javascript:void(0)" onClick="light_ir_request('down');return false;" class="btn-square-shadow btn-blue" style="width:440px;font-size: 9.0em;">暗▼</a> | |
</div> | |
<div class="one_btn_frame" style="margin-top:30px"> | |
<a href="index.html" class="btn-square-shadow btn-green" style="width:900px;height:120px;">ホームに戻る</a> | |
</div> | |
</center> | |
</body> | |
</html> |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | |
<html lang="ja"> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> | |
<link rel="stylesheet" type="text/css" href="button.css" /> | |
<title>テレビリモコン</title> | |
</head> | |
<script> | |
/* テレビ用サーバーに押したボタンに応じてリクエストを送る */ | |
function tv_ir_request(action_st) { | |
if(!action_st) return; | |
var url = "./tv?act=" + action_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.send(null); | |
} | |
/* 押したボタンに応じてリクエストを送る */ | |
function ir_request(action_st) { | |
if(!action_st) return; | |
var url = "./" + action_st; | |
var request = new XMLHttpRequest(); | |
request.open('GET', url); | |
request.send(null); | |
} | |
</script> | |
<body> | |
<center> | |
<h1>居間TVリモコン</h1> | |
<div class="some_btn_frame" style="height:140px;border-spacing: 10px 0;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('power');return false;" class="btn-square-shadow btn-red" style="width:260px;">電源</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('chi');return false;" class="btn-square-shadow btn-blue" style="width:150px;">地上</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('bs');return false;" class="btn-square-shadow btn-blue" style="width:150px;">BS</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('cs');return false;" class="btn-square-shadow btn-blue" style="width:150px;">CS</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('4k');return false;" class="btn-square-shadow btn-blue" style="width:150px;">4K</a> | |
</div> | |
<div class="some_btn_frame" style="height:140px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('volume_up');return false;" class="btn-square-shadow btn-blue" style="width:440px;">音量▲</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('volume_down');return false;" class="btn-square-shadow btn-blue" style="width:440px;">音量▼</a> | |
</div> | |
<div class="some_btn_frame" style="height:140px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('channel_up');return false;" class="btn-square-shadow btn-blue" style="width:440px;">チャンネル▲</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('channel_down');return false;" class="btn-square-shadow btn-blue" style="width:440px;">チャンネル▼</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('epg');return false;" class="btn-square-shadow btn-blue" style="width:440px;">番組表</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('reclist');return false;" class="btn-square-shadow btn-blue" style="width:440px;">録画リスト</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('up');return false;" class="btn-square-shadow btn-blue" style="width:286px;">↑</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('left');return false;" class="btn-square-shadow btn-blue" style="width:286px;">←</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('ok');return false;" class="btn-square-shadow btn-blue" style="width:286px;">決定</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('right');return false;" class="btn-square-shadow btn-blue" style="width:286px;">→</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('back');return false;" class="btn-square-shadow btn-blue" style="width:286px;">戻る</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('down');return false;" class="btn-square-shadow btn-blue" style="width:286px;">↓</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('fin');return false;" class="btn-square-shadow btn-blue" style="width:286px;">終了</a> | |
</div> | |
<div class="some_btn_frame" style="height:120px;"> | |
<a href="javascript:void(0)" onClick="tv_ir_request('beforecha');return false;" class="btn-square-shadow btn-blue" style="width:163px;"><<</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('reverse');return false;" class="btn-square-shadow btn-blue" style="width:163px;"><</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('stop');return false;" class="btn-square-shadow btn-blue" style="width:166px;">停止</a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('forward');return false;" class="btn-square-shadow btn-blue" style="width:163px;">></a> | |
<a href="javascript:void(0)" onClick="tv_ir_request('nextcha');return false;" class="btn-square-shadow btn-blue" style="width:163px;">>></a> | |
</div> | |
<div class="one_btn_frame" style="margin-top:30px"> | |
<a href="index.html" class="btn-square-shadow btn-green" style="width:900px;height:120px;">ホームに戻る</a> | |
</div> | |
</center> | |
</body> | |
</html> |