4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

enebularAdvent Calendar 2016

Day 14

自分だけのお天気アプリが欲しくなった。そうだ!enebularがある!

Last updated at Posted at 2016-12-13

自分の居場所を OpenWeatherMap に投げて直近の天気予報を表示するくそアプリ。

  • シンプルイズベスト。
  • 居場所は、 GeoLocation を使用。
  • 天気予報は、 OpenWeatherMap から取得。
  • 天候は、次の4タイプのみとした。 晴れ/曇り/雨/雪

できた!

▼ Flow をエクスポート

  • OpenWeatherMap の API Key は書き換えないと動作しない。
[{"id":"34c5cf5.5aa2fb","type":"http in","z":"f582755b.efeaf8","name":"request weather app","url":"/weather","method":"get","swaggerDoc":"","x":150,"y":80,"wires":[["2d6206d5.b21842"]]},{"id":"c56f0360.c2cce8","type":"template","z":"f582755b.efeaf8","name":"html","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n    <head>\n        <link href=\"//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css\" rel=\"stylesheet\" />\n        <script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js\"></script>\n        <style type=\"text/css\">\n            {{{css}}}\n        </style>\n        <script type=\"text/javascript\">\n            {{{js}}}\n        </script>\n    </head>\n    <body>\n        <div id=\"weather\">\n            <i id=\"icon\" class=\"fa weathericon\" aria-hidden=\"true\"></i>\n        </div>\n    </body>\n</html>","x":610,"y":80,"wires":[["4708a4b4.ab6014"]]},{"id":"4708a4b4.ab6014","type":"http response","z":"f582755b.efeaf8","name":"response","x":760,"y":80,"wires":[]},{"id":"f089755f.8069c8","type":"http in","z":"f582755b.efeaf8","name":"get weather","url":"/get","method":"get","swaggerDoc":"","x":130,"y":160,"wires":[["6ef16af5.167c9c"]]},{"id":"6ef16af5.167c9c","type":"function","z":"f582755b.efeaf8","name":"make url","func":"var lat = msg.payload.lat;\nvar lon = msg.payload.lon;\nvar baseurl = \"http://api.openweathermap.org/data/2.5/weather\";\nvar appid = \"e4157daxxxxxxxxxxxxxxxxxxb9baf14\";\n\nmsg.url = baseurl + \"?lat=\" + lat + \"&lon=\" + lon + \"&APPID=\" + appid;\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":160,"wires":[["26258434.060ae4"]]},{"id":"c473b665.a208e","type":"http response","z":"f582755b.efeaf8","name":"response","x":880,"y":160,"wires":[]},{"id":"26258434.060ae4","type":"http request","z":"f582755b.efeaf8","name":"call OpenWeatherMap","method":"GET","ret":"obj","url":"","x":500,"y":160,"wires":[["2ecd2991.4b7996"]]},{"id":"2ecd2991.4b7996","type":"function","z":"f582755b.efeaf8","name":"set weather","func":"var weather = msg.payload.weather[0].icon.substr(0, 2);\nvar weatherstring = \"\";\nswitch (weather) {\n    case \"01\":\n        weatherstring = \"sun\";\n        break;\n    case \"02\":\n    case \"03\":\n    case \"04\":\n        weatherstring = \"cloud\";\n        break;\n    case \"09\":\n    case \"10\":\n    case \"11\":\n        weatherstring = \"rain\";\n        break;\n    case \"13\":\n        weatherstring = \"snow\";\n        break;\n    default:\n        weatherstring = \"cloud\";\n        break;\n}\nmsg.payload = weatherstring;\nreturn msg;","outputs":1,"noerr":0,"x":710,"y":160,"wires":[["c473b665.a208e"]]},{"id":"2d6206d5.b21842","type":"template","z":"f582755b.efeaf8","name":"css","field":"css","fieldType":"msg","format":"handlebars","syntax":"plain","template":"html, body {\n    padding: 0;\n    margin: 0;\n    height: 100%;\n    background-color: black;\n}\n#weather {\n    position: relative;\n    height: 100%;\n}\n.weathericon {\n    font-size: 400px;\n    display: block;\n    text-align: center;\n    position: absolute;\n    top: 50%;\n    margin: -200px 0 0 0;\n    width: 100%;\n}\n.cloudy {\n    color: white;\n    background-color: #99a3a4;\n}\n.rainy {\n    color: white;\n    background-color: #85c1e9;\n}\n.sunny {\n    color: white;\n    background-color: #f39c12;\n}\n.snowy {\n    color: white;\n    background-color: #e5e8e8;\n}","x":330,"y":80,"wires":[["9ec2db8a.eb3238"]]},{"id":"9ec2db8a.eb3238","type":"template","z":"f582755b.efeaf8","name":"js","field":"js","fieldType":"msg","format":"handlebars","syntax":"plain","template":"$(function(){\n    var baseurl = \"https://nodered-pro2-35hshwv45.herokuapp.com\";\n\tif( navigator.geolocation ) {\n\t\tnavigator.geolocation.getCurrentPosition(\n\t\t\tfunction( position ){\n\t\t\t\tvar data = position.coords ;\n\t\t\t\tvar lat = data.latitude ;\n\t\t\t\tvar lon = data.longitude ;\n\t\t\t\tconsole.log(lat + \",\" + lon);\n                $.ajax({\n                    type: \"GET\",\n                    url: baseurl + '/get?lat=' + lat + '&lon=' + lon,\n                    dataType: 'text',\n                    cache: true,\n                    timeout: 10000\n                }).done(function(response, textStatus, jqXHR) {\n                    console.log(response);\n                    var wt = '';\n                    var cl = '';\n                    switch (response) {\n                        case \"sun\":\n                            wt  = 'fa-sun-o sunny';\n                            cl = 'sunny';\n                            break;\n                        case \"cloud\":\n                            wt  = 'fa-cloud cloudy';\n                            cl = 'cloudy';\n                            break;\n                        case \"rain\":\n                            wt  = 'fa-tint rainy';\n                            cl = 'rainy';\n                            break;\n                        case \"snow\":\n                            wt  = 'fa-snowflake-o snowy';\n                            cl = 'snowy';\n                            break;\n                    }\n                    $(\"body\").addClass(cl);\n                    $(\"#icon\").addClass(wt);\n                }).fail(function(jqXHR, textStatus, errorThrown ) {\n                    console.error(\"ajax\");\n                });\n\t\t\t},\n\t\t\tfunction( error ){\n\t\t\t    console.error(error.code);\n\t\t\t} ,\n\t\t\t{\n\t\t\t\t\"enableHighAccuracy\": false,\n\t\t\t\t\"timeout\": 8000,\n\t\t\t\t\"maximumAge\": 2000,\n\t\t\t}\n\t\t) ;\n\t} else {\n\t    console.error('geolocation');\n\t};\n});\n","x":470,"y":80,"wires":[["c56f0360.c2cce8"]]}]

