20211031のNode.jsに関する記事は4件です。

CHIRIMENをNode.jsで使用してみる⑶      ー I2C編 part1 ー

はじめに 本記事では、複数回に分けてCHIRIMENコミュニティが提供しているnpmパッケージnode-web-gpioとnode-web-i2cを使用してNode.jsからGPIOとI2Cを制御するために私が実施した方法とそのサンプルコードを記載した備忘録になっています。 今回はCHIRIMENのExamplesにあるI2C ExamplesのコードをNode.jsから実行可能にする方法について説明していきます。なお、I2C編は全4回になる予定で、今回は湿温度センサー”SHT-30”と温度センサー”ADT-7410”をCHIRIMENから使用する方法について説明します。 コードの主な違い Webブラウザ版とNode.js 版でのコードの主な違いについて説明します。 navigator()関数がNode.jsでは使用不可、記述する必要がないため削除する。 sleep()関数がNode.js には存在しないため、使用する場合は適宜実装する必要がある。 その他、HTML下では動作するがNode.js下では動作しない記法を変更する必要がある。 node-web-i2cを使う上での注意点 node-web-i2cを用いる場合、使用するI2Cパーツごとパッケージをインストールする必要があります。CHIRIMENをNode.jsで使用してみる⑴ ー 導入編 ーで作成したnode-web-i2c をインストールしたのと同じディレクトリで以下のようにパッケージのインストールを行ってください。また、パッケージ一覧はこちらのURLを参照してください。 xxxxはパッケージ名 % npm i @chirimen/xxxx I2C-SHT30 CHIRIMENからI2C-SHT30を使用して温度と湿度の値を出力する方法について説明します。 使用パーツ SHT30ブレークアウトボード x 1 ジャンパー線(メス・メス) x 4 配線 以下の図のように配線してください。 パッケージのインストール 以下のようにSHT-30のパッケージをインストールしてください。 % npm i @chirimen/sht30 Webブラウザ版のJavaScript Webブラウザ版では、ループ処理によってSHT30から得た温度と湿度を動的に出力しています。 main(); async function main() { const temperatureDisplay = document.getElementById("temperatureDisplay"); const humidityDisplay = document.getElementById("humidityDisplay"); const i2cAccess = await navigator.requestI2CAccess(); const port = i2cAccess.ports.get(1); const sht30 = new SHT30(port, 0x44); await sht30.init(); while (true) { const { humidity, temperature } = await sht30.readData(); temperatureDisplay.innerHTML = `${temperature.toFixed(2)} ℃`; humidityDisplay.innerHTML = `${humidity.toFixed(2)} %`; await sleep(500); } } Node.js版のJavaScript "i2c-sht30.js"というファイル名で下記のコードを保存してください。 このNode.jsでは、コードを実行した時点での温度と湿度を出力する形で実装しています。 // node-web-i2cを呼び出すおまじない const { requestI2CAccess } = require("node-web-i2c"); // SHT30のパッケージを呼び出す const SHT30 = require("@chirimen/sht30"); async function main() { const i2cAccess = await requestI2CAccess(); const i2c1 = i2cAccess.ports.get(1); // SHT30の接続されているポートの指定 const sht30 = new SHT30(i2c1, 0x44); await sht30.init(); const { humidity, temperature } = await sht30.readData(); console.log(`Temperature: ${temperature} ℃`); console.log(`Humidity: ${humidity} ℃`); } main(); 実行してみよう 下記のようにコマンドラインから実行し、温度と湿度が出力されれば成功です。 % node i2c-sht30.js Temperature: 24.433890287632565 ℃ Humidity: 53.6568245975433 ℃ I2C-ADT7410 CHIRIMENからADT7410を使用して、温度の値を出力する方法について説明します。 このセンサーは4本のピンヘッダ経由で接続します。あらかじめピンヘッダをハンダ付けしておいてください。 使用パーツ ADT7410使用高精度・高分解能I2C・16Bit温度センサモジュール )x 1 ジャンパー線(メス・メス) x 4 配線 以下の図のように配線してください。 また、センサーを接続する際に左右を間違えると高温になり火傷等をする恐れがあるため注意してください。 パッケージのインストール 以下のようにADT-7410のパッケージをインストールしてください。 % npm i @chirimen/adt7410 Webブラウザ版のJavaScript Webブラウザ版では、ループ処理によってADT7410から得た温度を動的に出力しています。 main(); async function main() { var head = document.getElementById("head"); var i2cAccess = await navigator.requestI2CAccess(); // i2cAccessを非同期で取得 var port = i2cAccess.ports.get(1); // I2C I/Fの1番ポートを取得 var adt7410 = new ADT7410(port, 0x48); // 取得したポートの0x48アドレスをADT7410ドライバで受信する await adt7410.init(); for (;;) { // 無限ループ var value = await adt7410.read(); head.innerHTML = value ? `${value} degree` : "Measurement failure"; await sleep(1000); } } Node.js版のJavaScript "i2c-adt7410.js"というファイル名で下記のコードを保存してください。 このNode.jsでは、コードを実行した時点での温度を出力する形で実装しています。 // ADT7410で温度を表示でさせるチュートリアル const { requestI2CAccess } = require("node-web-i2c"); // ADT7410のパッケージを呼び出す const ADT7410 = require("@chirimen/adt7410"); async function main() { const i2cAccess = await requestI2CAccess(); const i2c1 = i2cAccess.ports.get(1); // ADT7410の接続されているポートの指定 const adt7410 = new ADT7410(i2c1, 0x48); await adt7410.init(); const temperature = await adt7410.read(); console.log(`Temperature: ${temperature} ℃`); } main(); ​実行してみよう 下記のようにコマンドラインから実行し、温度が出力されれば成功です。 % node i2c-adt7410.js Temperature: 29.6875 ℃ さいごに 今回は以上になります。今回はnode-web-i2cでI2Cの使用方法の概要と湿温度センサー”SHT-30”と温度センサー”ADT-7410”のコードについて説明しました。次回も引き続きnode-web-i2cで使用可能なI2Cパーツの使用方法についての記事になる予定です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CHIRIMENをNode.jsで使用してみる⑶ ー I2C編 part1 ー

