sakura.ioで位置情報を送受信&マップに表示する

#はじめに
　はじめまして、Lily.Mameokaです。今回はマイコン向けのインターネットモジュール、sakura.ioを使って位置情報を送受信し、最終的にはその位置情報をマップ上に表示したいと思います。
sakura.io、参考になりそうなものが少ないもので...と思いまして、、、この記事が今後sakura.ioとGPSモジュールを使って何かしたい！って人の役に立てば幸いです。
##前提
　まず、この作業をする上での前提となる事項は...

・PCにArduino IDEが入っている
・さくらインターネットの会員登録ができている
・sakura.ioのモジュールの登録ができている
・WebSocket連携サービスの追加ができている
・SakuraIOライブラリがインストールしてある
・GPSモジュール(太陽誘電製小型高感度GPSモジュールGYSFDMAXB)を用いて位置情報を取得するくらいならできる

といったことですかね。要するにsakura.ioをArduinoで使えるように準備してあればダイジョウブというわけであります。GPSモジュールの基本的な使い方は以下の記事が参考になるかと思います。
https://deviceplus.jp/hobby/entry060/
##配線
GPSモジュールの配線は以下の通りです。
5V  ⇨5V
GND ⇨GND
RXD ⇨11
TXD ⇨10
1PPS⇨(使わない)

sakura.ioはこ↑こ↓にジャンパーピンを刺します。
<img width="375" alt="IMG_8394.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/334730/c9a41afa-dd3c-ffe2-972b-5380b6964ed8.jpeg">

最終的にこうなります。
<img width="375" alt="IMG_8397.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/334730/56f4c7a1-a0cf-c63b-4379-4cca1fc6c55e.jpeg">
配線が汚いのはお兄さん許して!
これで完了です。あ、そうそう、sakura.ioを使うときはPCからの電源だけでは安定しないので一応ACアダプタからの電源もとると安心。
#本題(sakura.ioを用いて位置情報を送受信)
　それではsakura.ioを使って位置情報を送受信してみたいと思います。Arduinoは以下のプログラムでデータ(緯度・経度)を送信します。Arduinoに関しては初心者なので、コードの可読性とかは許して。。。

```
#include <SakuraIO.h>
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;
SoftwareSerial mySerial(10, 11);

SakuraIO_I2C sakuraio;

float lat;
float lng;

void setup(){
    
    Serial.begin(57600);
    while (!Serial) {
        ;
    }
    Serial.println("Goodnight moon!");
    mySerial.begin(9600);
    mySerial.println("Hello, world?");
    while((sakuraio.getConnectionStatus() & 0x80) != 0x80){
        delay(1000);
    }
    
}

void loop() {
    
    while (mySerial.available() > 0){
        char c = mySerial.read();
        gps.encode(c);
        if (gps.location.isUpdated()){
            Serial.print("LAT="); Serial.println(gps.location.lat(), 6);
            Serial.print("LONG="); Serial.println(gps.location.lng(), 6);
            lat=gps.location.lat();
            lng=gps.location.lng();
            sakuraio.enqueueTx(0,lat);
            sakuraio.enqueueTx(1,lng);
            sakuraio.send();
            delay(30000);
        }
    }
    
}
```

##まずはsakura.ioのコントロールパネルにて
　上記のプログラムをArduinoに書き込み、位置情報がきちんと取得されていることをシリアルモニターで確認してから、sakura.ioのコントロールパネルを開きます。

コントロールパネルホーム
↓
プロジェクトの詳細
↓
連携サービスの編集(連携サービスのところにある設定のマークです)
↓
詳細表示モードに切り替え

