iPhoneを使ってM5BALAを操作する（JavaScript-MQTT編）

#概要

前の投稿で [M5BALAをMQTT経由で制御する](https://qiita.com/inasawa/items/2b89368a5796d6984155) をやっていますが、今回は iPhone をコントローラーとして使用し、MQTT経由で制御コマンドを送信することで、M5BALA を操作します。

- MQTT Broker で MQTT on Websocket を使えるようにする
- iPhone の傾きを JavaScript で検知する
- JavaScript から　MQTT on Websocket 経由で制御コマンドを送信する
- 受信した制御コマンドに従ってM5BALA+M5GOが動く

##環境

- M5BALA+M5GO
- M5UI.Flow (Firmware 0.7.2/0.8.0 で確認)
- iMac (macOS Mojave)
- MQTT Broker (mosquitto version 1.4.15)
- MQTT Client ([Eclipse Paho JavaScript Client 1.0.3](https://www.eclipse.org/paho/clients/js/))
- iPhone6 iOS 12.0.1

#実行例

iPhoneを前後左右に傾けることで、M5BALAが前進・後進・右回転・左回転します。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">iPhoneをコントローラーとしてM5BALAを操作することができました。<br>「iPhoneを使ってM5BALAを操作する（JavaScript編）」<a href="https://t.co/BQwqeSBfEW">https://t.co/BQwqeSBfEW</a><a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://twitter.com/hashtag/M5BALA?src=hash&amp;ref_src=twsrc%5Etfw">#M5BALA</a> <a href="https://t.co/K7WeJ2t53L">pic.twitter.com/K7WeJ2t53L</a></p>&mdash; 稲澤祐一 (@inasawa) <a href="https://twitter.com/inasawa/status/1054570605435998209?ref_src=twsrc%5Etfw">2018年10月23日</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

#iPhone用コントローラーページ

iPhoneの前後左右の傾きに応じて、左右の車輪を動かすための指示をMQTT経由で送信する仕組みです。Web Server に以下のページを置いて iPhone から開きます。

```html:m5bala_mqtt.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>M5BALA Controller</title>
    <script src="js/paho-mqtt-min.js" type="text/javascript"></script>
    <script>
			console.log("from script "+location.hostname);
			// Create a client instance
			client = new Paho.MQTT.Client(location.hostname, 9001, "JavaScriptMQTTClient");

			// set callback handlers
			client.onConnectionLost = onConnectionLost;
			client.onMessageArrived = onMessageArrived;

			// connect the client
			console.log("connect the client");
			client.connect({onSuccess:onConnect, onFailure:function(){console.log("onFailure")}});
			
			// called when the client connects
			function onConnect() {
				// Once a connection has been made, make a subscription and send a message.
				console.log("onSuccess");
				// 接続したら最初に I (パラメータリセット) を送信
				message = new Paho.MQTT.Message("I");
				message.destinationName = "M5BALA";
				client.send(message);
				event_timer = 0;
				last_action = '';
				window.addEventListener('deviceorientation', function(event) {
					// イベントが発生するたびに送信すると多すぎるので、ここでは500ms間隔で送信しています。
					if (performance.now() > event_timer) {
						now = performance.now();
						event_timer = now + 500;

						document.getElementById('alpha').innerHTML = event.alpha.toFixed(2);
						document.getElementById('beta').innerHTML  = event.beta.toFixed(2);
						document.getElementById('gamma').innerHTML = event.gamma.toFixed(2);
						
						// 傾きは、前後、左右、それぞれ60度の範囲内で操作する
						move = Math.max(-60, Math.min(60, event.beta))  * 4;
						turn = Math.max(-60, Math.min(60, event.gamma)) * 1;
						
						// 傾きに応じて、左右の車輪の動きを指定する
						action = 'L='+(move + turn / 2).toFixed(2)+',R='+(move - turn / 2).toFixed(2);
						// 変化があった場合のみ送信する
						if (action != last_action) {
							console.log(action);
							document.getElementById('action').innerHTML = action;
							message = new Paho.MQTT.Message(action);
							message.destinationName = "M5BALA";
							client.send(message);
							last_action = action;
						}
					}
    		});
			}

			// called when the client loses its connection
			function onConnectionLost(responseObject) {
				if (responseObject.errorCode !== 0) {
					console.log("onConnectionLost:"+responseObject.errorMessage);
				}
			}

			// called when a message arrives
			function onMessageArrived(message) {
				console.log("onMessageArrived:"+message.payloadString);
			}
    </script>
  </head>
  <body style="font-family: sans-serif;">
			<div style="text-align: center; font-size: 300%; padding: 100px;">M5BALA Controller</div>
			<div style="font-size: 400%;">
				<table style="margin: 0 auto;" cellpadding="10">
					<tr><td>方角</td><td id="alpha" align="right"></td></tr>
					<tr><td>前後</td><td id="beta"  align="right"></td></tr>
					<tr><td>左右</td><td id="gamma" align="right"></td></tr>
				</table>
			</div>
			<div id="action" style="text-align: center; font-size: 500%; padding: 40px;"></div>
  </body>
</html>
```

# Mosquitto 立ち上げ

Mosquitto は 通常の MQTT Client を使用する場合は Docker で動かすことで問題ありませんでしたが MQTT on Websocket を使うにあたって（設定の問題なのか、制限なのか）接続できなかったので、今回は Mac 上で Homebrew でインストールしたものを使っています。

mosquitto.conf に以下の行を追加し、MQTT on Websocket を使用可能にします。

```:mosquitto.conf
listener 1883
listener 9001
protocol websockets
```