Open10
obnizとLINE Botを組み合わせて、ビールの飲み頃温度を教えてくれるIoTに挑戦中のメモ
AMG8833使用 赤外線アレイセンサ(Grid-EYE)モジュールが未だ届かず、まずは手元にある温度センサーとLINE Botの組み合わせを確認するところから始める
【復習】 環境と整える
npm管理ができるように初期化
- npm init -y
SDKのインストール
- npm i @line/bot-sdk
- npm i @line/bot-sdk express
expressのインストール
- npm i express
ターミナルをもう1つ用意する、ngrokのインストール
- npm i -g ngrok
obnizパッケージのインストール
- npm i obniz
復習
【LINE Bot】 バイクで走るタイムリミットコード
'use strict';
// ########################################
// 初期設定など
// ########################################
// パッケージを使用します
const express = require('express');
const line = require('@line/bot-sdk');
const axios = require('axios');
// ローカル(自分のPC)でサーバーを公開するときのポート番号です
const PORT = process.env.PORT || 3000;
// Messaging APIで利用するクレデンシャル(秘匿情報)です。
const config = {
channelSecret: 'チャネルシークレット',
channelAccessToken: 'チャネルアクセストークン'
};
// ########## ▼▼▼ サンプル関数 ▼▼▼ ##########
const sampleFunction = async (event) => {
// ユーザーメッセージが「日の出」か「日の入り」かどうか
if (event.message.text !== '今日のタイムリミットは?') {
return client.replyMessage(event.replyToken, {
type: 'text',
text: '「今日のタイムリミットは?」と話しかけてね'
});
} else {
// 「リプライ」を使って先に返事しておきます
await client.replyMessage(event.replyToken, {
type: 'text',
text: 'ちょいとお待ちを…'
});
let pushText = '';
try {
// axiosで日の出日の入り時刻のAPIを叩きます(少し時間がかかる・ブロッキングする)
const res = await axios.get('https://api.sunrise-sunset.org/json?lat=35.7772463&lng=138.9766782');
// 取得できるのはUTCなので日本時間(+9時間)になおす
const utc_time = res.data.results.sunrise;
// '時', '分', '秒 PM' に分割する
const tm_split = utc_time.split(':');
// '時' を9時間進めて12時間戻す(13時を過ぎないようにする)
const jp_hour = Number(tm_split[0]) + 9 - 12;
// '秒 PM' を '秒' だけにする
const sec = tm_split[2].split(' ')[0];
// 再構成する
const time_string = `${jp_hour}時${tm_split[1]}分${sec}秒`;
pushText = `今日のタイムリミットは${time_string}です!渋滞前に帰りましょう!`;
} catch (error) {
pushText = '検索中にエラーが発生しました。ごめんね。';
// APIからエラーが返ってきたらターミナルに表示する
console.error(error);
}
// 「プッシュ」で後からユーザーに通知します
return client.pushMessage(event.source.userId, {
type: 'text',
text: pushText,
});
}
};
// ########## ▲▲▲ サンプル関数 ▲▲▲ ##########
// ########################################
// LINEサーバーからのWebhookデータを処理する部分
// ########################################
// LINE SDKを初期化します
const client = new line.Client(config);
// LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます
async function handleEvent(event) {
// 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// サンプル関数を実行します
return sampleFunction(event);
}
// ########################################
// Expressによるサーバー部分
// ########################################
// expressを初期化します
const app = express();
// HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします
app.post('/webhook', line.middleware(config), (req, res) => {
// 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行
if (req.body.events.length === 0) {
res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します(なくてもよい)
console.log('検証イベントを受信しました!'); // ターミナルに表示します
return; // これより下は実行されません
} else {
// 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します
console.log('受信しました:', req.body.events);
}
// あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、
// 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します
Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result));
});
// 最初に決めたポート番号でサーバーをPC内だけに公開します
// (環境によってはローカルネットワーク内にも公開されます)
app.listen(PORT);
console.log(`ポート${PORT}番でExpressサーバーを実行中です…`);
復習
【obniz】 ビールの飲み頃温度 4℃以上になったらLEDが光る
const Obniz = require('obniz');
const obniz = new Obniz('0000-0000'); // Obniz_IDに自分のIDを入れます
obniz.onconnect = async function () {
var led = obniz.wired("LED", {anode:10, cathode:11});
led.output(true);
const tempsens = obniz.wired('LM60', { gnd: 0, output: 1, vcc: 2 });
// setIntervalで間隔を作る
setInterval(async function () {
// 同期で取得
const temp = await tempsens.getWait();
// 温度をコンソールに表示
console.log(temp);
// displayに反映
obniz.display.clear();
obniz.display.print(temp + 'C'); // 英語が出力できる
}, 1000); // 1000ミリ秒 = 1秒
for (let i = 0; i < 100; i++) {
tempsens.onchange = (function(temp){
console.log(temp);
if (temp > 4) {
led.on();
} else {
led.off();
}
});
await obniz.wait(100);
}
}
全力の参考:LINEBotに尋ねたら温度センサーで室温を計ってみた
サンプルコード
const Obniz = require('obniz');
const obniz = new Obniz('obnizのID'); // Obniz_IDに自分のIDを入れてください
// obnizと接続確立したとき
obniz.onconnect = async () => {
obniz.display.clear();
obniz.display.print('obniz Ready');
}
// 温度センサから値を取得して返す
const getObnizTemp = async () => {
// 温度センサの利用
const tempsens = obniz.wired('LM60', { gnd: 0, output: 1, vcc: 2 });
// RGB LEDを利用
const rgbled = obniz.wired('WS2811', { gnd: 9, vcc: 10, din: 11 });
// 非同期で取得
const temp = await tempsens.getWait();
if (temp>25) {
// オレンジ
rgbled.rgb(255, 165, 0);
} else {
// 水色
rgbled.rgb(0, 191, 250);
}
// ターミナル表示
console.log('obniz temp:', temp);
// obnizディスプレイ表示
obniz.display.clear();
obniz.display.print(temp + ' C');
// 温度値を返す
return temp;
}
// ########################################
// LINEBot イベント処理部分
// channelSecret:LINE Developers → チャネル基本設定 → チャネルシークレット
// channelAccessToken:LINE Developers → Messaging API設定 → チャネルアクセストークン(長期)
// ターミナルで `ngrok http 3000` 実行後、発行されたURLをWebhook URLとして設定するのを忘れずに
// 「検証」ボタンをクリックするとターミナルにエラーが出ますがここでは問題ありません(検証イベントのハンドリングをしていないため)
// ########################################
const config = {
channelSecret: '作成したBotのチャネルシークレット',
channelAccessToken: '作成したBotのチャネルアクセストークン'
};
const line = require('@line/bot-sdk');
const client = new line.Client(config);
// ExpressからMessaging APIイベントを渡されて処理するところ
const handleEvent = async (event) => {
// テキストメッセージ以外を受信したときは何も行わずresolveを返す
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// テキストメッセージを受信したとき
if (event.message.text === '温度教えて') {
// 待ってねというメッセージを「リプライ」で先に返す
client.replyMessage(event.replyToken, {
type: 'text',
text: '少々お待ちください!'
});
// obnizの温度センサから値をとってくる(ブロッキング・時間のかかる処理で一旦ここで止まる)
const temp = await getObnizTemp();
// tempが取得できたらそれを含めたメッセージを「プッシュ」で送信する
client.pushMessage(event.source.userId, {
type: 'text',
text: '今の温度は' + temp + '度!',
});
} else {
// メッセージの中身が「温度教えて」以外だったとき
client.replyMessage(event.replyToken, {
type: 'text',
text: '「温度教えて」と話しかけてね!'
});
}
// resolveを返す
return Promise.resolve(null);
}
// ########################################
// Expressサーバー部分
// ########################################
const express = require('express');
const PORT = process.env.PORT || 3000;
const app = express();
// 「(サーバーURL)/webhook」にアクセス(LINEサーバーからのWebhook)があったとき
app.post('/webhook', line.middleware(config), (req, res) => {
// 受信したイベントをターミナルに表示
console.log(req.body.events);
// イベントをhandleEventに渡して1つずつ処理
Promise.all(
req.body.events.map(handleEvent)
).then(
result => res.json(result)
);
});
// PORT番号のポートでサーバーを開始
app.listen(PORT);
console.log('express runnning: PORT =', PORT);
あると便利!
RGBカラーチャート
有料になった?fritzing
この前失敗したので、今回は間違わず埋め込む
Qiitaにyoutube動画を埋め込む方法
カッコの位置要注意、どこからどこまでの範囲か
const Obniz = require('obniz');
const obniz = new Obniz('0000-0000'); // Obniz_IDに自分のIDを入れてください
// obnizと接続確立したとき
obniz.onconnect = async () => {
obniz.display.clear();
obniz.display.print('obniz Ready');
}
// 温度センサから値を取得して返す
const getObnizTemp = async () => {
// 温度センサの利用
const tempsens = obniz.wired('LM60', { gnd: 0, output: 1, vcc: 2 });
// RGB LEDを利用
const rgbled = obniz.wired('WS2811', { gnd: 9, vcc: 10, din: 11 });
// 非同期で取得
const temp = await tempsens.getWait();
if (temp > 4) {
// ブルー
rgbled.rgb(0, 51, 255);
} else {
// ブラック
rgbled.rgb(0, 0, 0);
}
// ターミナル表示
console.log('obniz temp:', temp);
// obnizディスプレイ表示
obniz.display.clear();
obniz.display.print(temp + ' C');
// 温度値を返す
return temp;
}
// ########################################
// LINEBot イベント処理部分
// channelSecret:LINE Developers → チャネル基本設定 → チャネルシークレット
// channelAccessToken:LINE Developers → Messaging API設定 → チャネルアクセストークン(長期)
// ターミナルで `ngrok http 3000` 実行後、発行されたURLをWebhook URLとして設定するのを忘れずに
// 「検証」ボタンをクリックするとターミナルにエラーが出ますがここでは問題ありません(検証イベントのハンドリングをしていないため)
// ########################################
const config = {
channelSecret: '作成したBOTのチャネルシークレット',
channelAccessToken: '作成したBOTのチャネルアクセストークン'
};
const line = require('@line/bot-sdk');
const client = new line.Client(config);
// ExpressからMessaging APIイベントを渡されて処理するところ
const handleEvent = async (event) => {
// テキストメッセージ以外を受信したときは何も行わずresolveを返す
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
// テキストメッセージを受信したとき
if (event.message.text === 'ビールの温度を教えて!') {
// 測定中というメッセージを「リプライ」で先に返す
client.replyMessage(event.replyToken, {
type: 'text',
text: '測定中、、、'
});
// obnizの温度センサから値をとってくる(ブロッキング・時間のかかる処理で一旦ここで止まる)
const temp = await getObnizTemp();
// tempが取得できたらそれを含めたメッセージを「プッシュ」で送信する
client.pushMessage(event.source.userId, {
type: 'text',
text: 'ビールの温度は' + temp + '度です!',
});
} else {
// メッセージの中身が「温度教えて」以外だったとき
client.replyMessage(event.replyToken, {
type: 'text',
text: 'ビール画像をタップしてね!'
});
}
// resolveを返す
return Promise.resolve(null);
}
// ########################################
// Expressサーバー部分
// ########################################
const express = require('express');
const PORT = process.env.PORT || 3000;
const app = express();
// 「(サーバーURL)/webhook」にアクセス(LINEサーバーからのWebhook)があったとき
app.post('/webhook', line.middleware(config), (req, res) => {
// 受信したイベントをターミナルに表示
console.log(req.body.events);
// イベントをhandleEventに渡して1つずつ処理
Promise.all(
req.body.events.map(handleEvent)
).then(
result => res.json(result)
);
});
// PORT番号のポートでサーバーを開始
app.listen(PORT);
console.log('express runnning: PORT =', PORT);