20210516のNode.jsに関する記事は13件です。

Google Cloud FunctionsからGoogle Cloud Translationを試してみる

前回、FirebaseでGoogle Cloud Functionsを使ってみました。 FirebaseのCloud FunctionsからGoogle Cloud Translationを試してみる 今回はFirebaseを使わずに、素のGoogle Cloud Functionsで同じ題材をやってみました。 Cloud FunctionsのHello, World! function.js という名前でJavaScriptのソースコードを書きます。 exports.helloWorld = function (req, res) { console.log("Hello, console.log!"); res.send('Hello, World!'); }; function.js という名前である必要があるみたいです。デプロイは以下のコマンド。 $ gcloud functions deploy hello_world --runtime=nodejs12 --entry-point=helloWorld --trigger-http --allow-unauthenticated デプロイ時にコンソールにこのCloud FunctionのURLが表示されますが、以下のようなURLです。 https://us-central1-xxxxxxxx.cloudfunctions.net/hello_world このURLにブラウザでアクセスすると Hello, World! と表示されます。 Cloud Functionsのログを見てみます。 $ gcloud functions logs read hello_world LEVEL NAME EXECUTION_ID TIME_UTC LOG D hello_world jqwsqgteu8tt 2021-05-16 13:23:36.513 Function execution took 10 ms, finished with status code: 304 hello_world jqwsqgteu8tt 2021-05-16 13:23:36.511 Hello, console.log! D hello_world jqwsqgteu8tt 2021-05-16 13:23:36.504 Function execution started Cloud FunctionsからCloud Translation APIを呼び出してみる 前回の記事に書いたCloud Translation API有効化は完了済みとします。 package.json ファイルを用意します。内容は以下のみ。 { "dependencies": { "@google-cloud/translate": "*" } } function.js の内容を以下のようにします。ほとんど前回の記事のサンプルコードそのままです。 const { TranslationServiceClient } = require("@google-cloud/translate").v3; const projectId = "xxxxxxxx"; const location = "us-central1"; // 言語判定 async function detectLanguage(text) { const translationClient = new TranslationServiceClient(); const req = { parent: translationClient.locationPath(projectId, location), content: text, mimeType: "text/plain" }; const res = await translationClient.detectLanguage(req); let sourceLang = null; for (const elem of res) { if (elem == null) // なぜかnullがレスポンスに含まれる continue; return elem["languages"][0]["languageCode"]; } } // 翻訳 async function translate(text, sourceLang, targetLang) { const translationClient = new TranslationServiceClient(); const req = { parent: translationClient.locationPath(projectId, location), contents: [text], mimeType: "text/plain", sourceLanguageCode: sourceLang, targetLanguageCode: targetLang, }; const res = await translationClient.translateText(req); for (const elem of res) { if (elem == null) // なぜかnullがレスポンスに含まれる continue; return elem["translations"][0]["translatedText"]; } } async function sample(text) { const result = {}; result["original"] = text; // 言語判定 const sourceLang = await detectLanguage(text); // 翻訳 for (const targetLang of ["en", "ja", "zh-TW", "zh-CN", "ko"]) { if (targetLang == sourceLang) // Target language can't be equal to source language. というエラーを防ぐため continue; const targetText = await translate(text, sourceLang, targetLang); result[targetLang] = targetText; } return result; } exports.helloWorld = async function (req, res) { sample("Hello, World!").then(result => { console.log(result); res.send(result); }).catch(err => { console.log(err); }); }; これをデプロイして、ブラウザでアクセスすると無事以下のように表示されました。 {"original":"Hello, World!","ja":"こんにちは世界!","zh-TW":"你好,世界!","zh-CN":"你好,世界!","ko":"안녕하세요, 세계!"}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コロナ禍で半年母親に会えないのでobnizとtwilioで見守りシステムを考えてみた。

1.はじめに  コロナによる緊急事態宣言により帰省が出来なくなり、一人住まいの母親とは電話では話しているものの全く顔を合わせる事もなく半年以上経ってしまいました。  母親は高齢のためガラケーを使っておりしかもメールやSNSも全く使えない世代。今更メールやLINEの使い方を教えることもできない。  一時期Apple Watchを持ってもらおうかとも考えたが、転倒検知がかなりの勢いで倒れないと検知しないみたいなので断念した。  今回はobnizに超音波距離センサー(HC-SR04)を組み合わせ、一定時間距離に変化がなければ母親の具合が悪くなっているとみなして、twilioを使用しショートメッセージを自分のスマホに送信する様にした。 2.環境 ハードウェア  obniz 1Y  HC-SR04 ソフトウェア  node.js v16.0.0 3.obniz  非常に簡単なセットアップとJavaScriptで操作できるため私の様な初心者にはありがたい仕組みであった。 4.twilio https://cloudapi.kddi-web.com/availability twilioの利用はいたって簡単で。  無料アカウント登録→アカウントSIDとAUTHTOKENを取得→トライアル発信用番号を取得あとはコードを書くだけである。 5.node.js obnizを利用するために以下のコマンドを実施 npm install obniz twilioを利用するために以下のコマンドを実施 npm install twilio  ソースは以下の通り。 const Obniz = require('obniz'); const obniz = new Obniz('foo'); // Obniz_IDに自分のIDを入れます const accountSid = "hoge"; //twilioのアカウントSID const authToken = "hogehoge"; //twilioのAUTHTOKEN const client = require('twilio')(accountSid, authToken); let pre_distance = 0; obniz.onconnect = async function () { // 超音波測距センサを利用する const hcsr04 = obniz.wired('HC-SR04', { gnd: 0, echo: 1, trigger: 2, vcc: 3 }); obniz.display.clear(); // クリア // setIntervalで一定間隔で処理 setInterval(async function () { // 距離を取得 let distance = await hcsr04.measureWait(); // そのままだと小数点以下の桁数がやたら多いので整数に丸めてもよい distance = Math.floor(distance); // 距離(mm)をターミナルに表示 console.log(distance + ' mm'); let diff = pre_distance - distance console.log('今回' + distance + ' mm'); console.log('前回' + pre_distance + 'mm'); console.log('差分' + diff + 'mm'); if ( diff < 40) { client.messages .create({ body: '実家に電話してください。', from: 'トライアル用発信番号', to: '送信先番号' }) .then(message => console.log(message.sid)); } pre_distance = distance; }, 2000); // 1000ミリ秒 = 2秒おきに実行 } 6.結果  距離測定を2秒おきに行い前回との差分が40mm未満だとショートメッセージを発信する。  HC-SR04は測定時の誤差がそれなりにあるので40mm未満は誤差と考えた。私の部屋では20mm程度の揺らぎがあった。  今回は2秒としたが、実際には1時間〜2時間のインターバルで屋内の数カ所、居間、台所、寝室、トイレ前に設置し、全てのobnizで距離測定の変化がない時にアラートをあげるようにしたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

平成生まれのエンジニアが初めてIoTに触れるのに丁度良い、生き残りゲーム~令和最新版~のプロトタイプをobnizで作る

