ソラコムTシャツ欲しいけど、これじゃ貰えないなーって思っている人です。
GPSマルチユニットSORACOM Edition 使ってみた(開封の儀)の続きです。
GPSマルチユニット SORACOM Edition購入して、約1ヶ月経ちました。
とりあえず行ったことは、SORACOM Laggonによる可視化、SORACOM Funk経由で、AWS LambdaでSlack通知の2つです。
Lagoonによる可視化
とりあえず、平日の10時から19時までの15分置きに加速度を除くデータを送信させてますが、12日間ぐらいは稼働するようです。
残量レベル3が一番長く、2、1は短いようです。
消費電力については、@1stshipさんのGPSマルチユニットSORACOM Edition消費電力の研究をご覧いただくといいと思います!
 
ちなみに、初めて、Lagoonを真面目wに触るので、こんなことをつぶやいてみたり。
SORACOM LagoonでGPSマルチユニットの気温と湿度を可視化するために、初めてまともなグラフを作ってみた。最小最大を適切にセットしないと、変動幅が大きくなって、見辛いグラフになることがわかったのが学び。 #soracom
— Kenichiro Wada (@Keni_W) February 25, 2020
SORACOM Funk経由でSlack通知
GPSマルチユニットからは、Funk経由で、AWS Lambdaでデータを送信できるので、
そこから、Slackにも通知させています。
base64デコードするもんだと思っていたので、とりあえず流してみたら、デコードされてeventに入ってきたので、ほんと
Funk神!って思いましたね。
GPSマルチユニットのデータをSORACOM Funk経由でLambdaに流したらbase64デコードされて出てきた。検証が1個減った。Funk素敵!#soracom
— Kenichiro Wada (@Keni_W) February 20, 2020
とりあえずソースはこんな感じ。
node.js v12のランタイムで動作確認してます。
大した内容じゃですが、どこかで、使い方含めて、githubで公開します。
'use strict'
const moment = require('moment-timezone');
const AWS = require('aws-sdk');
AWS.config.update({ region: 'ap-northeast-1' });
const kms = new AWS.KMS();
const request = require('request-promise');
const encryptedSlackWebHookUrl = process.env['SLACK_WEBHOOK_URL'];
let decryptedSlackWebHookUrl;
/**
 * 環境変数復号化
 * @param {*} decryptedEnvKey 
 */
async function decryptedEnv(decryptedEnvKey) {
  const data = await kms
    .decrypt({
      CiphertextBlob: new Buffer(process.env[decryptedEnvKey], 'base64'),
    })
    .promise();
  return String(data.Plaintext);
}
/**
 * データ整形
 * @param {*} event 
 */
async function formatData(event) {
  let typeStr; 
  if (event.type === 0) {
    typeStr = '自動'
  } else {
    typeStr = '手動'
  }
  return {
    locationLat : event.lat,
    locationLon : event.lon,
    batteryLevel: event.bat,
    signalLevel: event.rs,
    temperature: event.temp,
    humidity: event.humi,
    type: typeStr
  }
}
/**
 * Slack POST
 * @param  {[type]} data [description]
 * @return {[type]}       [description]
 */
async function postSlackMessage(data) {
 
  console.log('slack Call');
  let messageArray = [];
  messageArray.push(`${moment().tz("Asia/Tokyo").format('YYYY-MM-DD HH:mm:ss')}の測定値`);
  messageArray.push(`温度: ${data.temperature}`);
  messageArray.push(`湿度: ${data.humidity}`);
  messageArray.push(`バッテリーレベル: ${data.batteryLevel}`);
  messageArray.push(`電波レベル: ${data.signalLevel}`);
  messageArray.push(`${data.type}実行されました。`);
  // 位置情報付与
  if (data.locationLat !== null && data.locationLon !== null) {
    messageArray.push('GPSマルチユニット 現在位置: ');
    messageArray.push(`https://www.google.com/maps?q=${data.locationLat},${data.locationLon}`);
  }
  const message = messageArray.join('\n');
  // リクエスト設定
  const options = {
    url: decryptedSlackWebHookUrl,
    method: 'POST',
    headers: {
      'Content-type': 'application/json'
    },
    body: {
      "text": message
    },
    json: true
  };
  // メッセージ送信
  const res = await request(options)
  .then(function (body) {
    console.log('Slack Post Message Sucuessful! :', JSON.stringify(body, 2));
    if (body == 'ok') {
      return true;
    } else {
      return false;
    }
  })
  .catch(function (err) {
    console.log('Slack Post Error: ' + err);
    return false
  });
  console.log(res);
  return res;
};
module.exports.soracom =  async(event, context)  => {
  console.log(JSON.stringify(event, 2));
  console.log(JSON.stringify(context, 2));
  decryptedSlackWebHookUrl = await decryptedEnv('SLACK_WEBHOOK_URL');
  const data = await formatData(event);
  const isPostSlack = await postSlackMessage(data);
  if (isPostSlack) {
    return {
      statusCode: 200,
      body: JSON.stringify(
        {
          message: 'Slack Post Message Successful!',
          input: data,
        },
        null,
        2
      ),
    };
  } else {
    return {
      statusCode: 500,
      body: JSON.stringify(
        {
          message: 'Slack Post Message Failed!',
          input: data,
        },
        null,
        2
      ),
    };
  }
};
最近、Serverless Frameworkでデプロイするようにしているので、設定であるserverless.ymlはこんな感じにしてます。
service: soracom-gps-multiUnit-receiver
provider:
  name: aws
  runtime: nodejs12.x
# you can overwrite defaults here
  stage: dev
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: Allow
      Action:
        - KMS:Decrypt
      Resource: ${self:custom.kmsSecrets.keyArn}
plugins:
  - serverless-kms-secrets
custom:
  kmsSecrets:
    file: ${file(kms-secrets.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.yml)}
    keyArn: arn:aws:kms:ap-northeast-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
functions:
  soracom:
    handler: handler.soracom
    memorySize: 256
    timeout: 25
    environment:
      SLACK_WEBHOOK_URL: ${self:custom.kmsSecrets.file.secrets.SLACK_WEBHOOK_URL}
Serverless.yml内で呼んでるKMSで暗号化したSlackのWebhook URLを格納してる設定ファイルは、このような構成です。流石にURLは抜いてます。
secrets:
   SLACK_WEBHOOK_URL: (暗号化された文字列)
keyArn: 'arn:aws:kms:ap-northeast-1:123456789012:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
次やること
本当は、2台同じのを用意するのがいいんでしょうけど、とりあえずはないので、Grove IoT スターターキット for SORACOM(Wio LTE JP Version)付属(or別途購入)の温湿度センサーを使って、オフィスの2箇所の温度と湿度を可視化したいと思います。
あと、バッテリーを通知する何某かを作ろうかと(こちらはもっか実装中)