そうすると「チャンネル毎の最終到着データ」のCh:0に緯度が、Ch:1に経度が出てきます。これができればひとまず第一段階はクリアです。
![IMG_8400.PNG](https://qiita-image-store.s3.amazonaws.com/0/334730/0e2eb479-2afe-6dbf-66ef-32abe0bbb2b8.png)
こんな感じ
##Google Mapsのリンクにしてみる(?)
　一応データの送受信はできました。しかし、コントロールパネルにデータがあってもあんまし役には立たない。じゃあどうすべ。よし、この位置情報をGoogle Mapsのリンクにぶちんこでやればいいじゃないか。
(https://www.google.com/maps?q=緯度,経度)
Google Mapsのリンクは上記のようになっている。

（ペチン！）よし、じゃあぶちこんでやるぜ！

```html:getData.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<script>
const url = "連携サービスの編集のページにあるwss://から始まるURL";

function readstart() {
  var output = document.getElementById('msgarea');
  var client = new WebSocket(url);

  client.onopen = function() {
    output.innerHTML = output.innerHTML + "全速前進ヨーソロー！！\n";
  };
  
  client.onerror = function(error) {
    alert(error);
  };
  
  client.onmessage = function(e) {
    var data = JSON.parse(e.data);
    if (data.type == 'channels') {

      var datalist = data.payload.channels;
      
      for (var i = 0; i < datalist.length; i++) {
        if ((datalist[i].channel == 0)||(datalist[i].channel == 1)) {
          var lat = datalist[0].value;
          var lng = datalist[1].value;
          var date = new Date(datalist[i].datetime);
          var y = date.getFullYear();
          var m = date.getMonth() + 1;
          var d = date.getDate();
          var hour = date.getHours();
          var min = date.getMinutes();
          var sec = date.getSeconds();
          
          output.innerHTML = output.innerHTML + 
            y + "年" + m + "月" + d + "日" + 
            hour + "時" + min + "分" + sec + "秒" + ":  https://www.google.com/maps?q="+lat+","+lng+"\n";
        }
      }
    }
  };
}
</script>
</head>
<body>
<h1>GoogleMaps</h1>
<textarea id="msgarea" cols="40" rows="10"></textarea><br>
<input type="button" onclick="readstart();" value="読み取り開始">
</body>
</html>
```

この結果がこんな感じ。
<img width="1009" alt="無題58.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/851932a7-e3ab-b451-7647-7663aa87573e.png">
ん？リンクになってない？そりゃそうだ。ただ表示されているだけだもの。使うときはこれをブラウザにコピペしないと。。。うーん、めんどくさい。でも、これでsakura.ioから完全にデータを取り出すことができた。
##地図に表示させる(Leafletを使う)
　リンク生成はできなかった(←諦めるの早いぞ)ので直接地図に表示してみる。じゃあGoogleMapsAPIを......え？登録にクレジットカード番号が必要なの？めんどくさいな...。
...というわけで完全無料なLeafletを使うことにしました。地図データは国土地理院が出している「地理院タイル」というものを。地理院タイル、航空写真もあるんですか！ファッ！たまげたなぁ

　まずはLeafletがどういうものなのか試してみる。導入は下記のリンクからどうぞ。
https://leafletjs.com
このLeafletのホームページ、結構分かりやすく使い方載ってるからいいぞ＾〜これ。私もこのホームページを参考にして試す。

```html:getDataOnMap01.html
<!DOCTYPE html>
<html>
<head>
    <title>114514 - Leaflet</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
    var mymap = L.map('mapid').setView([35.0212649, 138.8837682], 14);
    L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/ort/{z}/{x}/{y}.jpg', {
    maxZoom: 18
    })
    .addTo(mymap);
</script>
</body>
</html>
```

この結果がこれ。
<img width="1009" alt="スクリーンショット 2019-01-09 18.24.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/1d294b46-f9d7-38e2-412c-668b0eccd7f0.png">

##位置情報を地図に表示する
　さてさて、次のステップへ。これでLeafletはうまくいきましたが、ちょっと航空写真だと見にくい。。。そこでOpenStreetMapを使ってみる。さっきの一部を変えて、

```html:getDataOnMap02.html
<!DOCTYPE html>
<html>
<head>
    <title>114514 - Leaflet</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
    var mymap = L.map('mapid').setView([35.0212649, 138.8837682], 14);
    L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 18
    })
    .addTo(mymap);
</script>
</body>
</html>
```

地図データを入れ替えただけです。
<img width="1009" alt="スクリーンショット 2019-01-09 18.36.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/adef1924-e2a2-e910-bbc6-31da57121548.png">
見やすい！！
ここからはOpenStreetMapを使うことにします。

```html:getDataOnMap03.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
    <title>114514 - Leaflet</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
const url = "連携サービスの編集のページにあるwss://から始まるURL";

function readstart() {
  var output = document.getElementById('msgarea');
  var client = new WebSocket(url);

  client.onopen = function() {
    output.innerHTML = output.innerHTML + "全速前進ヨーソロー！！\n";
  };
  
  client.onerror = function(error) {
    alert(error);
  };
  
  client.onmessage = function(e) {
    var data = JSON.parse(e.data);
    if (data.type == 'channels') {

      var datalist = data.payload.channels;
      
      for (var i = 0; i < datalist.length; i++) {
        if ((datalist[i].channel == 0)||(datalist[i].channel == 1)) {
          var lat = datalist[0].value;
          var lng = datalist[1].value;
          var date = new Date(datalist[i].datetime);
          var y = date.getFullYear();
          var m = date.getMonth() + 1;
          var d = date.getDate();
          var hour = date.getHours();
          var min = date.getMinutes();
          var sec = date.getSeconds();
          
          output.innerHTML = output.innerHTML + 
            y + "年" + m + "月" + d + "日" + 
            hour + "時" + min + "分" + sec + "秒" + ":  https://www.google.com/maps?q="+lat+","+lng+"\n";
            
     var mymap = L.map('mapid').setView([lat , lng], 15);
    L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
    })
    .addTo(mymap);
        }
      }
    }
  };
}
</script>
<textarea id="msgarea" cols="40" rows="10"></textarea><br>
<input type="button" onclick="readstart();" value="読み取り開始">
</head>
</body>
</html>
```

この結果がこれ。
<img width="1009" alt="無題59 2.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/35dad1b2-e74a-f76e-3093-2aeff7c3b45d.png">
成功！！
でもこれではどこだか正確にはわからない。そこでピンを立てる。

```html:getDataOnMap04.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
    <title>114514 - Leaflet</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
const url = "連携サービスの編集のページにあるwss://から始まるURL";

function readstart() {
  var output = document.getElementById('msgarea');
  var client = new WebSocket(url);

  client.onopen = function() {
    output.innerHTML = output.innerHTML + "全速前進ヨーソロー！！\n";
  };
  
  client.onerror = function(error) {
    alert(error);
  };
  
  client.onmessage = function(e) {
    var data = JSON.parse(e.data);
    if (data.type == 'channels') {

      var datalist = data.payload.channels;
      
      for (var i = 0; i < datalist.length; i++) {
        if ((datalist[i].channel == 0)||(datalist[i].channel == 1)) {
          var lat = datalist[0].value;
          var lng = datalist[1].value;
          var date = new Date(datalist[i].datetime);
          var y = date.getFullYear();
          var m = date.getMonth() + 1;
          var d = date.getDate();
          var hour = date.getHours();
          var min = date.getMinutes();
          var sec = date.getSeconds();
          
          output.innerHTML = output.innerHTML + 
            y + "年" + m + "月" + d + "日" + 
            hour + "時" + min + "分" + sec + "秒" + ":  https://www.google.com/maps?q="+lat+","+lng+"\n";

     var mymap = L.map('mapid').setView([lat , lng], 15);
     L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
    })
    .addTo(mymap);
    var marker = L.marker([lat , lng])
    .addTo(mymap);
        }
      }
    }
  };
}
</script>
<textarea id="msgarea" cols="40" rows="10"></textarea><br>
<input type="button" onclick="readstart();" value="読み取り開始">
</head>
</body>
</html>
```

この結果がこれ。<img width="1009" alt="無題60.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/a491b819-66f3-709e-515e-eaffacc0eb61.png">
立った！よし、そしたらついでに文字も表示させるか。

```html:getDataOnMap05.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
    <title>114514 - Leaflet</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
const url = "連携サービスの編集のページにあるwss://から始まるURL";

function readstart() {
  var output = document.getElementById('msgarea');
  var client = new WebSocket(url);

  client.onopen = function() {
    output.innerHTML = output.innerHTML + "全速前進ヨーソロー！！\n";
  };
  
  client.onerror = function(error) {
    alert(error);
  };
  
  client.onmessage = function(e) {
    var data = JSON.parse(e.data);
    if (data.type == 'channels') {

      var datalist = data.payload.channels;
      
      for (var i = 0; i < datalist.length; i++) {
        if ((datalist[i].channel == 0)||(datalist[i].channel == 1)) {
          var lat = datalist[0].value;
          var lng = datalist[1].value;
          var date = new Date(datalist[i].datetime);
          var y = date.getFullYear();
          var m = date.getMonth() + 1;
          var d = date.getDate();
          var hour = date.getHours();
          var min = date.getMinutes();
          var sec = date.getSeconds();
          
          output.innerHTML = output.innerHTML + 
            y + "年" + m + "月" + d + "日" + 
            hour + "時" + min + "分" + sec + "秒" + ":  https://www.google.com/maps?q="+lat+","+lng+"\n";
            
     var mymap = L.map('mapid').setView([lat , lng], 15);
     L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
    })
    .addTo(mymap);
    var marker = L.marker([lat , lng])
    .bindPopup("<h1>こ↑こ↓</h1>")
    .addTo(mymap);
        }
      }
    }
  };
}
</script>
<textarea id="msgarea" cols="40" rows="10"></textarea><br>
<input type="button" onclick="readstart();" value="読み取り開始">
</head>
</body>
</html>
```

この結果がこれ。
<img width="1009" alt="無題61.png" src="https://qiita-image-store.s3.amazonaws.com/0/334730/be9b233d-dad0-b0a6-e560-fb3721dcadb9.png">
やったぜ。
これで完成！！
#おわりに
　「sakura.ioで位置情報を送受信&マップに表示する」という当初の目的は達成されました！でも、これだけでは何も役に立たないといえばそりゃそうだ。今回作ったものを何かに搭載することで色々役に立つんじゃないかな...と思っております。小さな子供に持たせるのもいいし、自転車に付けるのもいいし、発電機とかも...色々有効利用方法がありそう。。。

#追記(2019/9/21)
iOSアプリにデータを送信する方法を書きました
https://qiita.com/LilyMameoka/items/3c4f04a48faaab8f7fda