技術的な話

【体重自動記録ツール】体重計のBLE情報を取得してみる #2

前回はこちら

今回の目標

  • 体重計から受信した体重情報をGoogle スプレッドシートに送信する。
  • 送信された体重情報からグラフ表示させる。

Google Apps Scriptとは

Googleが提供するローコードプラットフォームです。他のGoogleアプリとの連携が容易です。

ノーコードじゃなくてローコードなのでプログラム言語(HTML、CSS、Javascript)を使用して独自のシステムを構築することも可能です。

Gmailアカウントがあれば無料で使用可能です。

プログラムでHTTPリクエストも送信出来るので、Google以外のアプリケーションとも連携が可能です。例えば、Slack等のチャットアプリへ通知を送ることが可能です。

Googleスプレッドシートを作成する

事前準備

こちらからスプレッドシートを作成します。

https://www.google.com/intl/ja_jp/sheets/about/

データ書き込み用のシートを準備

スプレッドシートが開いたら、A列を日付、B列を体重記録用とします。
この辺はお好みで設定してください。
シート名はsourceとしています。

データ書き込みAPIサーバを作成

Google Apps Scriptを活用すると簡易なAPIサーバを構築可能です。
スプレッドシート上部のツールからスクリプトエディタを選択してください。
すると以下のようにエディタ画面が開きます。

最終的にはこのコードをWebアプリケーションとしてデプロイするのですが、スクリプト内にdoGet 、doPostというメソッドを定義すると、生成されたURLにGETでアクセスするとdoGetが動作、POSTでアクセスするとdoPostが動作するようになります。

制限としてはdoGet、doPostはそれぞれ1つずつしか定義できません。シンプルなAPIであればこれで十分ですが。

今回は下記機能を実装します。

メソッド名機能
doGetスプレッドシート内に書き込まれた値を返す。
doPost送信された値をスプレッドシートの末尾に書き込む。
date:日付(YYYY-mm-dd HH:MM:SS形式)
weight:体重(単位:kg)

Javascriptを書いたことある人であれば抵抗なく入っていけると思います。
doGetではスプレッドシートを取得してsourceという名前のシートを検索してあれば、A列、B列の値を取得して返すといった処理を行っています。

シートが存在しない場合はエラーを返すようにしています。他細かいチェックやエラー処理はしておりません。悪しからず。

function doGet(e){
  // output
  const output = ContentService.createTextOutput();

  // get spreadsheet
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  // get data sheet
  let sourcesheet = null;
  for(let sheet of spreadsheet.getSheets()) {
    if(sheet.getName() == 'source') {
      sourcesheet = SpreadsheetApp.setActiveSheet(sheet)
    }
  }
  // sheet exists check
  if(sourcesheet == null) {
    return 'error occured. not found source sheet.'
  }
  // found data
  const dates = sourcesheet.getRange(2, 1, sourcesheet.getLastRow()).getValues();
  const weights = sourcesheet.getRange(2, 2, sourcesheet.getLastRow()).getValues();
  output.append(dates);
  output.append(weights);
  return output;  
}

doPostではリクエストされた値(date、weight)を取得して、sourceシートに書き込みます。
書き込みに際してA列を検索して最終行を判定して、最終行+1にリクエストされた値を書き込むようにしています。

レスポンスは成功、失敗メッセージをそれぞれ返すようにしています。

function doPost(e){
  // output
  const output = ContentService.createTextOutput();
  
  const date = e.parameter.date;
  const weight = e.parameter.weight;

  // get spreadsheet
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  // get data sheet
  let sourcesheet = null;
  for(let sheet of spreadsheet.getSheets()) {
    if(sheet.getName() == 'source') {
      sourcesheet = SpreadsheetApp.setActiveSheet(sheet)
    }
  }
  // sheet exists check.
  if(sourcesheet == null) {
    return output.append('error occured. not found source sheet.')
  }

  const values = sourcesheet.getRange('A:A').getValues();
  const lastRow = values.filter(String).length;

  sourcesheet.getRange(lastRow + 1, 1).setValue(date);
  sourcesheet.getRange(lastRow + 1, 2).setValue(weight);
 
  return output.append('write data success.');  
}

Webアプリケーションとしてデプロイする

スクリプトエディタ画面の右上にあるデプロイから新しいデプロイを選択します。

下記要領でデプロイします。

  1. 種類の選択からウェブアプリを選択します。
  2. 次のユーザとして実行:自分
  3. アクセス出来るユーザ:全員
  4. デプロイを選択します。

デプロイが完了すると以下画面が表示されます。URLをコピーします。

動作確認

リクエストを送るツールは何でも良いのですが、Postmanを使用しました。
GETのみの動作確認であればブラウザにURLを入力すれば可能です。

doGetの動作確認

形式はちょっとあれですが、とりあえず値は取れました。

doPostの動作確認

日付(date)には2021-09-20 10:00:00、体重(weight)には80.1を設定してリクエストを送ります。リクエスト結果に成功メッセージが返ってきたらスプレッドシートを確認します。

スプレッドシートを確認すると送信した値が書き込まれています。
これでAPI経由でスプレッドシートに体重を書き込めるようになりました。

グラフの設定

別シートにグラフを設定しておきます。
横軸にA列(date)、縦軸にB列(weight)を設定します。
この辺もお好みのグラフを作成してください。

体重情報をHTTPリクエストで送信する

前回の記事で作成した体重計とBluetooth接続するプログラムを少し修正します。

体重情報を受信したら先程作成したGoogle Apps ScriptのURLにアクセスするようにします。

<your-request-url>にはGoogle Apps Scriptで発行されたURLを入力します。

    def _weight_measurement_notification_handler(self, sender, data:bytearray):
        """Weight measurement notification handler."""
        weight:float = (data[1] + data[2] * 256) * 0.005
        self._logger.info(f'weight measurement notification handler: {data.hex()} / {weight} kg')

        send_date:str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        response = requests.post(
            '<your-request-url>',
            {'weight': weight, 'date': send_date})

全体の動作確認

体重を計測するとスプレッドシートに自動的に値が書き込まれます。
体重計に乗って測っているので時間が掛かるのはご愛嬌。
椅子に座って足だけ体重計に乗せているので20kg前後になっています。

まとめ

今回はRapsberryPi上に体重計のBluetoothに接続して体重情報を取得し、それをGoogle Apps Script経由で送信し、Googleスプレッドシートに書き込むところまでを行いました。

現時点で概ね完成ですが、まだグラフ表示を改良したいなぁとか色々思うところがあるので改良したらその辺も書いていくと思います。

次回はRaspberryPi上に配置したPythonスクリプトの管理をsystemdにするのと、cronで起動時間を設定しようと思います。

-技術的な話
-, , , , , , , ,