はじめに 本記事では、複数回に分けてCHIRIMENコミュニティが提供しているnpmパッケージnode-web-gpioとnode-web-i2cを使用してNode.jsからGPIOとI2Cを制御するために私が実施した方法とそのサンプルコードを記載した備忘録になっています。 今回はCHIRIMENのExamplesにあるI2C ExamplesのコードをNode.jsから実行可能にする方法について説明していきます。なお、I2C編は全4回になる予定で、今回は湿温度センサー”SHT-30”と温度センサー”ADT-7410”をCHIRIMENから使用する方法について説明します。 コードの主な違い Webブラウザ版とNode.js 版でのコードの主な違いについて説明します。 navigator()関数がNode.jsでは使用不可、記述する必要がないため削除する。 sleep()関数がNode.js には存在しないため、使用する場合は適宜実装する必要がある。 その他、HTML下では動作するがNode.js下では動作しない記法を変更する必要がある。 node-web-i2cを使う上での注意点 node-web-i2cを用いる場合、使用するI2Cパーツごとパッケージをインストールする必要があります。CHIRIMENをNode.jsで使用してみる⑴ ー 導入編 ーで作成したnode-web-i2c をインストールしたのと同じディレクトリで以下のようにパッケージのインストールを行ってください。また、パッケージ一覧はこちらのURLを参照してください。 xxxxはパッケージ名 % npm i @chirimen/xxxx I2C-SHT30 CHIRIMENからI2C-SHT30を使用して温度と湿度の値を出力する方法について説明します。 使用パーツ SHT30ブレークアウトボード x 1 ジャンパー線(メス・メス) x 4 配線 以下の図のように配線してください。 パッケージのインストール 以下のようにSHT-30のパッケージをインストールしてください。 % npm i @chirimen/sht30 Webブラウザ版のJavaScript Webブラウザ版では、ループ処理によってSHT30から得た温度と湿度を動的に出力しています。 main(); async function main() { const temperatureDisplay = document.getElementById("temperatureDisplay"); const humidityDisplay = document.getElementById("humidityDisplay"); const i2cAccess = await navigator.requestI2CAccess(); const port = i2cAccess.ports.get(1); const sht30 = new SHT30(port, 0x44); await sht30.init(); while (true) { const { humidity, temperature } = await sht30.readData(); temperatureDisplay.innerHTML = `${temperature.toFixed(2)} ℃`; humidityDisplay.innerHTML = `${humidity.toFixed(2)} %`; await sleep(500); } } Node.js版のJavaScript "i2c-sht30.js"というファイル名で下記のコードを保存してください。 このNode.jsでは、コードを実行した時点での温度と湿度を出力する形で実装しています。 // node-web-i2cを呼び出すおまじない const { requestI2CAccess } = require("node-web-i2c"); // SHT30のパッケージを呼び出す const SHT30 = require("@chirimen/sht30"); async function main() { const i2cAccess = await requestI2CAccess(); const i2c1 = i2cAccess.ports.get(1); // SHT30の接続されているポートの指定 const sht30 = new SHT30(i2c1, 0x44); await sht30.init(); const { humidity, temperature } = await sht30.readData(); console.log(`Temperature: ${temperature} ℃`); console.log(`Humidity: ${humidity} ℃`); } main(); 実行してみよう 下記のようにコマンドラインから実行し、温度と湿度が出力されれば成功です。 % node i2c-sht30.js Temperature: 24.433890287632565 ℃ Humidity: 53.6568245975433 ℃ I2C-ADT7410 CHIRIMENからADT7410を使用して、温度の値を出力する方法について説明します。 このセンサーは4本のピンヘッダ経由で接続します。あらかじめピンヘッダをハンダ付けしておいてください。 使用パーツ ADT7410使用高精度・高分解能I2C・16Bit温度センサモジュール )x 1 ジャンパー線(メス・メス) x 4 配線 以下の図のように配線してください。 また、センサーを接続する際に左右を間違えると高温になり火傷等をする恐れがあるため注意してください。 パッケージのインストール 以下のようにADT-7410のパッケージをインストールしてください。 % npm i @chirimen/adt7410 Webブラウザ版のJavaScript Webブラウザ版では、ループ処理によってADT7410から得た温度を動的に出力しています。 main(); async function main() { var head = document.getElementById("head"); var i2cAccess = await navigator.requestI2CAccess(); // i2cAccessを非同期で取得 var port = i2cAccess.ports.get(1); // I2C I/Fの1番ポートを取得 var adt7410 = new ADT7410(port, 0x48); // 取得したポートの0x48アドレスをADT7410ドライバで受信する await adt7410.init(); for (;;) { // 無限ループ var value = await adt7410.read(); head.innerHTML = value ? `${value} degree` : "Measurement failure"; await sleep(1000); } } Node.js版のJavaScript "i2c-adt7410.js"というファイル名で下記のコードを保存してください。 このNode.jsでは、コードを実行した時点での温度を出力する形で実装しています。 // ADT7410で温度を表示でさせるチュートリアル const { requestI2CAccess } = require("node-web-i2c"); // ADT7410のパッケージを呼び出す const ADT7410 = require("@chirimen/adt7410"); async function main() { const i2cAccess = await requestI2CAccess(); const i2c1 = i2cAccess.ports.get(1); // ADT7410の接続されているポートの指定 const adt7410 = new ADT7410(i2c1, 0x48); await adt7410.init(); const temperature = await adt7410.read(); console.log(`Temperature: ${temperature} ℃`); } main(); ​実行してみよう 下記のようにコマンドラインから実行し、温度が出力されれば成功です。 % node i2c-adt7410.js Temperature: 29.6875 ℃ さいごに 今回は以上になります。今回はnode-web-i2cでI2Cの使用方法の概要と湿温度センサー”SHT-30”と温度センサー”ADT-7410”のコードについて説明しました。次回も引き続きnode-web-i2cで使用可能なI2Cパーツの使用方法についての記事になる予定です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Calendarから予定を取得してESP32のLCDに表示する