▼ こんな Flow

  • UI の流れ
  • 天気予報APIのラッパーAPI的な流れ

01-flow.png

▼ こんなアプリ

iphone-sun.png iphone-cloud.png iphone-rain.png

まずは準備(OpenWeatherMap の Key を取得)

サインアップ

03-openweathermap-signup.png

API Key のページを開いて、API Key をゲット。

04-openweathermap-apikey.png

そして enebular

enebular でログイン。

05-enebular-signin.png

▼ [ +New Project ] ボタンで新規プロジェクトを作成。

06-enebular-newproject.png

▼ [ New Flow ] ボタンで新規フローを作成。

07-enebular-newflow.png

UI の Flow 作成へ

▼ http ノードはこんな感じ。これでアプリのURLが決まる。

08-httpnode.png

▼ アプリはこんなURLになる

▼ ドメイン部分はココ!

08-01-i.png

▼ template ノード(css)はこんな感じ。

  • 今回はtemplateノードを、css用、js用、html用の3つに分割。

09-cssnode.png

css
html, body {
    padding: 0;
    margin: 0;
    height: 100%;
    background-color: black;
}
#weather {
    position: relative;
    height: 100%;
}
.weathericon {
    font-size: 400px;
    display: block;
    text-align: center;
    position: absolute;
    top: 50%;
    margin: -200px 0 0 0;
    width: 100%;
}
.cloudy {
    color: white;
    background-color: #99a3a4;
}
.rainy {
    color: white;
    background-color: #85c1e9;
}
.sunny {
    color: white;
    background-color: #f39c12;
}
.snowy {
    color: white;
    background-color: #e5e8e8;
}

