RaspberryPi
Geolocation
SORACOM
awsIoT

Soracomスターターキットで作るGPSなしの位置情報トラッカー ~その2 AWS IoT連携~

Soracomスターターキットで作るGPSなしの位置情報トラッカー ~その1~からの続きになります

ソースコードは以下になります
ymmtyuhei/GeoLogAWS: Google Geolocation APIを使い取得した位置情報をAmbientに送信する。

AWS IoTのセットアップ

AWS IoTへRaspberry PIからMQTTでメッセージをPublishするまでのRaspberry PiとAWSの環境を、チュートリアルの通り構築します。

Raspberry Pi の接続 - AWS IoT

  • Raspberry PIからメッセージをパブリッシュしたがAWSのウェブコンソールで確認できなかったとき、 デバッグツールとしてMQTT.fxをつかってみるといいかもしれません。

AWS IoTを始めよう -MQTTの設定(MQTT.fx編)-
https://recipe.kc-cloud.jp/archives/9629

スクリーンショット 2018-04-18 17.05.00.png

  • 前回の手順でSoracom AirをセットアップしたRaspberry PIに有線LANのみ接続した状態だと、 AWS IoTへのメッセージのパブリッシュができず、USBモデムを接続したときのみパブリッシュできました。

AWS Lambdaを設定

AWS IoTのカスタムルールを作成します。特定のトピックへのメッセージをフックし、Lambdaを実行する設定をします。

AWS IoT チュートリアル ラムダルールの作成

  • トピックフィルターとしてpisora/ssidsを設定しました。
  • MQTTfxを使いながらテストデータをパブリッシュし、Lambdaが実行されることを確認します。
  • Lambdaの実行ログは CloudWatch>ロググループで確認できます。
  • RasPi側でpisora/updateというトピックをフックして、SSIDの送信処理が実行されるようにしたので、AWS IoT側からそのトピックにメッセージを送信し、動作を確認できます。

スクリーンショット 2018-04-18 17.23.10.png

スクリーンショット 2018-04-18 17.23.22.png

const ambient = require('ambient-lib')
const axios = require('axios')
const geolocation_key = '***'
const ep_geolocation = 'https://www.googleapis.com/geolocation/v1/geolocate?key='+geolocation_key

//ambient.connect(チャネルId, ライトキー[, リードキー[, ユーザーキー]]);
ambient.connect(1234, "***", "***", "***");

function postAmbient(accuracy, lat, lng){
  var ambientData = {
    d5: accuracy, 
    lat: lat, 
    lng: lng
  }
  ambient.send(ambientData, function(err, res) {
      if (err) {
          console.error(err)
      }
      console.log('update to ambient success. :',res.statusCode)
  })
}

function requestPosition(ssids){
  console.log("got ssids")
  console.dir(ssids)
  axios.post(ep_geolocation, ssids)
    .then(function (response) {
      console.log("got geolocation from ssids")
      console.dir(response.data)
      postAmbient(
        response.data.accuracy,
        response.data.location.lat,
        response.data.location.lng
      )
    })
    .catch(function (error) {
      console.log(error)
    })
}

exports.handler = (event, context, callback) => {
  var eventText = JSON.stringify(event, null, 2);
  console.log("Received event:", eventText);
  requestPosition(event)
}

Raspberry PiからSSIDをパブリッシュする

  • AWS IoTの鍵情報などが設定されたRaspberry Piから、定期的にSSIDを送信するスクリプトを展開します。
const piWifi = require('pi-wifi')
const cron = require('node-cron')
const axios = require('axios')
const geolocation_key = '***'
const ep_geolocation = 'https://www.googleapis.com/geolocation/v1/geolocate?key='+geolocation_key
let awsIot = require('aws-iot-device-sdk')
let device = awsIot.device({
  keyPath: "/home/pi/deviceSDK/certs/private.pem.key",
 certPath: "/home/pi/deviceSDK/certs/certificate.pem.crt",
   caPath: "/home/pi/deviceSDK/certs/root-CA.crt",
 clientId: "PISORA",
     host: "xxx.iot.us-east-1.amazonaws.com"
})

function geolocationObject(piwifiResponse) {
    var wifiAccessPoints = []
    for (const network in piwifiResponse) {
        if (piwifiResponse.hasOwnProperty(network)) {
          const element = piwifiResponse[network]
          let wifiAccessPoint = {
              "macAddress":element.bssid,
              "signalStrength":element.signalLevel
          }
          wifiAccessPoints.push(wifiAccessPoint)
        }
    }
    let res = {
      "considerIp": "false",
      "wifiAccessPoints":wifiAccessPoints
    }
    return res
}

function scan(){
  piWifi.scan(function(err, networks) {
      if (err) {
        return console.error(err.message)
      }
      if (networks === undefined ){
        return console.error("networks undefined")
      }
      var res = geolocationObject(networks)
      console.log("found ssids :")
      console.dir(res)
      device.publish('pisora/ssids', JSON.stringify(res))
  })
}

device
  .on('connect', function() {
    console.log('connect')
    device.subscribe('pisora/update')
    scan()
    /**
     * 定期実行
     * 1分に1回実行
     */
    cron.schedule('*/1 * * * *', function(){
      scan()
    })
  })

device
  .on('message', function(topic, payload) {
    console.log('message', topic, payload.toString())
    scan()
  })

永続化 (Raspberry Pi)

前回設定したpm2の自動起動の設定を削除したあと、pm2を再始動します

pm2 delete all
pm2 start {スクリプトのファイルパス}
pm2 save
pm2 startup

Ambidataで確認

位置情報がAmbidata上にプロットされていることを確認します。
SSIDから位置情報を推測しているので、GPSの電波を受信できない、地下鉄でも位置情報をプロットできました。

スクリーンショット 2018-04-18 17.38.14.png

運用にかかった費用(参考値)

1時間ほど動かしてみたところ、以下の転送量がSoracomコンソール上で確認されました

種別 1時間あたり転送量(その1) 1時間あたり転送量(その2)
上り 52.3KiB (0.05107 MiB) 113.7KiB(0.11104 MiB)
下り 188.2KiB (0.18379 MiB) 69.5KiB(0.06787 MiB)

* s1.standard 上り0.24 円/MB 下り0.8 円/MB

(なぜ上り転送量が増えたのか疑問が残る結果になりました...)

スクリーンショット 2018-04-18 16.51.07.png

1日稼働後のAWSの請求ダッシュボード

スクリーンショット 2018-04-18 17.41.37.png

(しばらく放置したの情報を追記)

** 条件が変わっています
*前回と条件が変わっています
送信間隔 1分→10分

バッテリは5000mAhの以下のもの
https://www.amazon.co.jp/gp/product/B01DEURI48

開始 終了 稼働時間
21:15 翌06:50 9:35

スクリーンショット 2018-04-20 12.33.56.png

1時間あたり転送量
  • UP 37.2kb/h
  • DL 39.2kb/h
上記の設定で一ヶ月稼働した場合
  • UP27.028125Mib = 6.48円
  • DL28.48125Mib = 22.4円
  • 想定される月額料金29円