前回の投稿 Google Photosからランダムな1枚の画像を取得できるようにする にて、Google Photosに登録しておいた画像をランダムに表示されるフォトフレームを作りました。 今回は、少し拡張して、Google Calendarに登録しておいたイベントも合わせて表示するようにします。 Google PhotosのAPIの呼び出しの時には、REST呼び出しでしたが、Google CalendarはNode.js用のライブラリが用意されているのでそれを使います。 ですが、Googleアカウントログイン部分は、REST呼び出しのものを流用したいので、REST呼び出しで認証したGoogleアカウントの認証結果(アクセストークン)をGoogle Calendarライブラリに引き継ぐようにします。 ソースコードもろもろは、以下に上書きしています。 poruruba/GooglePhotosGallery Google Calendar APIを利用できるようにする Google Cloud Platformのコンソールから、Google Calendar APIを使えるように有効化します。 GCP:APIとライブラリ https://console.cloud.google.com/apis/library 検索のところに、Calendarと入力すると、Google Calendar APIが出てきますので、選択してEnableにします。 認証結果をGoogleライブラリに引き継ぐ 以前の投稿 GoogleAPIライブラリを使わずにGoogleアカウントでログインできるようにする で認証結果(アクセストークン・IDトークン・リフレッシュトークン)をファイル出力していました。 それを使います。 node.js/api/controllers/googlecalendar-api/index.js function get_calendar(token){ const oAuth2Client = new google.auth.OAuth2(CLIENT_ID); oAuth2Client.setCredentials(token); return google.calendar({ version: 'v3', auth: oAuth2Client }); } 上記のtokenには、access_tokenがあれば大丈夫です。 ただし、このトークンを取得したときのGoogleアカウント認証時のScopeに、以下が含まれている必要があります。 https://www.googleapis.com/auth/calendar.readonly CLIENT_IDは、認証時に利用していたクライアントIDを指定してください。 あとは、以下のように呼び出すだけです。 node.js/api/controllers/googlecalendar-api/index.js var result = await new Promise((resolve, reject) => { calendar.events.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); paramsには、以下で示されるパラメータを指定します。 取得結果には、nextPageTokenが含まれている場合があります。その場合には、すべてのイベントを取得しきれていないので、pageTokenにnextPageTokenを指定して、続けて呼び出す必要があります。 結局、こんな感じです。 node.js/api/controllers/googlecalendar-api/index.js async function get_event_list(calendar, date){ var startTime = date.toISOString(); var endDate = new Date(date.getTime()); endDate.setHours(23); endDate.setMinutes(59); endDate.setSeconds(59); endDate.setMilliseconds(999); var endTime = endDate.toISOString(); var params = { calendarId: 'primary', timeMin: startTime, timeMax: endTime, singleEvents: true, orderBy: 'startTime', }; var result = await new Promise((resolve, reject) => { calendar.events.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); var items = result.data.items || []; while (result.nextPageToken) { params.pageToken = result.nextPageToken; result = await new Promise((resolve, reject) => { calendar.events.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); items = items.concat(result.data.items); } var list = []; for (const item of items) { var term = convert_date(item.start, item.end); list.push({ summary: item.summary, term: term }); } return list; } イベントの変更通知を受け取る Google Calendarのイベントは、他のGoogleアプリから編集されるため、イベントリスト取得後にも変更されている場合があります。 そこで、変更されたことをNotificationとして通知してくれる機能があります。以下のように登録します。 (参考) https://developers.google.com/calendar/api/guides/push?hl=ja node.js/api/controllers/googlecalendar-api/index.js const CALENDAR_WEBHOOK_URL = 'https://【Node.jsサーバのURL】/googlecalendar-webhooks'; ・・・ var params = { id: uuidv4(), type: "web_hook", address: CALENDAR_WEBHOOK_URL }; var result = await do_post_with_token('https://www.googleapis.com/calendar/v3/calendars/primary/events/watch', params, token.access_token); URLのところで「primary」に指定することで、ログインユーザのプライマリカレンダーが変更検知対象になります。 idには、毎回異なる値を指定します。今回はuuidにしました。 addressには、通知を受けたいWebAPIのURLを指定します。 戻り値はJsonです。戻り値のresultには、idとresourceIdが含まれており、登録解除時に必要ですので、ファイルに保存しておきます。 解除は以下の通りです。 node.js/api/controllers/googlecalendar-api/index.js var params = { id: json.notification.id, resourceId: json.notification.resourceId }; var result = await do_post_text_with_token('https://www.googleapis.com/calendar/v3/channels/stop', params, token.access_token); console.log(result); 戻り値は、Jsonではなくテキストです。 以下は、通知を受けた時の処理の例です。 node.js/api/controllers/googlecalendar-api/index.js case '/googlecalendar-webhooks': { console.log(event); if( event.headers['x-goog-resource-state'] == 'exists'){ var token = await read_token(); const calendar = get_calendar(token); var list = await read_event_list(calendar, true); client.publish(TOPIC_CMD, "1"); } return new Response({}); } 登録したURLに届く通知は、Google Calendarのイベントの変更時以外にも、いくつかのタイミングで届きます。HTTPヘッダー「x-goog-resource-state」がexistsの時が、イベント変更時の通知です。 上記の例では、イベントリストを更新したのち、MQTTにパブリッシュして他のデバイス(今回の場合は、LCD付のESP32がSubscribeしている)に通知しています。 ついでにGoogle Tasks(toDo)のタスクリストも取得してみます こちらも、Googleライブラリ化されていますので、それを使います。 毎度の通り、以下で、Tasks APIを有効にします。 GCP:APIとライブラリ https://console.cloud.google.com/apis/library また、Googleアカウント認証時には、以下をScopeに含めます。 https://www.googleapis.com/auth/tasks.readonly あとは、以下のようにtasksのインスタンスを生成して、呼び出すだけです。 node.js/api/controllers/googlecalendar-api/index.js case '/googletasks-list': { var token = await read_token(); const tasks = get_tasks(token); var list = await get_tasklist_list(tasks); console.log(list); for( var i = 0 ; i < list.length ; i++ ){ list[i].list = await get_task_list(tasks, list[i].id); } return new Response({ list: list }); } ・・・ function get_tasks(token) { const oAuth2Client = new google.auth.OAuth2(CLIENT_ID); oAuth2Client.setCredentials(token); return google.tasks({ version: 'v1', auth: oAuth2Client }); } async function get_tasklist_list(tasks){ var params = {}; var result = await new Promise((resolve, reject) => { tasks.tasklists.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); var items = result.data.items; while (result.nextPageToken) { params.pageToken = result.nextPageToken; result = await new Promise((resolve, reject) => { tasks.tasklists.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); items = items.concat(result.data.items); } var list = []; for (const item of items) { list.push({ title: item.title, id: item.id }); } return list; } async function get_task_list(tasks, id) { var params = { tasklist: id }; var result = await new Promise((resolve, reject) => { tasks.tasks.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); var items = result.data.items || []; while (result.nextPageToken) { params.pageToken = result.nextPageToken; result = await new Promise((resolve, reject) => { tasks.tasks.list(params, (err, res) => { if (err) return reject(err); resolve(res); }); }); items = items.concat(result.data.items); } var list = []; for (const item of items) { list.push({ title: item.title, notes: item.notes, id: item.id, parent: item.parent || null, due: item.due ? new Date(item.due).getTime() : null }); } return list; } 流れとしては、タスクリストというタスクを束ねたもののリストを取得したのち、タスクリストごとに含まれるタスクのリストを取得する、という流れです。 流れさえわかれば、おおよそ理解できると思いますので、詳しくは、GitHubのソースコード参照してください。 poruruba/GooglePhotosGallery  https://github.com/poruruba/GooglePhotosGallery LCD付ESP32の実装 Google Calendarのイベントの取得は、以下のURLに対してJSON-POST呼び出ししているだけです。 https://【Node.jsサーバのホスト名】/googlecalendar-list 一方で、イベントの変更検知するために、MQTTでトピック「calendar/notify」でSubscribeして待ち受けています。通知を受けたら、Google Calendarイベントの再取得を含むLCD再描画処理を実行しています。 詳しくは、GitHubのソースコード参照してください。 poruruba/GooglePhotosGallery  https://github.com/poruruba/GooglePhotosGallery 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ランダムなダミーの温湿度の値で急激な変動がない値を生成する(Node.js で simplex-noise を利用)