先日、手軽にIoTに触れられると噂の「obniz」を入手しました。 ラズパイに比べて、圧倒的に早く、楽に電子デバイスを操れるのでうっかりスキルが向上したか?と錯覚するほどです。 この手軽さを活かす先は、プロトタイプでしょ?!ということで、さっそく行動してみました。 生き残りゲームの令和最新版をプロトしよう 時代背景・コロナ感染予防・働き方・IoT・サーボモーターの動き、、、パッとピラめいたのが  生き残りゲーム レトロラブな私としては、これの令和最新版が作りたい!新しい形で対戦してみたい! これです。  コレは絶対楽しいやつにしか思えないので、プロトしてポテンシャルを測ってみたいと思います。 ちなみに、この生き残りゲーム、平成生まれの方はあまり知らないらしいですね。そんな記事をネットで見ました。 ご存じない方は「生き残りゲーム 沈没」でググってみてください。 そして、私のこの記事をこのまま読み進めていただき、私のような昭和生まれのエンジニアに対して「IoT触ってみましたよ!生き残りゲームでw」と会話のネタにしていただければ幸いです。上司や仕事仲間と良好な人間関係を構築することができることでしょう。 まん防に対応しても当時の興奮そのまま!そしてニューノーマルへ コンセプトはズバリこれ↑です 生き残りゲーム(物理的なゲーム)をIoTデバイスを駆使してリモートで対戦できるようにします。 いろいろなものが電子化され、新型コロナのおかげでさらに拍車がかかっています。そんな時だからこそ、現物にこだわりたい! 生き残りゲームの醍醐味は、球がドボンするところ。やはり物理的なモノがあってナンボです。ガシャ!ってならないと興奮しません。素朴なギミックを大事にしたいですね 仕掛けはこんな感じ さて、実現可能なのでしょうか?面白いのでしょうか?プロトしてみましょう。 出来上がったのがこちらです アイデアを可視化しそこから新たな学びを得ることがプロトの目的ですので、「さっさと作る」が肝要。 そこらへんに転がっているもので、さっさと作りましょう。本物の生き残りゲームは、もう手に入らないしね。。。 できたアウトプットも「さっさと見せて」しまいましょう。 ということで完成品がこちらです。 本人いたって真剣です(笑 2×2マスのミニマム仕様です。 縦方向に走る緑色の板がリモート参加者用のドボンバー(正式名称不明)。 ドボンバーはキングピン代わりのカーボン抵抗を介してサーボアームと直結、obnizで制御され上へ下へと動きます。 横方向のドボンバーは実機参加者用で、手動となります。 ドボン機構の再現には、材料の穴あけ容易性とそこそこの強度が必要となります。いろいろな素材を試した結果、某おもちゃショップのポイントカードと某アイドルグループのメンバーズカードを採用するに至りました。 制作概要 使ったもの obniz board 1Y サーボモーター×2 ジャンパワイヤ カーボン抵抗 古びたタッパー 無用になったメンバーズカード2枚 ビーズ 両面テープ ガムテープ 猫頭付箋 貯まりにたまったAmazonの段ボール 仕掛け リモート側のユーザインターフェースとしてLINE Botを採用 Node.jsでLINE Bot とobnizを制御 リモートユーザのドボンバー2本を 2つのサーボモータでリモート操作 作成風景 穴あけ作業がちょいちょい発生するので、ピンバイス、ドリルなどあると良いです。 Node.jsによる制御(コード) 技術要素 LINE Botを使ったユーザとのメッセージ授受 obnizを使ったサーボモータの制御 expressを使ったLINEとobnizの連携 expressをつかって手持ちのパソコンでサーブ。 ngrokをつかってインターネット上のLINEのサービスと接続した。 dobon.js // ######################################## // obniz処理部分 // Obniz_ID:自分のobniz ID(XXXX-XXXX) // ######################################## const Obniz = require('obniz'); const obniz = new Obniz('XXXX-XXXX'); // obnizと接続確立したとき obniz.onconnect = async () => { obniz.display.clear(); obniz.display.print('obniz Ready'); } //サーボの動作 const svRFunc = async (deg) => { const sv = obniz.wired('ServoMotor', { signal: 2 }); sv.angle(deg); } const svLFunc = async (deg) => { const sv = obniz.wired('ServoMotor', { gnd: 9, vcc: 10, signal: 11 }); //let degrees = i; sv.angle(deg); } // ######################################## // LINEBot イベント処理部分 // channelSecret:LINE Developers → チャネル基本設定 → チャネルシークレット // channelAccessToken:LINE Developers → Messaging API設定 → チャネルアクセストークン(長期) // ######################################## const config = { channelSecret: 'XXXXXXXXX', channelAccessToken: 'XXXXXXXXX' }; 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 === '下のレバーを左') { // 受け付けたということを「リプライ」で先に返す await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); // obnizのサーボ動かす(ブロッキング・時間のかかる処理で一旦ここで止まる) const temp = await svRFunc(120.0); // 処理完了を「プッシュ」で送信する client.pushMessage(event.source.userId, { type: 'text', text: '下のレバーを左に動かしたよ', }); //以下 各サーボ毎にふるまいを設定 }else if (event.message.text === '下のレバーを真ん中') { await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); const temp = await svRFunc(90.0); client.pushMessage(event.source.userId, { type: 'text', text: '下のレバーを真ん中に動かしたよ', }); }else if (event.message.text === '下のレバーを右') { await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); const temp = await svRFunc(60.0); client.pushMessage(event.source.userId, { type: 'text', text: '下のレバーを右に動かしたよ', }); }else if (event.message.text === '上のレバーを左') { await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); const temp = await svLFunc(45.0); client.pushMessage(event.source.userId, { type: 'text', text: '上のレバーを左に動かしたよ', }); }else if (event.message.text === '上のレバーを真ん中') { await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); const temp = await svLFunc(90.0); client.pushMessage(event.source.userId, { type: 'text', text: '上のレバーを真ん中に動かしたよ', }); }else if (event.message.text === '上のレバーを右') { await client.replyMessage(event.replyToken, { type: 'text', text: '了解' }); const temp = await svLFunc(130.0); client.pushMessage(event.source.userId, { type: 'text', text: '上のレバーを右に動かしたよ', }); } else { // LINEから飛んできたメッセージの中身が指定の文言以外だったとき 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); プロトタイプテストの様子 被験者には実際に離れたところから、今回開発したLINEのアプリをつかってゲームに参加していただいた。 生き残りゲーム本体の様子は別途Zoomで中継した。 プロトタイプから得られた学び 良かった点 見た目を含め実にアホくさくて非常にウケてもらえた。作ってよかったと感じた。(改めて、自分はこの手のやつが大好物だということを思い知った) 仕事の合間、WEB会議で雰囲気が悪くなった時などに、こいつをいそいそ出してくるとウケるかもしれないとおもった。やはりニューノーマルガジェットの筆頭になるか? サーボの勢いがありすぎて球が下におちるのではなく外に飛び出した時(想定外の動き)が一番盛り上がった。そういえば当時、その手のチートを繰り出す輩もいたよねと昔の思い出話に花が咲いた。このゲームを令和最新版にするにあたりこだわるポイントは物理的アクションで間違いはないと確信した。 もっと深堀したい点 昭和時代の人に当てたらどれだけウケるか? サイズ感はどれくらいがよいか?実際にプロトで触ってみて、通常版(フルスペック)をネット越しでガチでやるのはちょっと想像ができなかった。今回のような2×2またはもうちょっと大きいくらいがよいだろうか。ユースケースはやはりWEB会議のアイスブレイクなどではないだろうか 付加機能があったほうがいいのか?それともシンプルが一番なのか?なんとなくシンプルのほうが良い気がする。 当たり前だが、本物の意匠をどれだけ再現できるか?にかかっているとおもう。 リモートだとほんのり動かして穴の様子を探るチートができない点をどうするか?LINEボタンではなく、フリック入力などで力加減を伝えられる仕組みも面白いかもしれない。 やはり平成生まれには刺さらないだろうか? 完全フルオートはどうだろうか?球の回収・セッティングまで全自動。オンラインUFOキャッチャーのようなイメージ メーカーさん製品化してくれないだろうか? 生き残りゲーム~令和最新版~のプロトタイピングは以上です。 ご意見お待ちしております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nvm-windowsでnode.jsのバージョン管理をする【Windows】

Node.jsのバージョン管理をwindowsPCでやりたくなったので入れ方を備忘録として。 どなたかの参考になれば幸いです 手順 windowsはnodistが有名っぽいんですが、 以前なぜかめちゃくちゃ苦戦したのでnvmを入れてみます! ※正確にはnvm-windowsというMacで使うnvmのwindows版みたいなやつです。 nvm-windows:https://github.com/coreybutler/nvm-windows とりあえずアンインストール 現状普通に入っている場合はややこしくなるのでいったん削除します。 ($node -vでバージョン出てきたら入っていて、  特にバージョン管理入れてなければベタだと思います) スタート(左下のWindowsアイコン) → 設定(歯車アイコン) → アプリ → アプリと機能 出てくるリストにNode.jsがあるはずなのでそちらをアンインストールでOK! nvm-windowsのインストール https://github.com/coreybutler/nvm-windows/releases こちらのGitHubにダウンロードリンクの記載がありますので、 nvm-noinstall.zipをダウンロードします。 中にnvm-setup.exeが入っているので、素直にインストールを進めます。 終わったら$nvm versionでバージョンを確認して、数字が出ればOK! $nvm version 1.1.7 Node.jsのインストール インストール済みのNode.jsの確認が$nvm list、 インストールできるNode.jsの確認が$nvm list availableでできます。 $nvm list available | CURRENT | LTS | OLD STABLE | OLD UNSTABLE | |--------------|--------------|--------------|--------------| | 16.1.0 | 14.17.0 | 0.12.18 | 0.11.16 | | 16.0.0 | 14.16.1 | 0.12.17 | 0.11.15 | ~省略~ This is a partial list. For a complete list, visit https://nodejs.org/download/release LTS(推奨版)は14.17.0とのことですので、14.17.0をインストールしましょう。 $nvm install [使いたいバージョン]でインストールします。 $nvm install 14.17.0 ~省略~ Installation complete. If you want to use this version, type nvm use 14.17.0 インストール済みリストでも大丈夫そうです! $nvm list 14.17.0 使用バージョンの指定 $nvm use [使いたいバージョン]で指定ができます。 「デバイスに変更を加えることを許可しますか?」みたいなのが出てくるので通します。 $nvm use 14.17.0 Now using node v14.17.0 (64-bit) インストール済みのリストと、Node.jsのバージョンを確認してみます。 $nvm list * 14.17.0 (Currently using 64-bit executable) $node -v v14.17.0 リストには*マークがついて使用してるよーというのがわかるようになり、 Node.jsのバージョン確認では選んだものが出るようになりました! ちなみにnpmもしれっと大丈夫でした。 $npm -v 6.14.13 バージョン切り替え 試しに最新版も入れて、切り替えてみます。 // インストール $nvm install 16.1.0 ~省略~ Installation complete. If you want to use this version, type nvm use 16.1.0 // インストール済みリスト確認 $nvm list 16.1.0 * 14.17.0 (Currently using 64-bit executable) // 使用バージョンの指定 $nvm use 16.1.0 Now using node v16.1.0 (64-bit) // インストール済みリスト選択確認 $nvm list * 16.1.0 (Currently using 64-bit executable) 14.17.0 // Node.jsのバージョンを確認 $node -v v16.1.0 インストール → 切り替え → 確認を通してみましたが無事切り替わってますね! バージョン削除 さて、最新版は用済みなので削除です。 $nvm uninstall [削除したいバージョン]で削除します。 // 使用バージョンの指定 $nvm use 14.17.0 Now using node v14.17.0 (64-bit) // インストール済みリスト選択確認 $nvm list 16.1.0 * 14.17.0 (Currently using 64-bit executable) // 16.1.0をアンインストール $nvm uninstall 16.1.0 Uninstalling node v16.1.0... done // なくなってることを確認 $nvm list * 14.17.0 (Currently using 64-bit executable) こちらも問題なく削除できました! まとめ 環境設定苦手マンでも躓かずできたのでスムーズでうれしいですね! 切り替えのときに確認が出るのが面倒ですがそれ以外はシンプルで分かりやすいです! 使ったコマンドまとめ コマンド 用途 $node -v Node.jsのバージョン確認 $npm -v npmのバージョン確認 $nvm version nvmのバージョン確認 $nvm list インストール済みのNode.jsの確認 $nvm list available インストールできるNode.jsの確認 $nvm install [使いたいバージョン] Node.jsのインストール $nvm use [使いたいバージョン] 使用バージョンの指定 $nvm uninstall [削除したいバージョン] バージョンの削除 ありがとうございました
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テレワーク中の旦那さんに「お昼だよ!」を間接的に伝えるためのしかけを作ってみた!

作った目的 こんにちは。wataminoです。 旦那さんとテレワークがかぶるときは、いつも別々の部屋で仕事をしているのですが、お昼時は私から「お昼だよー!」と知らせに行きます。 なぜならお昼を忘れるほど彼は真剣(?)に仕事をしているからなのです。 でも真剣(?)すぎるあまり9割は声をかけても無視をされるか、嫌な顔されてしまいます。 せっかく、貴重なお昼時間を教えてあげているのに、、、 そこで、今、obnizでものづくりの勉強をしていることもあり、「ならば行かずとも視覚と聴覚に訴えお昼時間を知らせるための仕掛けを作ってみよう!」ということで、作成に取り掛かりました。 使用したもの ・obniz Board 1Y ・サーボモーター ・抵抗内蔵LED(赤) ・スピーカー トリガーに関する試行錯誤 仕掛けを作ったところで、それを動かすためのトリガーをどうしようか、、、といろいろ考えました。 Twitter まずは、Twitterです。 obnizはTwitterとも連携できるようなので、Twitterで「旦那さん」とかつぶやいて動作させられたら、ステキだな、、、と思い、APIを取得しようと考えました。 ところが、APIの取得には「TwitterAPI、Twitterのデータをどのように利用するかを「In your words」の欄に英語で200字以上入力」する必要があるようで、英語が苦手な私はこれだけで日数が経ってしまいそうだったので、残念ですが今回はあきらめました。 次回、トライしようと思います。 ジャンパーワイヤーをつなげる そして次に考えたのが、「ジャンパーワイヤーをつなげる」です。 部屋が離れている分をジャンパワイヤーをつなげることでいけるんじゃない?と考え、家に無数にあるジャンパーワイヤーをつなげてみました。 結果、まったく動作しませんでした。? これは、抵抗が増えて電圧が低下したためでしょうか? こちらもあえなく断念。 sleepMinuteを使う obnizのドキュメントに「定期実行」というガイドがありました。 https://obniz.com/ja/doc/guides/battery-long-life/intervally 「sleepMinuteを使うことで、指定した時間だけsleepします。sleepが開始されると、自動的にobnizとの接続が切断され、sleep状態に入ります。sleep状態はobnizBoard 1Yの見た目が電源をつないでいない時と同じになり、画面に何も表示されなくなります。」(obnizガイドより抜粋) これはいいですね。 実際使ってみましたが、ガイドに記載のとおり、sleepMinuteの時間だけ電源が落ちて、その時間が経過するとobnizが起動され、仕掛けが動きました。 でも、これ、PC落としちゃったら動作しない、、、ということに気が付きました。 やっぱり手動 というわけで最後は、手動でプログラムを動かすことにしました。 (なんともマニュアルすぎますが、、、) いざ、起動 とりあえず自宅にあったグッズにセットしてみた。 なんか工作感まるだしですが、気にしないでください。 ちなみに顔は私そっくりです!(笑) では、動かしてみます! 1.最初にお知らせの音楽が流れます。(一応、ピンポンパンポーーン♪です) 2.obnizの画面に「LunchTime!LunchTime!LunchTime!」が表示されます。 3.LEDライト(一応ハート)と私の顔が傾いて最後の猛アピールです。 テレワーク中の旦那さんにお昼の時間を間接的に伝える仕掛けを作ってみました。画像の顔はわたしにそっくり!笑#protoout #obniz pic.twitter.com/FnZm2pEis2— watamino (@watamino2) May 16, 2021 動画ではobnizのコードを隠すためLunchTimeの表示が見えていないので写真を載せます。 サンプルコード node.js const Obniz = require('obniz'); const obniz = new Obniz('obniz-id'); // Obniz_IDに自分のIDを入れます obniz.onconnect = async function () { const led1 = obniz.wired('LED', { anode:8, cathode:9}); //LEDライトを使用 const speaker = obniz.wired('Speaker',{signal:4, gnd:5}); //スピーカーを利用 const servo = obniz.wired('ServoMotor', { gnd: 0, vcc: 1, signal: 2 }); //サーボモーターを使用 // ディスプレイ表示(実行中表示される画面) obniz.display.clear(); obniz.display.print('LunchTime! LunchTime! LunchTime!'); // 角度を保持する変数 let degrees = 90.0; //スピーカーから流れる音階 speaker.play(262); //ド await obniz.wait(800); speaker.play(330); //ミ await obniz.wait(800); speaker.play(392); //ソ await obniz.wait(800); speaker.play(523); //ド await obniz.wait(1000); speaker.play(523); //ド await obniz.wait(800); speaker.play(392); //ソ await obniz.wait(800); speaker.play(330); //ミ await obniz.wait(800); speaker.play(262); //ド await obniz.wait(800); speaker.stop(); // LEDライト点滅(起動されている間) led1.blink(500); let count = 0; // 旗の角度 let angles = [10, 50, 10, 50, 10, 50, 10, 50, 90, 10]; let timer = setInterval(() => { count++; servo.angle(angles[count]); //11回旗が左右に動きます if (count >= 11) { clearInterval(timer); let degrees = 90.0; led1.off(); obniz.display.clear(); } }, 1000); } 最後に いつもはラズパイでものづくりをしている私ですが、念願のobnizを触ることができて楽しかったです。♪ obnizにはできることがたくさんあるということを知ったので、次回はラズパイとobnizをつなげてなにかものづくりしようと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[obniz]季節の変わり目に飲み物提供マシン

ここだけ見てくれたら閉じていいよw 今回はこんなものを作りました! この動画見てくれたら、もうそれでいいですw 気温判断で飲み物提供マシンを作りました!寒いと温かい飲み物を暑いと冷たいものを提供してくれます!荒々しすぎるしコード邪魔で奇跡の一枚になりそう笑#protoout #obniz pic.twitter.com/1v20lCHRRU— kkyosuke (@kkyosuke17) May 16, 2021 見てくださりありがとうございました。 以下このマシンの概要になるので気になる方はぜひご覧ください。 暑いし寒い、1日の気温の変化が大変 この時期、朝は寒いのに昼間は暑い。。 日が暮れるころにはまた寒いなんて感じませんか? そんなときに少し役に立つ飲み物の提供マシンをobnizでつくりました。 マシンの中身 まず温度センサー(LM60 | JS Parts Library | obniz)とLEDWS2811 | JS Parts Library | obnizが使用されています。 温度センサーで気温を計測し、設定した温度より高いか低いかでLEDが変色します。 今回のマシンに欠かせないのがサーボモータ!!(サーボモーターの概要) 回転する鍋蓋と土台のボールの間に設置しました。 これを固定してバランスとるのが難しかったw あとは回転する鍋蓋の上につけられたカップに飲み物の温度を保つための保冷剤とカイロを入れて完成! ここも見る価値ありかも!obnizの配線とソースコード 各部品とobnizは以下のように接続しました。 使用したobnizは1Yボードになります。 以下が使用したソースコードになります。 const Obniz = require('obniz'); //IDの書き換え忘れずに!! const obniz = new Obniz('ID'); obniz.onconnect = async () => { // 温度センサ const tempsens = obniz.wired('LM60', { gnd: 0, output: 1, vcc: 2 }); // RGB LEDを利用 const rgbled = obniz.wired('WS2811', { gnd: 4, vcc: 5, din: 6 }); // サーボモータを利用 const servo = obniz.wired('ServoMotor', { gnd: 9, vcc: 10, signal: 11 }); // 角度を保持する変数 let degrees = 90.0; // obnizディスプレイ(初期表示) obniz.display.clear(); obniz.display.print('obniz Ready'); // setIntervalで定期実行 setInterval(async () => { // 同期的に取得 const temp = await tempsens.getWait(); // 温度をコンソールに表示 console.log(temp + 'C'); // 温度をobnizディスプレイに表示 obniz.display.clear(); obniz.display.print(temp + 'C'); // 温度によって判定 if (temp < 22.0) { //冷たい飲み物が置いてあるほうに回転 degrees = 180.0; servo.angle(degrees); //水色のLEDを点灯 rgbled.rgb(45, 140, 255); } else { //暖かい飲み物が置いてあるほうに回転 degrees = 1.0; servo.angle(degrees); //オレンジ色のLEDを点灯 rgbled.rgb(255, 110, 30); } }, 180000); // 180000ミリ秒 = 30分ごとに実行 }; できなかったこと・・・ ここまで完成はしたのですが本来使いたかったのはこの部品! 圧力センサー(FSR-40X)!!!! こいつを使って飲み物が減っているかを検知したかった。 もし30分以上減っていなければ音を鳴らし脱水症防止にも役立てられただろうに・・・ なぜ実装に至らなかったかというと短すぎwwwww 回転盤の素材や土台をもうすこし考えてから再挑戦したと思います! まとめ 今回はあったらいいなでいうと1日の水分摂取量を管理してくれるものが作りたかったのでできなかったことのほうがあったらいいなでした。 しかし今回作成したマシンを見てこれは面白いし、こちらを作りたいという気持ちが勝ったため圧力センサーは今回外しました。 作成前はこのマシンはあまり面白くないだろうなと思い圧力センサーを思いついたのですが動いているところを見たらシュールで面白かったです。 やはり作ってみるまで分からないところもあるなと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

obnizでわが子と一緒に「オリジナル目覚ましBot」を作って、実際に起きられるかどうかを試した結果

今回の目的 ~わが子に"オリジナル目覚まし"を作りたい!~ 来年の今頃は、わが家の息子は小学校1年生。 今後のために、朝は1人で起きられるようになって欲しい!! そんな思いから、先日学習したobnizで「オリジナル目覚ましBot」を作ってみよう!と考えました。 そもそも、わが家の息子は、朝がとっても苦手。 毎日、必死に起こすのが日課となっていますが、寝起きがとっても不機嫌です? 本人いわく、「パパやママの声だと、ビックリするから嫌」なのだとか。 その後の支度もグダグダとなってしまうので、なんとか笑顔で朝を迎えてくれたら・・・と、模索しており、このあたりもBotで解消できればと思います。 完成品(「わが子専用 目覚ましBot」) 完成品のご紹介です。 LINEBotからの合図とともに、obniz電圧スピーカーからメロディーが流れる仕様。 前回の記事で作ったLINEBotを、一部アレンジしています。 わが子専用「オリジナル目覚ましBot」が完成!?リズムが所々不自然ですが、個人的には苦労した部分なので、かえって愛着が湧いてます。笑さて、わが子は起きられるようになるのでしょうか??#obniz #LINEBot #子ども#ポケモン #めざまし #Javascript pic.twitter.com/ZPyClWlFi3— くるみ (@Kokano23) May 16, 2021 メロディーは、「めざせ ポケモンマスター」。 息子本人のモチベーションがなにより大事になると思ったので、「どんな曲なら起きられそう?」と本人にヒアリングして一緒に決めました。 前回作ったピカチュウBotが好評で、「今度は、ミュウに起こして欲しい!」と要望もありました。幻のポケモン"ミュウ"が、今は一番好きなのだそう。 そこで、今回もLINEのリッチメニューを活用しました。(ポケモンの画像は、pokeAPIより取得) ミュウをタッチすると、テーマソングの再生とともに応援メッセージが届く仕組みです。実際は、わが子の名前も入れて、オリジナル感を演出しました。 (これを見れば、きっと笑顔になれる!) 作り方 ①obnizの設定 準備したもの obniz Board 1Y 圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0 事前設定や接続は、obniz公式ドキュメント(起動とWi-Fi設定)やobniz公式ドキュメント(Speaker)を参考にしました。 ②LINEBotの準備 Botアカウントの準備は、前回と同様に、こちらの記事を参考にしています。 ③メロディーの設定 音階周波数を参考にしました。 「めざせポケモンマスター」の楽譜から、メロディーをソースコードに組み込みました。 リズムが不自然になってしまったところがあり、手作り感が満載です。(テンポの調整など、何度も再生しながら試行錯誤しました。難しかったです。) ソースコード ソースコード全文です。(セクション内参照) 'use strict'; // obniz呼び出し const Obniz = require('obniz'); const obniz = new Obniz("XXXXXXXXX"); // Obniz_ID に自分のIDを入れます const express = require('express'); const line = require('@line/bot-sdk'); const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', channelAccessToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' }; 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)); }); const client = new line.Client(config); // obniz接続 obniz.onconnect = async function () { obniz.display.clear(); obniz.display.print("obniz meets LINE Bot!"); } function handleEvent(event) { if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); } let mes = '' if(event.message.text === 'めざましかけて'){ mes = 'すこしまってね'; //メッセージだけ先に処理 getAskObnizSpeaker(event.source.userId); //スクレイピング処理が終わったらプッシュメッセージ }else{ mes = event.message.text; } return client.replyMessage(event.replyToken, { type: 'text', text: mes }); } const getAskObnizSpeaker = async (userId) => { // スピーカーを呼び出す const speaker = obniz.wired("Speaker", {signal:0, gnd:1}); console.log("Speaker") await client.pushMessage(userId, { type: 'text', text: "おはよう!きょうもがんばろう!", }); // 音階とhzの参考サイト https://tomari.org/main/java/oto.html // 「めざせポケモンマスター」 await speaker.play(880.000); // A5 ラ await obniz.wait(800); await speaker.stop(); await obniz.wait(80); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(1200); await speaker.stop(); await obniz.wait(500); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(880.000); // A5 ラ await obniz.wait(140); await speaker.stop(); await obniz.wait(80); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(880.000); // A5 ラ await obniz.wait(100); await speaker.stop(); await obniz.wait(80); await speaker.play(783.991); // G5 ソ await obniz.wait(1200); await speaker.stop(); await obniz.wait(600); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(880.000); // A5 ラ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(900); await speaker.stop(); await obniz.wait(300); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(140); await speaker.stop(); await obniz.wait(60); await speaker.play(659.255); // E5 ミ await obniz.wait(150); await speaker.stop(); await obniz.wait(80); await speaker.play(783.991); // G5 ソ await obniz.wait(900); await speaker.stop(); await obniz.wait(300); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(880.000); // A5 ラ await obniz.wait(140); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(150); await speaker.stop(); await obniz.wait(60); await speaker.play(880.000); // A5 ラ await obniz.wait(140); await speaker.stop(); await obniz.wait(60); await speaker.play(783.991); // G5 ソ await obniz.wait(600); await speaker.stop(); await obniz.wait(80); await speaker.play(1046.502); // C6 ド await obniz.wait(200); await speaker.stop(); await obniz.wait(80); await speaker.play(987.767); // B5 シ await obniz.wait(1200); await speaker.stop(); await obniz.wait(80); speaker.stop(); } app.listen(PORT); console.log(`ポート${PORT}番でExpressサーバーを実行中です…`); 結果 ~メロディー再生では起きず。でも、笑顔は達成!~ さっそく「目覚ましBot」を使ってみた結果、メロディー再生ではピクリとも動かず、いつも通りに名前を連呼しながら起こすことになりました。(わが子、手強いです) 実際に使ってみると、目覚ましの割にはボリュームが小さい点など、さっそく改善したい部分が見つかりました。 一方、寝起きには「これ、大好きな歌だ!」と反応していて、ミュウの画像やひらがなのメッセージを読んで、笑顔で目覚めることができました。ここは狙いどおりです! メロディーに慣れてきた場合、飽きてしまいそうなので、子どもが好きな曲のランダム再生などの機能が追加できたら面白そう・・・と新たな妄想が膨らみました。 今後は、一定時間になったら起動するタイマーやスヌーズ機能なども付けてみたいと思っています。 参考 ▶LINEでメッセージを送ると メロディを奏でるBOT【IoT連携】【LINE BOT】 ▶1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

zodを使ってJSON.parseしたオブジェクトをvalidationして型安全にしたい

やりたいこと JSON.parse(json)して得られたオブジェクトをTypescriptの型でバリデーションしたい なぜやりたいか APIなどからjson文字列を受け取る際、JSON.parse(json)のようにして文字列を解析してjavascriptのオブジェクトを構築しますが、このJSON.parseの返り値の型がanyなので、変数に代入する型をいくら指定してもしれっと代入可能になってしまいます。 そのため、↓のようなコードはコンパイルは通ってもランタイムでエラーになってしまいます。 type Post = { id: number title: string content: string } const post: Post = JSON.parse("{ id: 1, title: 'title' }") // JSON.parseの返り値がanyなので普通に代入できてしまう。 post.content.length // => contentはundefinedなのでerror せっかくTypescriptで型のある開発を満喫していても、anyの前にはすべてが崩壊します。 Typescriptは実行時の型情報の提供は目指していないので、Proposalな仕様であるdecorator等を使ってアノテーションを記載するか、それ以外の方法を使って実行時のvalidationに対応する必要があります。 Add or rely on run-time type information in programs, or emit different code based on the results of the type system. Instead, encourage programming patterns that do not require run-time metadata. やったこと validationライブラリであるzodを使って、JSON.parseしたオブジェクトをvalidationするサンプルコードを書きました。 zodとは typescript firstなvalidationライブラリです。類似のライブラリにyupやio-tsなどがありますが、Typescriptへの親和性や、重複するスキーマ・型宣言の排除を目標に様々な機能が設計されています。 使い方も非常にシンプルで、ファイルサイズもminifyされたファイルが8kbと非常に小さいのも良い点です。 また、Next.jsをラッパーしたフルスタックフレームワークで最近話題のblitz.jsのvalidationライブラリとして採用されていたりと、なかなか注目のライブラリとなっています。 zodの仕様については公式リポジトリか、こちらの記事が日本語で非常によくまとまっているので一度見てみてください。 実際のコード import { z } from 'zod' const User = z.object({ id: z.number(), name: z.string(), email: z.string().email() }) type User = z.infer<typeof User> const Post = z.object({ id: z.number(), title: z.string(), user: User }) type Post = z.infer<typeof Post> const validJson = JSON.stringify({ "id": 1, "title": 'title', "user": { "id": 1, "name": "name", "email": "email@email.com" } }) const invalidJson = JSON.stringify({ "id": 1, "title": 'title', "user": { "id": 1, // "name": "name", name should be required "email": "email@email.com" } }) try { const validPost: Post = Post.parse(JSON.parse(validJson)) console.log('validPost parse success') console.log(validPost) const invalidPost: Post = Post.parse(JSON.parse(invalidJson)) console.log('invalidPost parse success') // not run console.log(invalidPost) // not run } catch (e) { console.log(e) /** ZodError: [ { "code": "invalid_type", "expected": "string", "received": "undefined", "path": [ "user", "name" ], "message": "Required" } ] **/ } まず、以下のコードでvalidation schemaを定義しています。 const User = z.object({ id: z.number(), name: z.string(), email: z.string().email() }) 上記はオブジェクト型のschemaを定義していますが、もちろんプリミティブ型や、Typescriptで定義されているUtilityTypesライクな pick omit partialなど、他にも様々な便利な関数が定義されています。 ネストしたオブジェクトの型などももちろん柔軟に定義できます const Post = z.object({ id: z.number(), title: z.string(), user: User // 先程作成したvalidation schema }) 続いて、先程定義したvalidation schemaから型を生成するコードです type Post = z.infer<typeof Post> 型定義とvalidation schemaの定義が1度に行えるので、重複管理にならなくて嬉しいですね。 そして、実際に検証を行うコードは以下で、 parseに渡された引数を検証し、問題なければ Post型としてリターンします。 const validPost: Post = Post.parse(JSON.parse(validJson)) 検証に引っかかった場合はZodErrorオブジェクトがthrowされます try { const invalidPost = Post.parse(JSON.parse(invalidJson)) } catch (e) { console.log(e) /** ZodError: [ { "code": "invalid_type", "expected": "string", "received": "undefined", "path": [ "user", "name" ], "message": "Required" } ] **/ } parseを使わずsafeParse関数という使うと、throwされず、検証結果とデータ/エラーを返します。 Post.safeParse(JSON.pase(validJson)) // => { success: true; data: { // ... } } Post.safeParse(JSON.parse(invalidJson)) // => { success: false; error: ZodError } 以上で、実現したかったJSON.parseしたオブジェクトをvalidationして型安全にするという目的は達成できました。 型があるっていいですね。 終わりに 以下の記事でも書かれているように、ZodのSchemaと既存の型のダブルメンテ問題など実運用をする上での細かい対応や注意するべき点があったり、最新のver3は現在betaだったりと、全員に進められるものというわけではありませんが、個人的にAPIのシンプルさや設計思想はとても気に入っているので、継続して使っていきたいなと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

超リアルなザクを目指して!obnizでぐぽーんと音がしてモノアイが光るプロトタイプを作成!!

ぐぽーんと音がしてモノアイが光るのは男のロマン ガンダムの色んな作品でよく見かける演出として、 格納庫でスタンバってるMS(モビルスーツ)の目が「ぐぽーん」という音と共に光る というのがあります。(ザクやドムなどバリエーションも豊富) この演出、個人的に大好物なんですが、いつかこれをガンプラで再現したいなーと思っています。 今回は100均で見かけたおもちゃとIoT基盤「obniz」を組み合わせてプロトタイプを作ったので記事にしていきます。 完成品(ぐぽーんとなってモノアイ光るぜ) 実際に作ったものはこんな感じで動きます。 できた!(スピーカーのノイズが凄いとかLEDの赤がカメラ通すとピンクに見えるとかあるけど気にしない)#obniz pic.twitter.com/sQLUUQqyrz— shoito66 (@shoito66) May 15, 2021 作り方 用意する(した)もの ハードウェア ■obniz Board 1Y  制御の要となります。 ■赤色LED  抵抗内蔵のもの。モノアイに見立てて使います。 ■ブレッドボード  配線用。そのままだとLEDからobnizへの配線が厳しかったため。 ■Grove_MP3  グポーンという音を出すための装置。obnizから命令を送るとMP3ファイルを再生してくれます。 ■スピーカー  Grove_MP3に繋げて音を出してもらいます。今回はダイソーで300円のものを購入。 ■Keyestudio_Button  音と光を制御するためのボタン。INPUTになれば良いのでセンサーの類でも代用できます。 ■プチブロック ロボットシリーズ  ザクの代わりにするべくダイソーで購入。今回はスナイプをベースにナイトのパーツを少し混ぜてます。 ■適当な箱  作ったロボットと各種機器を固定するためのもの。ダイソーで購入。 ソフトウェア ■Node.js  obnizの制御に使いました。 組み立て ロボットはこんな感じで組み立てました。(LEDをモノアイ代わりにするので顔だけちょっと改造しています) 箱に穴をあけてブレッドボードと赤色LEDを取り付けます。 配線は穴を通して裏側へ。 裏側はこんな感じになってます。 (黒く塗りつぶしているのはobniz-IDを隠すためです。) 後は、LEDの位置に顔が来るようにロボットを配置して完了! 制御用プログラムを実行してボタンを押せばぐぽーんという音とともにモノアイが光ります! 制御用プログラム obnizの制御用コードは以下の通りです。 起動後、ボタンを押すとMP3の再生とLEDの点灯処理が実行されます。 (LEDは3秒後に消えるようにしています。) const Obniz = require('obniz'); const obniz = new Obniz('XXXX-XXXX'); // 自分のObniz_ID const sleep = (msec) => new Promise(res => setTimeout(res, msec)); obniz.onconnect = async function () { // MP3プレーヤーを利用 const mp3 = obniz.wired("Grove_MP3", { gnd: 0, vcc: 1, mp3_rx: 2, mp3_tx: 3 }); await mp3.initWait(); mp3.setVolume(20); // 赤色LEDを利用 const led = obniz.wired("LED", { anode: 5, cathode: 6 }); // 入力用にボタンを利用する const button = obniz.wired("Keyestudio_Button", {signal:9, vcc:10, gnd:11}); // ディスプレイ obniz.display.clear(); // クリア obniz.display.print('Ready!'); // ボタンが押されたら処理 button.onchange = async function (pressed) { if (!button.isPressed) { //ぐぽーんという音を再生 mp3.play(1); ///モノアイを点灯 led.on(); //3秒経ったらLEDをオフにする。 await sleep(3000); led.off(); } } } 補足(Grove_MP3の使い方) 今回、どうしても「ぐぽーん」が聞きたかったのでobnizでMP3ファイルを再生できる機器を探したところ、 公式ドキュメントで紹介されていたGrove_MP3に行きつきました。 ただ、こいつを使うまでに色々あったので補足しておきます。 そのままではobnizに接続できない。 Grove_MP3は名前の通り、Grove規格のコネクタを持っています。 当然、付属のケーブルもGrove規格のものなのですが、obnizはGrove規格のソケットを持っていないのでそのままだと接続できません。 なので、ケーブルを別途購入しました。 GROVE - 4ピン - ジャンパオスケーブル(5本セット) 使用できるのはマイクロSDカード(8GB以下のもの) obniz公式にSDカードという記載がありますが、実際にはマイクロSDカードを使うことになります。 容量も8GB以下しか使えないのでご注意を。 使用する際はマイクロSDカードに「MP3」というフォルダを作って「0001.mp3」みたいに数字4桁を頭につけたファイル名のMP3ファイルを格納しておけば再生できます。 プログラムの書き方 プログラム自体は以下のような形で記述します。 ※音量は明示的に設定しないと最大値で再生されるので注意 const mp3 = obniz.wired("Grove_MP3", { gnd: 0, vcc: 1, mp3_rx: 2, mp3_tx: 3 }); await mp3.initWait();//初期化 mp3.setVolume(20);//音量設定(0~31)※デフォルトは31 mp3.play(1);//MP3フォルダ内の「0001」から始まるMP3ファイルを再生 最後に 今回のプロトタイプ作成ではソフトウェアではなくハードウェアに力を入れました。 初心者なりにカッコいいものができたと満足しております。 次は実際にザクのプラモデルにLEDを仕込んで「ぐぽーん」やりたいですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ヘッドレストと頭の距離を計測して顔を画面へ突き出したら音で教えるobnizで首コリ頭痛を防ごう

こめかみが締め付けられるような頭痛があり、整体師さんから「首の上の筋肉まで固まってますね。」と首と頭の付け根に鍼を6本も打たれました。パソコン作業で顔を前に突き出す格好は首に負担がかかるのですが、集中するとついつい自覚なしにそんな態勢になってしまっています。なので、顔を画面へ突き出したらビープ音で警告してくれるシステムをobnizで作りました。 実際に動いているところの動画 椅子のヘッドレストの上にobnizを設置して、距離センサーで頭との距離を計測して、その値によってビープ音を鳴らします。(動画のビープ音は小さめですがそれなりの音が出ています) いつもの姿勢がセンサーから何㎝なのかを計測する 私の姿勢は下図のような感じですので、obnizからの計測値をconsoleに出しながら何㎝くらいが閾値として適正なのか見極めていきました。 改めて写真に撮ってみると頭(体重の10%)が重力に引かれるのに逆らう筋肉が姿勢によって異なりそう、というのがわかります。 席を立つときにOFF、席に戻ったらONは絶対運用しなくなる 当初想定していた「10㎝未満だと音が鳴らない。10㎝以上だと音が鳴る」という条件だと席から離れてもビープ音が鳴り続けてしまいます。「席を立つときにOFF、席に戻ったらONにする」という”運用でカバー”は絶対しなくなる自信があるので「50㎝以上だと音が鳴らない」というif文を追加しました。 物理法則には適わない。obnizが重力に負けて2回落ちる。 椅子がメッシュ生地なのでブレッドボードの粘着シールでは弱く、後傾姿勢になってから数分でモバイルバッテリーがobnizを巻き添えにして床に落ちました。それでモバイルバッテリーを落ちないように椅子に固定したのですがそれでもブレッドボードとobnizだけの重さで落ちました。(壊れなくて良かった…) 「魔法のテープ 極」という強力な両面テープを持っていたのでこれで固定しました。テグスがあればメッシュの隙間に通してブレッドボードを固定するのがいいかな、と思います。 意外と測定不能値が出るので1mm以上というif文を加える 当初はif文のelseでビープ音が鳴るようにしていたので計測不能値が出てもビープ音が鳴っていました。1秒単位で計測していると割と計測不能が出てしまうので「1mm以上を計測した場合はビープ音を鳴らす」というelse ifを追加して、elseでは音を鳴らさないようにしました。 環境 Node.js 15.12.0 npm 7.6.3 obniz Board 1Y 超音波距離センサー HC-SR04 圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0 コード distance_beep.js const Obniz = require('obniz'); const obniz = new Obniz('【各自のobniz ID】'); obniz.onconnect = async () => { // 超音波距離センサを利用 const hcsr04 = obniz.wired('HC-SR04', { gnd: 3, echo: 2, trigger: 1, vcc: 0, }); // スピーカーを利用 const speaker = obniz.wired('Speaker', { signal: 10, gnd: 11 }); // obnizディスプレイ(初期表示) obniz.display.clear(); obniz.display.print('obniz Ready'); // setIntervalで定期実行 setInterval(async () => { // 距離を取得 let distance = await hcsr04.measureWait(); // 小数点以下がたくさんあるのでここでは整数にします distance = Math.floor(distance); // 距離をコンソールに表示 console.log(distance + ' mm'); // 距離をobnizディスプレイに表示 obniz.display.clear(); obniz.display.print(distance + ' mm'); // 距離によって判定 if(distance > 500.0){ // 50cm より大きい場合、席を離れたと判断する。 obniz.display.clear(); obniz.display.print('Away From Keyboard.'); console.log('Away From Keyboard.'); // 音を停止する speaker.stop(); } else if (distance < 100.0) { // 10cm 未満の場合、良い姿勢と判断する。 obniz.display.clear(); obniz.display.print('Good!!'); console.log('Good!'); // 音を停止する speaker.stop(); } else if (distance > 1.0){ // 10cm 以上 50cm未満の場合、悪い姿勢を判断する。 // 計測不可時に音が鳴るのを防ぐため、1mm以上を条件としている。 obniz.display.clear(); obniz.display.print('Bad Posture!!'); console.log('Bad Posture!!'); // 100mm = 10cm を超えるときは300Hzで音を鳴らす speaker.play(300); }else { // 測定不可エラーの場合の処理 obniz.display.clear(); obniz.display.print('Error'); console.log('Error'); // 音を停止する speaker.stop(); } }, 1000); // 1000ミリ秒 = 1秒ごとに実行 }; おわりに コードとしては難しくないので簡単に完成までもっていけると目論んでいたのですが「椅子がobnizを粘着しにくい生地だったので固定部材を探す」「甲高いビープ音が家族に不評なので低い周波数に変える」など普段のソフト開発では気にしないところにハードを組み合わせた開発の難しさがあって新鮮でした。ハードいじりは楽しいですね。 ━-━-━-━-━-━-━-━-━-━-━-━-━━-━-━-━-━-━-━-━-━ 2021年4月からプロトアウト(プロトタイプ+アウトプット)スタジオに参加して、技術を学んだり自身を深掘りして卒業制作=クラウドファンディングのテーマを決めたりしています。 金融系SEという安定稼働を最優先にガチガチに設計書を作ってバグは許さぬ、という世界で十数年やってきました。自分の性格としても独創的なアイディア出しは苦手で、決まったことを正確に効率的にこなすことが得意です。 そんな私が無事クラウドファンディングに辿り着いて成功できるのか、見守っていただけましたら幸いです。 〇情報発信 ・自身とテーマ深掘り的な記事 → note ・開発中のつぶやき → Twitter
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

obnizで猫背になったら音が鳴る椅子を作って首コリ頭痛を防ぐ

前回の整体通院から1週間とたたずにこめかみが締め付けるような頭痛がしはじめ、整体師さんから「首の上の筋肉まで固まってますね。」と首と頭の付け根に鍼を6本も打たれたので、次の2週間後の整体までに頭痛を起こさないように猫背になったら音で注意してくれるシステムを作りました。 実際に動いているところの動画 椅子のヘッドレストの上にobnizを設置して、距離センサーで頭との距離を計測して、その値によってビープ音を鳴らします。(動画のビープ音は小さめかもしれません) いつもの姿勢がセンサーから何㎝なのかを計測する 私の姿勢は下図のような感じですので、obnizからの計測値をconsoleに出しながら何㎝くらいが閾値として適正なのか見極めていきました。 改めて写真に撮ってみると頭(体重の10%)が重力に引かれるのに逆らう筋肉が姿勢によって異なりそう、というのがわかります。 席を立つときにOFF、席に戻ったらONは絶対運用しなくなる 当初想定していた「10㎝未満だと音が鳴らない。10㎝以上だと音が鳴る」という条件だと席から離れてもビープ音が鳴り続けてしまいます。「席を立つときにOFF、席に戻ったらONにする」という”運用でカバー”は絶対しなくなる自信があるので「50㎝以上だと音が鳴らない」というif文を追加しました。 物理法則には適わない。obnizが重力に負けて2回落ちる。 椅子がメッシュ生地なのでブレッドボードの粘着シールでは弱く、後傾姿勢になってから数分でモバイルバッテリーがobnizを巻き添えにして床に落ちました。それでモバイルバッテリーを落ちないように椅子に固定したのですがそれでもブレッドボードとobnizだけの重さで落ちました。(壊れなくて良かった…) 「魔法のテープ 極」という強力な両面テープを持っていたのでこれで固定しました。テグスがあればメッシュの隙間に通してブレッドボードを固定するのがいいかな、と思います。 意外と測定不能値が出るので1mm以上というif文を加える 当初はif文のelseでビープ音が鳴るようにしていたので計測不能値が出てもビープ音が鳴っていました。1秒単位で計測していると割と計測不能が出てしまうので「1mm以上を計測した場合はビープ音を鳴らす」というelse ifを追加して、elseでは音を鳴らさないようにしました。 環境 Node.js 15.12.0 npm 7.6.3 obniz Board 1Y 超音波距離センサー HC-SR04 圧電スピーカー(圧電サウンダ)(13mm)PKM13EPYH4000-A0 コード distance_beep.js const Obniz = require('obniz'); const obniz = new Obniz('【各自のobniz ID】'); obniz.onconnect = async () => { // 超音波距離センサを利用 const hcsr04 = obniz.wired('HC-SR04', { gnd: 3, echo: 2, trigger: 1, vcc: 0, }); // スピーカーを利用 const speaker = obniz.wired('Speaker', { signal: 10, gnd: 11 }); // obnizディスプレイ(初期表示) obniz.display.clear(); obniz.display.print('obniz Ready'); // setIntervalで定期実行 setInterval(async () => { // 距離を取得 let distance = await hcsr04.measureWait(); // 小数点以下がたくさんあるのでここでは整数にします distance = Math.floor(distance); // 距離をコンソールに表示 console.log(distance + ' mm'); // 距離をobnizディスプレイに表示 obniz.display.clear(); obniz.display.print(distance + ' mm'); // 距離によって判定 if(distance > 500.0){ // 50cm より大きい場合、席を離れたと判断する。 obniz.display.clear(); obniz.display.print('Away From Keyboard.'); console.log('Away From Keyboard.'); // 音を停止する speaker.stop(); } else if (distance < 100.0) { // 10cm 未満の場合、良い姿勢と判断する。 obniz.display.clear(); obniz.display.print('Good!!'); console.log('Good!'); // 音を停止する speaker.stop(); } else if (distance > 1.0){ // 10cm 以上 50cm未満の場合、悪い姿勢を判断する。 // 計測不可時に音が鳴るのを防ぐため、1mm以上を条件としている。 obniz.display.clear(); obniz.display.print('Bad Posture!!'); console.log('Bad Posture!!'); // 100mm = 10cm を超えるときは300Hzで音を鳴らす speaker.play(300); }else { // 測定不可エラーの場合の処理 obniz.display.clear(); obniz.display.print('Error'); console.log('Error'); // 音を停止する speaker.stop(); } }, 1000); // 1000ミリ秒 = 1秒ごとに実行 }; 参考URL 肩こりがヤバイ人集まれ!指圧師が教えるラクな作業環境【リモートワーク】 おわりに コードとしては難しくないので簡単に完成までもっていけると目論んでいたのですが「椅子がobnizを粘着しにくい生地だったので固定部材を探す」「甲高いビープ音が家族に不評なので低い周波数に変える」など普段のソフト開発では気にしないところにハードを組み合わせた開発の難しさがあって新鮮でした。ハードいじりは楽しいですね。 ━-━-━-━-━-━-━-━-━-━-━-━-━━-━-━-━-━-━-━-━-━ 2021年4月からプロトアウト(プロトタイプ+アウトプット)スタジオに参加して、技術を学んだり自身を深掘りして卒業制作=クラウドファンディングのテーマを決めたりしています。 金融系SEという安定稼働を最優先にガチガチに設計書を作ってバグは許さぬ、という世界で十数年やってきました。自分の性格としても独創的なアイディア出しは苦手で、決まったことを正確に効率的にこなすことが得意です。 そんな私が無事クラウドファンディングに辿り着いて成功できるのか、見守っていただけましたら幸いです。 〇情報発信 ・自身とテーマ深掘り的な記事 → note ・開発中のつぶやき → Twitter
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsとReact.jsのプロジェクト作成から公開準備(※コーディングは含みません。)

Vue.jsとReact.jsのプロジェクト作成から公開準備 Javascriptで使用できるフロントエンド側のフレームワーク、VueとReactのプロジェクト作成コマンドを忘れないためと、ビルドしてからの流れについての説明が見当たらず、せっかく個人開発でやってみても誰にもリリースすることがないように記す。 なお、今回はそれぞれポートフォリオをフロントエンド側でのみ、作成したという程で作成しました。 動作環境 MacBook Air (Retina, 13-inch, 2018) BicSur 11.3.1 1.6 GHz Dual-Core Intel Core i5 6 GB 2133 MHz LPDDR3 Node.js v13.8.0 @vue/cli 4.5.13 各プロジェクトの作成 Vue.js vue create vue-portfolio React.js npx create-react-app react-portfolio インストール確認 Vue.js ..省略.. ? Successfully created project vue-portfolio. ? Get started with the following commands: $ cd vue-portfolio $ npm run serve React.js ..省略.. Success! Created react-portfolio at XXXXXXX/react-portfolio Inside that directory, you can run several commands: npm start Starts the development server. npm run build Bundles the app into static files for production. npm test Starts the test runner. npm run eject Removes this tool and copies build dependencies, configuration files and scripts into the app directory. If you do this, you can’t go back! We suggest that you begin by typing: cd react-portfolio npm start Happy hacking! インストール後のnpmサーバーを起動して画面の確認 Vue.js ■実行 cd vue-portfolio npm run serve ■結果 DONE Compiled successfully in 5762ms App running at: - Local: http://localhost:8080/ - Network: http://192.168.10.9:8080/ Note that the development build is not optimized. To create a production build, run npm run build. No issues found. ■画像 React.js ■実行 cd react-portfolio npm start ■結果 Compiled successfully! You can now view react-portfolio in the browser. Local: http://localhost:3000 On Your Network: http://192.168.10.9:3000 Note that the development build is not optimized. To create a production build, use npm run build. ■画像 いじる ※自分だけのポートフォリオを作成してください。  今回はわかりやすくトップページのみ日本語に変更をしていきます。 Vue.js .src/views/Home.vue <template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png"> <!-- <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/> --> <HelloWorld msg="ようこそ。あなたのVue.jsとTypeScript App"/> //上からの変更点 </div> </template> <script lang="ts"> import { defineComponent } from 'vue' import HelloWorld from '@/components/HelloWorld.vue' // @ is an alias to /src export default defineComponent({ name: 'Home', components: { HelloWorld } }) </script> React.js .src/App.js import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> {/* Edit <code>src/App.js</code> and save to reload. */} <code>src/App.js</code>を編集と保存して再読み込み。{/* 上の行を変更 */} </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App; ポートフォリオ公開準備 自分だけのポートフォリオを作成したら公開するために、ビルドを行なっていきます。 Vue.js STEP1:作成したコードをビルド 以下のコマンドを実行する npm run build STEP2:ビルド結果の確認 ビルド結果 「.dist」配下にビルドしたファイルが作成 DONE Compiled successfully in 11164ms File Size Gzipped dist/js/chunk-vendors.506821c6.js 118.83 KiB 42.80 KiB dist/js/app.67acf451.js 6.65 KiB 2.39 KiB dist/js/about.2b8983e6.js 0.34 KiB 0.26 KiB dist/css/app.aaf04fac.css 0.42 KiB 0.26 KiB Images and other types of assets omitted. DONE Build complete. The dist directory is ready to be deployed. INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html React.js STEP1:作成したコードをビルド 以下のコマンドを実行する npm run build STEP2:ビルド結果の確認 ビルド結果 「.build」配下にビルドしたファイルが作成 Compiled successfully. File sizes after gzip: 41.34 KB build/static/js/2.a9157932.chunk.js 1.63 KB build/static/js/3.4db56475.chunk.js 1.17 KB build/static/js/runtime-main.e0b02365.js 631 B build/static/js/main.5d1e222e.chunk.js 574 B build/static/css/main.9d5b29c0.chunk.css The project was built assuming it is hosted at /. You can control this with the homepage field in your package.json. The build folder is ready to be deployed. You may serve it with a static server: npm install -g serve serve -s build Find out more about deployment here: https://cra.link/deployment 作成したものをAWS S3へアップロードしてリリース ※AWSアカウントを持っている前提で記載しております。 共通 公式HPに公開方法が記載されております。 そのため掻い摘んで説明 STEP1:S3バケットの作成 サービス検索ボックスより「S3」と検索 右側オレンジボタンの「バケットを作成」をクリック STEP2:一般的な設定 バケット名は小文字英数字と半角記号のみで設定(※一意になるように命名) AWSリージョンについては今回はデフォルトのまま(アジアパシフィック(東京)ap-northeast-1) STEP3:このバケットのブロックパブリックアクセス設定 「パブリックアクセスをすべてブロック」のチェックを外す 「パブリックアクセスのブロックをすべてオフにすると、このバケットとバケット内のオブジェクトが公開される可能性があります。」の確認にチェックを入れる STEP4:バケットの作成 指定項目以外についてはデフォルトのまま 右下の「バケットを作成」をクリック STEP5:静的ウェブサイトホスティング設定 作成したバケットをクリック プロパティタブを選択 「静的ウェブサイトホスティング」の「編集」をクリック 「有効にする」にチェックを入れ「ホスティングタイプ」に「静的ウェブサイトをホストする」がチェック入っていること 「インデックスドキュメント」に「index.html」を入力 右下の「変更の保存」をクリック STEP6:バケットポリシー アクセス許可タブをクリック バケットポリシー欄の編集をクリック 以下の内容を入力し、["arn:aws:s3:::Bucket-Name/*"]部分の[Bucket-Name]をバケット名へ変更 右下の「変更の保存」をクリック { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": [ "s3:GetObject" ], "Resource": [ "arn:aws:s3:::XXXXXXXXX/*" ] } ] } STEP7:ビルドしたファイルのアップロード オブジェクトタブから「アップロード」をクリック 以下のファイルに対して、アップロードを行う Vueの場合は「.dist」配下のファイルすべて Reactの場合は「.build」配下のファイルすべて STEP8:外部ネットワークで確認 プロパティタブの「静的ウェブサイトホスティング」にある「バケットウェブサイトエンドポイント」をクリック アップロードした内容が閲覧できること 以上。 Appendix ?ビルドしたプログラムをすぐ見れない? VueもReactも共通してだが、ビルドされた「index.html」についてはサブディレクトリのままでは閲覧することができない。理由はビルド時にファイル内に記載される読み込みファイルが絶対パスのドメイン直下(ルートフォルダ)で記載がされているため、初心者はAWS S3などにあげて確認するほうがよい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelにReactとTypeScriptを導入する

前提 Laravelでプロジェクトを作成していて、nodeはインストール済みの想定で進めていきます。 TypeScriptをインストールする webpack.mix.js(webpackのラッパーライブラリ)を下記のように編集する mix.ts('resources/ts/index.tsx', 'public/js') .sass('resources/sass/app.scss', 'public/css'); 先ほどの編集内容を反映させる npm install プロジェクト内にnode_modulesディレクトリが作成されていればOK。 一旦下記コマンドでビルドする。 npm run prod package.jsonにwebpack.mix.jsで編集した内容の不足分が記載される(typescriptとsass) Reactをインストールする npm i -D react react-dom @types/react @types/react-dom npm install package.jsonに追記されているか確認する。 React用のTypeScriptの設定ファイルを作成する tsc --init --jsx react すると... tsconfig.jsonが作成される。 動作確認 ①webpack.mix.jsに記載した下記を作成する。 ■resources/ts/index.tsx import React from 'react' import ReactDOM from 'react-dom' const App = () => { return ( <h1>Laravel SPA</h1> ) } ReactDOM.render( <App />, document.getElementById('app') ) ■resources/sass/app.scss →resources/css/app.cssをリネームする ②下記コマンドでビルドする npm run prod ③resources/views/welcome.blade.phpをresources/views/index.blade.phpへリネームする 下記のように書き直す <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <link rel="stylesheet" href="{{ mix('/css/app.css') }}"> </head> <body> <div id="app"></div> </body> <script src="{{ mix('/js/index.js') }}"></script> </html> ④web.phpでrouteをwelcomeからindexへ変更する ⑤キャッシュ対策でファイルパスにパラメーターを付与する webpack.mix.jsに下記を追記する if (mix.inProduction()) { mix.version() } ⑥ビルトインサーバーを起動してlocalhost:8000へアクセスする php artisan serve 編集した内容が表示されていることを確認できました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む