解説:デバイスの位置を地図に表示するフロー

今回も前回から続いて、Node-RED con 2023の発表で使用したフローの解説を行います。

1回目はセンサーデータをデータストアに保存するフローについて解説しました。2回目は、メール通知するフローについて解説しました。3回目では、センサーデータを地図表示するアプリをクラウド実行環境で実現します。今回が最終回です。

デバイスで動くフロー

前回のフローとほとんど同じですが、Changeノードのプロパティが異なります。例えば、デバイスの経度(longitude)情報を環境変数$Longに、デバイスの緯度(latitude)情報を環境変数$Latに設定しています。

[{"id":"01053414074637dd","type":"change","z":"b31f38e2.ebf108","name":"","rules":[{"t":"set","p":"item.ContentType","pt":"msg","to":"Spot","tot":"str"},{"t":"set","p":"item.SerialNo","pt":"msg","to":"SerialNo","tot":"env"},{"t":"set","p":"item.temperature","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"item.Name","pt":"msg","to":"place","tot":"env"},{"t":"set","p":"item.Message","pt":"msg","to":"\"現在の室温は\"&payload.temperature&\"℃です。\"","tot":"jsonata"},{"t":"set","p":"item.Lat","pt":"msg","to":"Lat","tot":"env"},{"t":"set","p":"item.Long","pt":"msg","to":"Long","tot":"env"},{"t":"set","p":"item.timestamp","pt":"msg","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":260,"wires":[["9a0f5bc354e3a03f","7bd41fbb.b756"]]}]

このフローによって、デバイスから送信された位置情報がデータストアに格納されます。

クラウドで動くフロー

データストアに格納された経度緯度情報を取りだして、地図に表示するフローを作ります。

このフローは今までのフローよりも複雑です。フローはDiscoverに公開していますので、自分のプロジェクトにインポートできます。

enebular | discover | map-flow

LCDPノード

LCDPノードでフローの前後が囲まれています。これは、クラウド実行環境のHTTPトリガーでフローを呼び出すためです。

データストアノード

データストアに格納された位置情報データを取りだします。ここでは、メインキーがSpotであるもの、かつ、サブキーが0以上のものを、100個まで取り出すように指定しています。

Changeノード(マップ設定)

マップの初期表示に必要な設定をしています。

Templateノード(HTML出力)

Templateノードで、マップ表示に必要なHTMLを作っています。leafletというライブラリを使っています。JavaScriptでデータストアから受け取ったデータをポイントに表示しています。(ここはコーディングの力を借りています。)

<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
    integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI="
    crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"
    integrity="sha256-WBkoXOwTeyKclOHuWtc+i2uENFpDZ9YPdf5Hf+D7ewM="
    crossorigin=""></script>
<style>
    #map { height: 1024px; }
    .icon-green { /* icon-greenは最初に指定したクラス名 */
  filter: hue-rotate(250deg);
}
</style>
</head>
<body>
<div id="map"></div>
<script>
const greenIcon = L.icon({
  iconUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-icon.png",
  iconRetinaUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-icon-2x.png",
  shadowUrl: "https://esm.sh/leaflet@1.9.2/dist/images/marker-shadow.png",
  iconSize: [25, 41],
  iconAnchor: [12, 41],
  popupAnchor: [1, -34],
  tooltipAnchor: [16, -28],
  shadowSize: [41, 41],
  className: "icon-green", // <= ここでクラス名を指定
});

// マップの初期位置
let map = L.map('map', {
  center: [
    {{mapSetting.startLocationLat}},
    {{mapSetting.startLocationLong}}
    ],
  zoom: 13,
});

L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 19,
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);

// マーカー 1 番目
let marker1 = L.marker(
    [
        {{mapSetting.marker1LocationLat}},
        {{mapSetting.marker1LocationLong}}
    ],
    {icon: greenIcon }
).addTo(map);
marker1.bindPopup("{{{mapSetting.marker1Message}}}").openPopup();

const spot = {{{mapSetting.spot}}};

for(let i = 0; i < spot.length; i++){
    console.log(i);
    const item = spot[i];
    console.log(item);
    const lat = Number(item.Lat);
    const lon = Number(item.Long);
    let marker = L.marker([lat, lon]).addTo(map);
    marker.bindPopup("<b>" + item.Name + "</b><p>" + item.Message + "</p>");
}

</script>
</body>
</html>

実行環境の設定

エージェント実行環境

それぞれのエージェント実行環境の設定タブをクリックしてください。

環境変数を設定するため、環境変数を編集するボタンをクリックしてください。

ここでは、デバイスの位置情報や場所の名前、シリアル番号などを入力できるようにしています。

また、クラウド実行環境との接続もONになっていることを確認します。

クラウド実行環境

メールで通知するフローで使ったクラウド実行環境とは別のクラウド実行環境を作っておきます。

HTTPトリガーをONにして、URLを設定してください。

データストア接続がONになっていることを確認します。

デプロイ

デバイスのエージェント実行環境にセンサーデータのフローをデプロイします。

また、クラウド実行環境にも地図のフローをデプロイします。

動作確認

さきほど地図のフローをデプロイしたクラウド実行環境のHTTPトリガーのURLをブラウザで開きます。

すると、データストアに格納された経度緯度情報をもとに、デバイスの位置をマップに付置してくれます。

まとめ

今回は、データストアに保存された経度緯度情報を元に地図表示をするフローについて解説しました。クラウド実行環境でWebページが作れるので、サーバーを用意したり、運用しなくてよいメリットがあります。

今回は環境変数で経度緯度情報を設定しましたが、フローを改造して、GPSの位置情報を取得してそれを元に、経度緯度情報をフローの中で設定すれば、リアルタイムの位置情報表示も可能になるでしょう。

全部説明し切れていない部分もあるかと思います。不明な点がありましたら、お気軽にサポートまでご連絡ください。