【MESH カスタムタグ】天気タグを自分で作ってみた 

#できること
MESH*アプリ上で、今外は雨が降っているかどうかを知ることが出来ます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/159447/823c90da-ddc0-34a6-b416-6b480fa57ee0.gif" height=90% width=90%>

*MESHとは、小さな便利を形にできる、ブロック形状の電子タグです。
- [MESH：小さな便利を形にできる、ブロック形状の電子タグ](http://meshprj.com/jp/)


#なぜ今更天気系タグを作ったか
MESH SDKのカスタムタグのサンプルでWeatherタグがあったので、それを利用していたのですが、下記の理由により新しく作る事にしました。
- OpenWeatherMapのAPIの天気の精度が微妙で、当たらないことが多い。
- 指定してると思った住所と違う場所の天気を取得できる場合がある(都市名で利用していたから?)。
- 天気の状態(晴れ・曇り・雨)ではなく、雨の強さを知り**傘が必要かどうか**を知りたかったため。

#仕組み
MESH SDKのカスタムタグ内で下記の2つのAPIを利用して『外は雨かどうか』を判定しています。
- [YOLP(地図):Yahoo!ジオコーダAPI](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/geocoder.html)
- [YOLP(地図):気象情報API](https://developer.yahoo.co.jp/webapi/map/openlocalplatform/v1/weather.html)

![外は雨タグのしくみ.jpg](https://qiita-image-store.s3.amazonaws.com/0/159447/87a94d92-c145-9dd8-b219-bb89efd50c03.jpeg)

気象情報APIを利用して雨の強さを取得するには緯度経度の情報が必要ですが、**緯度経度情報を入力テキストにするのは流石に使い勝手が悪い**ので、まず住所から緯度経度を取得できるYahoo!ジオコーダAPIで利用して、入力された住所から緯度経度を取得し、その情報を基に気象情報APIから雨の強さを求めることにしました。

#実装
##事前準備
下記の2つを使えるように登録しておきます。
- [SDK - Mesh](https://meshprj.com/sdk-jp/)
- [Yahoo! JAPAN Webサービス](https://developer.yahoo.co.jp/start/)

Yahoo! JAPAN Webサービスの**アプリケーションID(下記の画面のClient ID部分)**は後で利用します。
![名称未設定-2.png](https://qiita-image-store.s3.amazonaws.com/0/159447/b4094a95-aad8-faf1-dce8-e7879b2103ce.png)

##MESH SDKの中身の説明
プログラムをExportしたものです。
MESH SDKで下記をimportして、*アプリケーションID**部分を変更したら使えます。
また、Propertyの住所のDefault Valueを良く使う住所にしておくと便利です。

```raining_outside.json
{"formatVersion":"1.0","tagData":{"name":"外は雨？","icon":"data:image/png;base64,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","description":"指定した住所の降水強度を調べ、外が雨かどうかを判断します","functions":[{"id":"function_0","name":"外が雨かどうか調べる","connector":{"inputs":[{"label":""}],"outputs":[{"label":"晴れor曇り"},{"label":"雨"},{"label":"豪雨"}]},"properties":[{"name":"住所","referenceName":"location","type":"string","defaultValue":"住所を入力してください(良く使う住所を設定しておくと便利です)"}],"extension":{"initialize":"return {\n\truntimeValues : {\n\t\toutputIndex : 0\n\t},\n\tresultType : \"continue\"\n};","receive":"","execute":"var locationURL = \"https://map.yahooapis.jp/geocode/V1/geoCoder\";\nvar weatherURL = \"https://map.yahooapis.jp/weather/V1/place\";\nvar client_id = \"YOUR_APPLICATION_ID\";\n\n//緯度経度取得用パラメータ\nvar l_data = {\t\n\t\"appid\":client_id,\n\t\"query\" : properties.location,\n\t\"output\":\"json\"\n};\n\n\n//降水強度取得用パラメータ\nvar w_data = {\t\n\t\"appid\":client_id,\n\t\"interval\":\"5\",\n\t\"output\":\"json\"\n};\n\ngetLatLng(locationURL, l_data);\n\n//緯度経度の取得\nfunction getLatLng(_url, _data){\n\tajax ({\n    url : _url,\n\tdata : _data,\n    type : \"GET\",\n    timeout : 5000,\n\t})\n\t.then(\n\t\t//成功時\n\t\tfunction(data){\n\t\t\tvar json_data = JSON.stringify(data);\n\t\t\tvar json_text = JSON.parse(json_data);\n\t\t\t//緯度経度の要素の追加(経度,緯度)\n\t\t\tw_data.coordinates = json_text[\"Feature\"][0][\"Geometry\"][\"Coordinates\"];\t\n\t\t\tlog(\"経度,緯度=\" + w_data.coordinates);\n\t\t\t\n\t\t\t//降水強度の取得\n\t\t\tgetWeather(weatherURL, w_data);\n\t\t},\n\t\t//失敗時\n\t\tfunction(){\n\t\t\tlog('getLatLng: Network error');\n\t\t}\n\t);\t\n}\n\n//降水強度の取得\nfunction getWeather(_url, _data){\n\tajax ({\n    url : _url,\n\tdata : _data,\n    type : \"GET\",\n    timeout : 5000,\n\t})\n\t.then(\n\t\t//成功時\n\t\tfunction(data){\n\t\t\tvar json_data = JSON.stringify(data);\n\t\t\tvar json_text = JSON.parse(json_data);\n\t\t\t\n\t\t\t//5分前、現在、5分後の降水強度を取り出す\n\t\t\tvar past = parseFloat(json_text[\"Feature\"][0][\"Property\"][\"WeatherList\"][\"Weather\"][0][\"Rainfall\"]);\n\t\t\tvar now = parseFloat(json_text[\"Feature\"][0][\"Property\"][\"WeatherList\"][\"Weather\"][1][\"Rainfall\"]);\n\t\t\tvar soon = parseFloat(json_text[\"Feature\"][0][\"Property\"][\"WeatherList\"][\"Weather\"][2][\"Rainfall\"]);\n\t\t\t\n\t\t\tlog(\"5分前の実際の降水強度 = \" + past + \"mm/h\");\n\t\t\tlog(\"現在の予測降水強度 = \" + now + \"mm/h\");\n\t\t\tlog(\"5分後の予測降水強度 = \" + soon + \"mm/h\");\n\t\t\t\n\t\t\t//豪雨\n\t\t\tif(10 < past || 10 < now){\n\t\t\t\truntimeValues.outputIndex = 2;\n\t\t\t}\n\t\t\t//雨\n\t\t\telse if(past != 0 || now != 0 || soon !=0){\n\t\t\t\truntimeValues.outputIndex = 1;\n\t\t\t}\n\t\t\t//晴れ or 曇り\n\t\t\telse{\n\t\t\t\truntimeValues.outputIndex = 0;\n\t\t\t}\n\t\t\t\n\t\t\tcallbackSuccess( {\n\t\t\t\tresultType : \"continue\",\n\t\t\t\truntimeValues : runtimeValues\n\t\t\t} );\n\n\t\t},\n\t\t//失敗時\n\t\tfunction(){\n\t\t\tlog('getWeather: Network error');\n\t\t}\n\t);\t\n}\n\nreturn {\n    resultType : 'pause'\n};","result":"return {\n\tindexes : [ runtimeValues.outputIndex ],\n\tresultType : \"continue\"\n};"}}]}}
```

###Initialize
runtimeValuesの初期化を行います(runtimeValuesとは、同一Function内のメソッド間で共有できる変数です)。

```Initialize.js
return {
	runtimeValues : {
		outputIndex : 0
	},
	resultType : "continue"
};
```
###Receive
特に書くことはありません。

```Receive.js

```

###Execute
3行目にある**YOUR_APPLICATION_ID**の部分をYahoo! JAPAN Webサービス登録後に取得した自分の**アプリケーションID**に置き換えてください。また、雨判定の部分はruntimeValues.outputIndexに値を代入している条件部分を調整する事で、判定の仕方を変更できます。

```Execute.js
var locationURL = "https://map.yahooapis.jp/geocode/V1/geoCoder";
var weatherURL = "https://map.yahooapis.jp/weather/V1/place";
var client_id = "YOUR_APPLICATION_ID";

//緯度経度取得用パラメータ
var l_data = {	
	"appid":client_id,
	"query" : properties.location,
	"output":"json"
};


//降水強度取得用パラメータ
var w_data = {	
	"appid":client_id,
	"interval":"5",
	"output":"json"
};

getLatLng(locationURL, l_data);

//緯度経度の取得
function getLatLng(_url, _data){
	ajax ({
    url : _url,
	data : _data,
    type : "GET",
    timeout : 5000,
	})
	.then(
		//成功時
		function(data){
			var json_data = JSON.stringify(data);
			var json_text = JSON.parse(json_data);
			//緯度経度の要素の追加(経度,緯度)
			w_data.coordinates = json_text["Feature"][0]["Geometry"]["Coordinates"];	
			log("経度,緯度=" + w_data.coordinates);
			
			//降水強度の取得
			getWeather(weatherURL, w_data);
		},
		//失敗時
		function(){
			log('getLatLng: Network error');
		}
	);	
}

//降水強度の取得
function getWeather(_url, _data){
	ajax ({
    url : _url,
	data : _data,
    type : "GET",
    timeout : 5000,
	})
	.then(
		//成功時
		function(data){
			var json_data = JSON.stringify(data);
			var json_text = JSON.parse(json_data);
			
			//5分前、現在、5分後の降水強度を取り出す
			var past = parseFloat(json_text["Feature"][0]["Property"]["WeatherList"]["Weather"][0]["Rainfall"]);
			var now = parseFloat(json_text["Feature"][0]["Property"]["WeatherList"]["Weather"][1]["Rainfall"]);
			var soon = parseFloat(json_text["Feature"][0]["Property"]["WeatherList"]["Weather"][2]["Rainfall"]);
			
			log("5分前の実際の降水強度 = " + past + "mm/h");
			log("現在の予測降水強度 = " + now + "mm/h");
			log("5分後の予測降水強度 = " + soon + "mm/h");
			
			//豪雨
			if(10 < past || 10 < now){
				runtimeValues.outputIndex = 2;
			}
			//雨
			else if(past != 0 || now != 0 || soon !=0){
				runtimeValues.outputIndex = 1;
			}
			//晴れ or 曇り
			else{
				runtimeValues.outputIndex = 0;
			}
			
			callbackSuccess( {
				resultType : "continue",
				runtimeValues : runtimeValues
			} );

		},
		//失敗時
		function(){
			log('getWeather: Network error');
		}
	);	
}

return {
    resultType : 'pause'
};
```

###Result

Execute Function内で決まったruntimeValues.outputIndexから、発火される出力コネクタを決定します。

```Result.js
return {
	indexes : [ runtimeValues.outputIndex ],
	resultType : "continue"
};
```

#使い方
指でコンコン叩いたら、LEDの色で傘がいるかどうかを教えてくれます。
オフィスの自席などで使うことを想定しています。

##MESHアプリ上のプログラム
下記のようにタグを繋げ、住所を測定したい住所に変更してください。
![MESHアプリ画面02.jpg](https://qiita-image-store.s3.amazonaws.com/0/159447/b177d7a8-ac2a-e097-4d40-d3169a76f8a9.jpeg)

トリガー(動きタグ)やアクション(LED)の部分を違うタグに変更すれば、定期的に結果を表示したり、LINE等のサービスに通知したりできます。

##注意事項
Yahoo! JAPANが提供するWeb APIの利用には制限、**1アプリケーションIDごとに1日50000回**なのでその範囲内で利用してください。ちなみに、このカスタムタグを一度利用すると2回ずつ加算されます(ジオコーダと気象情報分)。
 [Yahoo! JAPANが提供するWeb AP利用制限について](https://developer.yahoo.co.jp/appendix/rate.html)

#感想
わざわざ調べなくても、知りたい時にちょっとしたアクションで必要な情報だけ知れるのは便利でした。また、OpenWeatherMapのAPIを無料利用するのに比べて体感的に精度はかなり良かったです。

#その他
表面
![教えてコンコン天気_表面.JPG](https://qiita-image-store.s3.amazonaws.com/0/159447/5e55c5ea-b1ba-8c97-71c4-db19b2c52674.jpeg)

背面
![教えてコンコン天気_背面.JPG](https://qiita-image-store.s3.amazonaws.com/0/159447/01fb8454-3e9d-7863-31d1-2e62f9068eef.jpeg)

裏面
![教えてコンコン天気_底面.JPG](https://qiita-image-store.s3.amazonaws.com/0/159447/9afee836-6ae2-0f12-3ed1-447300800be5.jpeg)

また、今回のMESH上のカスタムタグの傘のアイコンは、下記の無料アイコンサイトのものを利用しています。
- [FLAT ICON DESIGN](http://flat-icon-design.com/)