「デバイス+センサー」が MQTTクライアントになった構成の開発をしている中で、MQTT の値を受信する MQTTブローカーの部分や別クライアント側に手を加える開発をするのに、以下のような物理部分をセットしなくても開発できるようにしたくて、今回の内容を進めました。 GR-ROSE と「Grove - CO2 & Temperature & Humidity Sensor (SCD30) 」の接続はスルーホール用テストワイヤを使い、差し込み式で接続してる。 https://t.co/hA2wu3KYw3 pic.twitter.com/WbV3yNgNB6— you (@youtoy) October 30, 2021 概要 ひとまず温湿度の 2つの値を対象に、それらをランダムに生成するプログラムを作っていきます。 その値について、JavaScript だと Math.random() を使う方法もありますが、あまり急激な変化はしてほしくなかったため、乱数生成の部分には「Simplex Noise」を使いました(パッケージは以下を利用)。 ●simplex-noise - npm  https://www.npmjs.com/package/simplex-noise ちなみに、Simplex Noise をざっくり説明すると、以下のパーリンノイズと同じようなものになります。 ●パーリンノイズ - Wikipedia  https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%BC%E3%83%AA%E3%83%B3%E3%83%8E%E3%82%A4%E3%82%BA 必要になる環境など 開発には Node.js を使っていきます。 MQTTブローカーを何らか用意し、今回のプログラムを動作させる PC の中で動かしてください。 また、以下のコマンドで 2つのパッケージを利用できるようにしておいてください。 $ npm i mqtt simplex-noise プログラム プログラムの内容は、以下のとおりです。 const mqtt = require("mqtt"); const client = mqtt.connect("mqtt://localhost"); const { SimplexNoise } = require("simplex-noise"); const simplex = new SimplexNoise(); let count = 0; client.on("connect", function () { const timerId = setInterval(() => { const randomT = convertedValueRandom(simplex.noise2D(count, 10), 20, 25); client.publish("outTopic/T", randomT + ""); const randomH = convertedValueRandom(simplex.noise2D(count, 20), 60, 80); client.publish("outTopic/H", randomH + ""); console.log(` 温度: ${randomT}, 湿度: ${randomH}`); count += 0.007; }, 2000); }); function convertedValueRandom(inputSimplexNoise, min, max) { const randomZeroToOne = (inputSimplexNoise + 1) / 2; return randomZeroToOne * (max - min) + min; } simplex-noise は -1 から 1 の間の値を生成するため、Math.random() のような 0 から 1 の値を生成させたい場合は、少し手を加える必要があります。 上記の中では、 convertedValueRandom() でその変換を行っています。 また、 count += 0.007 の値を変更すると、生成される乱数の変化の度合いを変えることができたりもします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む