🍀

LINEで確認:ラズパイに繋いだセンサーで温度を取得してみた

2022/09/16に公開約8,400字

概要

前回のブログにてRaspberry Piのセットアップが完了したので、今回から本格的にIoT開発に取り組んでいきます。

メンバーの水無瀬・杉本でどんなIoT開発をしようか?と相談し、今回はIoTセンサー開発ノウハウと、LINEアプリの開発ノウハウが蓄積できることを目的に、簡単なシステムを構築してみようという事になりました。

その結果、Raspberry Piに温度センサーを繋いで現在の気温を取得し、LINEから気温を確認できる仕組みを構築しました!

Raspberry Piへの温度センサーの接続

まずRaspberry Piと温度センサーを接続します。
センサーは「COODENKEY Raspberry Pi用センサー 電子部品キット」にある温度センサーを使用しました。

センサーとRaspberry Piをブレッドボード経由で接続します。
まずRaspberry PiのGPIO端子にジャンパーピン(オスメス)経由でブレッドボードを接続し、ブレッドボードに温度センサーを差し込みます。
接続後の回路図はコチラ。

GPIO端子の 1-Wire機能を有効化

温度の取得のため、 GPIO端子の 1-Wire機能の有効化を行います。

次のコマンドでconfigファイルを編集します。
sudo vim /boot/config.txt

configファイル末尾に下記の文章を追記します。
dtoverlay=w1-gpio

ファイルを保存したら再起動。
sudo reboot

再起動できたら、下記のコマンドを実行し、「1-Wire」のモジュールがあることを確認します。
lsmod

もし無ければ、下記のコマンドを実行して、1-Wireを有効化します。

sudo modprobe w1-gpio
sudo modprobe w1-therm

w1_slaveファイルがあるディレクトリに移動。
※このw1_slaveがあるパスは後で使用するので控えておきます
cd /sys/bus/w1/devices/28-xxxxxxxxxxxx
※このディレクトリ名は環境によって異なるので注意

下記のコマンドを実行し、現在の気温が取得できます。

cat w1_slave
c4 01 55 05 7f a5 81 66 46 : crc=46 YES
c4 01 55 05 7f a5 81 66 46 t=28250

LINE Messaging APIの設定

下記サイトでアカウント登録を行いLINEのビジネスIDを取得します。
LINE ビジネスID作成

LINE Developersコンソールにログインします。
LINE Developersコンソールログイン

まず初めにプロバイダーを作成します。

※今回はプロバイダー名を「kdl-iot-blog」としました。
※プロバイダー名に「LINE」という文字は含めることができないので注意

次に新規チャンネルを作成するので作成ボタンを押下し、Messaging APIを選択します。

下図を参考に必要な項目を入力し、作成ボタンを押下します。

チャネル名:温度
チャネル説明:部屋の温度を確認できる
会社・事業者の所在国・地域:日本
メールアドレス:自身のメールアドレス
大業種:個人
小業種:個人(学生)
その他の設定は未設定のまま
※チャネルアイコンはこの画面から設定できます。

確認ダイアログが表示されるので、OKボタンを押下。

チャネル設定から先程作成したチャネルを開きチャネル基本設定のタブを開きます。

チャネルシークレットの項目を確認し、後ほど使用するため値を控えておきます。

次にMessaging API設定のタブを開きます。

QRコードから自身のLINEアプリにLINEアカウントを友達登録をしておきます。

チャネルアクセストークンの項目から発行ボタンを押下し、後ほど利用するので値を控えておきます。

次に応答設定を行います。

LINE公式アカウント機能の項目の応答メッセージの項目の編集ボタンを押下。

応答設定を以下のように設定します。
応答モード:Bot
あいさつメッセージ:オフ
応答メッセージ:オフ
Webhook:オン

LINEに温度を返すスクリプトの準備

スクリプトを格納するディレクトリを作成します。
mkdir iot-blog-temperature
※今回は「iot-blog-temperature」というディレクトリ名としました。

次のコマンドを実行し開発環境を初期化します。
npm init

次のコマンドで必要なモジュールをインストールします。
npm install @line/bot-sdk dotenv express fs

node.jsで温度を返すスクリプトを作成します。
vim index.js

reply_temperature.js
require('dotenv').config();
const line = require('@line/bot-sdk');
const express = require('express');
const fs = require('fs');

const w1SlavePath = process.env.W1_SLAVE_PATH;

// 温度を返すキーワード
const keyword = '温度確認';

// LINE Botの設定
const config = {
  channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.CHANNEL_SECRET,
};
const client = new line.Client(config);

// expressの設定
const app = new express();
const port = 3000;

// LINE Bot webhookコールバック【POSTのみ】
app.post('/webhook', line.middleware(config), (req, res) => {
  console.log('LINE Botのウェブフック・コールバック・ハンドル関数呼びだし');
  if (req.body.destination) {
    console.log('送信先User ID: ' + req.body.destination);
  }
  // req.body.eventsにはイベントの配列を指定
  if (!Array.isArray(req.body.events)) {
    return res.status(500).end();
  }
  // 各イベントを処理する
  Promise.all(req.body.events.map(handleEvent))
    .then(() => res.end())
    .catch((err) => {
      console.error(err);
      res.status(500).end();
    });
});