▼ template ノード(js)はこんな感じ。

  • html用のノードでjquery読み込んでるので、jqueryで書く。このjsはhtmlに展開される。
  • navigator.geolocation で、現在位置を取得。
  • 取得した位置情報をパラメータにくっつけて天気予報APIをコール。

10-jsnode.png

js
$(function(){
    var baseurl = "https://nodered-pro2-35hshwv45.herokuapp.com";
	if( navigator.geolocation ) {
		navigator.geolocation.getCurrentPosition(
			function( position ){
				var data = position.coords ;
				var lat = data.latitude ;
				var lon = data.longitude ;
				console.log(lat + "," + lon);
                $.ajax({
                    type: "GET",
                    url: baseurl + '/get?lat=' + lat + '&lon=' + lon,
                    dataType: 'text',
                    cache: true,
                    timeout: 10000
                }).done(function(response, textStatus, jqXHR) {
                    console.log(response);
                    var wt = '';
                    var cl = '';
                    switch (response) {
                        case "sun":
                            wt  = 'fa-sun-o sunny';
                            cl = 'sunny';
                            break;
                        case "cloud":
                            wt  = 'fa-cloud cloudy';
                            cl = 'cloudy';
                            break;
                        case "rain":
                            wt  = 'fa-tint rainy';
                            cl = 'rainy';
                            break;
                        case "snow":
                            wt  = 'fa-snowflake-o snowy';
                            cl = 'snowy';
                            break;
                    }
                    $("body").addClass(cl);
                    $("#icon").addClass(wt);
                }).fail(function(jqXHR, textStatus, errorThrown ) {
                    console.error("ajax");
                });
			},
			function( error ){
			    console.error(error.code);
			} ,
			{
				"enableHighAccuracy": false,
				"timeout": 8000,
				"maximumAge": 2000,
			}
		) ;
	} else {
	    console.error('geolocation');
	};
});

▼ template ノード(HTML)はこんな感じ。矢印の部分の括弧に注意。

  • cssとjsを展開するとこだけ注意。

12-htmlnode.png

html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8" />
        <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" rel="stylesheet" />
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        <style type="text/css">
            {{{css}}}
        </style>
        <script type="text/javascript">
            {{{js}}}
        </script>
    </head>
    <body>
        <div id="weather">
            <i id="icon" class="fa weathericon" aria-hidden="true"></i>
        </div>
    </body>
</html>

▼ http request ノード(response)はこんな感じ。

13-httpresponse.png

天気予報 API を呼び出す API のフロー。

▼ API のエンドポイントのノードはこんな感じ。

14-getweather.png

▼ Function ノード(make url)はこんな感じ。

  • http in ノードで受け取ったパラメータを処理。
  • OpenWeatherMap をコールするURLの作成。

15-makeurl.png

js
var lat = msg.payload.lat;
var lon = msg.payload.lon;
var baseurl = "http://api.openweathermap.org/data/2.5/weather";
var appid = "e4157daxxxxxxxxxxxxxxxxxxb9baf14";

msg.url = baseurl + "?lat=" + lat + "&lon=" + lon + "&APPID=" + appid;
return msg;

▼ http request ノード(make url)はこんな感じ。

16-call.png

▼ Function ノード(set weather)はこんな感じ。

  • 天気を4パターンに集約。

17-setweather.png

js
var weather = msg.payload.weather[0].icon.substr(0, 2);
var weatherstring = "";
switch (weather) {
    case "01":
        weatherstring = "sun";
        break;
    case "02":
    case "03":
    case "04":
        weatherstring = "cloud";
        break;
    case "09":
    case "10":
    case "11":
        weatherstring = "rain";
        break;
    case "13":
        weatherstring = "snow";
        break;
    default:
        weatherstring = "cloud";
        break;
}
msg.payload = weatherstring;
return msg;

▼ Function ノード(response)はこんな感じ。

18-response.png

以上

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?