// 単一のイベントを処理するためのコールバック関数
const handleEvent = (event) => {
  if (event.replyToken && event.replyToken.match(/^(.)\1*$/)) {
    return console.log('テスト用フックを受け取りました: ' + JSON.stringify(event.message));
  }
  if (event.type === 'message') {
    const message = event.message;
    if (message.type === 'text') {
      return handleText(message, event.replyToken, event.source);
    } else {
      throw new Error(`Unknown message: ${JSON.stringify(message)}`);
    }
  } else {
    throw new Error(`Unknown event: ${JSON.stringify(event)}`);
  }
};

const handleText = (message, replyToken, event_source) => {
  console.log('handleText関数の呼び出し');
  console.log(message.text);
  if (message.text === keyword) {
    // w1_slaveファイルから温度を読み取る
    const w1Slave = fs.readFileSync(w1SlavePath, 'utf8');
    const matches = w1Slave.match(/t=(\d+)/);
    const celsius = parseInt(matches[1]) / 1000;
    return replyText(replyToken, `${celsius}`);
  }
};

// メッセージの返信
const replyText = (token, texts) => {
  texts = Array.isArray(texts) ? texts : [texts];
  return client.replyMessage(
    token,
    texts.map((text) => ({ type: 'text', text }))
  );
};

// express serverを実行する
app.listen(port, () => {
  console.log(`Server running on ${port}`);
});

expressで3000ポートでサーバーを待ちの状態にします。
LINEアカウントへメッセージが送信されると、Webhookに設定したURLにPOSTリクエストが送信されます。
/webhookのリクエストを受けて、特定のキーワード(温度確認)を受けとった際に、
w1_slaveファイルから温度の情報を読み取り、LINEbot SDKのreplyMessage関数で、温度情報をLINEアカウントに返します。

次に環境変数を設定するための.envファイルを作成します。
vim .env

CHANNEL_ACCESS_TOKEN=チャネルアクセストークン
CHANNEL_SECRET=チャネルシークレット
W1_SLAVE_PATH=w1_slaveのファイルのパス

※これまでの手順で控えておいた各値を設定

作成したスクリプトを実行します。
node reply_temperature.js

ngrokのインストール

今回は簡単にWEBサーバとなる環境を準備するために、
ローカルサーバを外部公開できるngrokというツールを利用します。
ngrok.com

次のコマンドでzipファイルを取得。
wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-arm.zip

次のコマンドでzipファイルを解凍。
unzip ngrok-stable-linux-arm.zip

次のコマンドで解凍したファイルを/usr/local/bin/配下に移動させます。
sudo mv ngrok /usr/local/bin/

次のコマンドを実行しバージョン情報が確認できればインストール成功。

ngrok version
ngrok version 2.3.40

次のコマンドでポート3000をWEBサーバとして公開します。
ngrok http 3000

この後の設定に必要なため、ForwardingのhttpsのURLを控えておきます。

LINE Messaging APIのWebhookの設定

LINE Developersコンソールにログインし、Messaging API設定のタブを開きます。

Webhook設定の項目のWebhook URLの項目に下記のURLを入力します。
ngrokのForwardingのURL/webhook

また、Webhookの利用をONにしておきます。

リッチメニューの設定

この時点で、友達登録したLINEアカウントに「温度確認」のメッセージを送ると気温が返ってくるが、ボタン1つで温度確認できるようにしたいので、LINEのリッチメニューの機能を使いボタンを押すと「温度確認」のメッセージが送信されるようにします。

下記のURLからLINE Official Account Manegerにログインします。
LINE Official Account Maneger

アカウントリストから先に作成したLINEアカウントを選択します。

ホームタブの左サイドメニューから「リッチメニュー」を開き、作成ボタンを押下します。

表示設定に必要な情報を設定します。
タイトル:現在の温度
表示期間:2022/06/08 00:00 - 2030/09/30 23:59
メニューバーのテキスト:メニュー
メニューのデフォルト表示:表示する

次にコンテンツの設定を行います。
今回は温度確認のボタンのみ必要なので、テンプレートの選択ボタンを押下し、小の枠組みから1枠のテンプレートを選択し選択ボタンを押下します。

次にリッチメニュー上のボタンのデザインの設定を行います。
今回は画像をアップロードせず、設定画面上から直接デザインを作成するので、画像の作成ボタンを押下します。
メニューにあるツールを使って背景色や、文字色、ボタンに表示する文字を設定し、適用をボタンを押下します。
別途確認ダイアログがでるので、もう一度適用ボタンを押下します。

次にボタンを押下した時のアクションを設定します。
今回はボタンを押下した際に「温度確認」というメッセージを送信したいので、アクションの項目のタイプを「テキスト」に設定します。
次にテキストを入力する項目に「温度確認」と入力します。

全ての設定が完了したら、下部にある保存ボタンを押下します。

実際に温度を確認してみる

友達登録をしたLINEアカウントを開くと先程設定したリッチメニューが表示されるので、温度確認のボタンを押してみます。

すると温度確認というメッセージが発信されて、その後しばらくすると温度が返ってくることを確認できました!

ngrokで取得した公開用URLはngrokのプロセスが停止してしまうと、次回起動時に別のURLに変わってしまい、webhookの設定もやり直しになるのでご注意ください。

以上でRaspberry piで取得した温度をLINEアカウントから確認する仕組みを構築できました。

LINEbot SDKとngrokを利用することで、短時間でこの仕組みを構築できることが実感できたと思います。
単純に温度を通知するだけの仕組みであればLINE Notifyを使ったほうが簡単に実装できますが、次回は作成したLINEアカウントを利用して、もう少し応用的な機能を構築してみようと思います。

Discussion

ログインするとコメントできます