- 投稿日:2020-07-28T23:30:04+09:00
Twitterでプチバズってたスマートロックをリスペクトを込めてobnizで再現してみた
まず最初にこのTwitterの投稿をご覧ください。
LINEで操作できるスマートロックのプロトタイプを弊社に実装した(製作7時間・材料費約3500円) pic.twitter.com/DHjcMkFvLS
— うこ (@ukokq) October 8, 2019
先日、このスマートロックの製作者うこさんのお話を聞く機会がありました。
今まで私は、スマートロックって、なんかスゴい仕組みでスゴいことやっていて私には関係ない世界かと思っていました。
それが、うこさんの作品では、まさかサーボモーターとダブルクリップで実現できていました。
目からウロコ、まさにコロンブスの卵でした。作ったもの
さっそく、リスペクトを込めて obnizで再現してみました。
私が作ったものはこちらです。【Qiita記事投稿しました】@ukokq さん製作のスマートロックを再現してみました。
— たつや (@tatsuya1970) July 28, 2020
〜『Twitterでプチバズってたスマートロックをリスペクトを込めてobnizで再現してみた』#obniz #protoout https://t.co/CIOZc8ZQET pic.twitter.com/SPzcyl5prr環境
Node 14.5.0
必要なもの
・obniz Board
・マイクロサーボ SG-5010
・ケーブル(オスーオス)
・ダブルクリップ (100円ショップで購入)
・タッパー (100円ショップで購入)
原理
ダブルクリップで錠のつまみを掴み、サーボモータでつまみを回して開閉します。
工程
構成図
コード
LINE BOT
linebot.js'use strict'; const request = require('request'); const express = require('express'); const line = require('@line/bot-sdk'); const PORT = process.env.PORT || 3000; const config = { channelSecret: 'channelSecret', channelAccessToken: 'channelAccessToken' }; const app = express(); app.post('/webhook', line.middleware(config), (req, res) => { console.log(req.body.events); Promise .all(req.body.events.map(handleEvent)) .then((result) => res.json(result)); }); const client = new line.Client(config); async function handleEvent(event) { //obnizクラウドへPOST const options = { url: "https://obniz.io/events/XXXX/ABCDEFGHIJKLMN/run", method: 'POST', form: {"order":event.message.text } } request(options, function (error, response, body) { console.log(body); }) //LINEチャットボットへ返信 return client.replyMessage(event.replyToken, { type: 'text', text: event.message.text //実際に返信の言葉を入れる箇所 }); } app.listen(PORT); console.log(`Server running at ${PORT}`);obnizクラウド
servo.js<!-- HTML Example --> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script> <script src="https://unpkg.com/obniz@3.7.0/obniz.js"></script> </head> <body> <div id="obniz-debug"></div> <h1>ServoMotor</h1> <script> const obniz = new Obniz("obniz ID"); obniz.onconnect = async function () { const servo = obniz.wired('ServoMotor', {gnd:0,vcc:1,signal:2}); obniz.display.clear(); // ディスプレイを一旦クリアする //ドアを開く if (req.body.order=="open") { obniz.display.print("OPEN"); servo.angle(0.0); } //ドアを閉める else if (req.body.order=="lock") { obniz.display.print("LOCK"); servo.angle(90.0); } } </script> </body> </html>はまったところ
pwmって何?
最初は obnizクラウドを利用せずに、LINEのチャットボットと「obniz+サーボモータ」を同じプログラム上で実行していました。
その場合、LINEで開閉(投稿)すると、毎回7回目に以下のエラーが出て途方にくれました。
UnhandledPromiseRejectionWarning: Error: No More pwm Available.
ある方から、このエラーは、サーボモータを動かすごとにpwmが消費され、最終的にpwmが枯渇したのではないかご指摘いただきました。
いろいろ試行錯誤して、最終的にはサーボモーターの処理をobnizクラウドに移したら、エラーが出なくなりました。
結局、pwmのことはよく分からず・・・obonizクラウドでのライブラリ?
Node.jsでは、post通信を受信するには、requestライブラリ、expressライブラリが必要ですが、obnizクラウドではその使い方がわからず、ハマりました。
結局は、req.body にpost通信されたものが入ってることに気がついて事なきを得ました。
そのあたりのことは、こちらをご参照ください。
サーバーレスイベントセットアップ(obniz公式)最後に
今回私が作ったスマートロックは、たまにエラーはないのに動かなくなるなど不安定です。
それにwifiに依存していること、電源をどうするかなど、実用化するにはまだまだです。ただ、自分がスゴいと思ったものを真似することで、多くのことを学びました。
お金をかけてなんかスゴいことをしなくても、おおげさにシステム開発しなくても、このように100円ショップで売っているものを有効活用する等のちょっとした工夫でスゴいものができるということを教えてもらいました。
※「ちょっとした」と言いましたが、実はその「ちょっとした」ことを思いつくのがとてもとても難しいです。コロンブスの卵の話のように。おかげさまで、物事を見る目、電子工作の幅が広がりました。
うこさん、ありがとうございました。
- 投稿日:2020-07-28T22:01:57+09:00
nuxt.js × firebase で画像保存処理実装してみた
使うもの
- nuxt.js
- firebase storage
今回実装するもの
- ローカルフォルダから画像を選択してfirebaseのstorageに保存する処理
- firebaseのstorageからデータを取得して画面上に表示する処理
コード
画像をfirebaseのstorageに保存
<!-- 画像を選択 --> <input type="file" @change="selectIcon">selectIcon (e) { // 選択した画像ファイルを取得 const file = e.target.files[0] // refの中身が保存する場所のpathになる const storageRef = firebase.storage().ref('images/sample.jpg') storageRef.put(file) }firebaseのstorageからデータを取得して画面上に表示
<!-- ここに表示する --> <img :src="icon">data () { return { icon: '' } }, methods: { async setIcon () { const storageRef = firebase.storage().ref() // childの中身にパスを指定してurlを取得する const url = await storageRef.child('images/sample.jpg').getDownloadURL() this.icon = url } }おまけ(画像選択してその場で表示する方法)
<img :src="icon"> <input type="file" @change="selectIcon">data () { return { icon: '' } }, methods: { selectIcon (e) { const file = e.target.files[0] const reader = new FileReader() reader.readAsDataURL(file) reader.onload = (e) => { this.icon = e.target.result } } }
- 投稿日:2020-07-28T01:35:26+09:00
SwaggerでLambdaのデバッグ環境を作る(7):AWS S3トリガをデバッグする
久しぶりの、SwaggerでLambdaのデバッグ環境を作る の拡張です。
第一回の投稿はこちらから:SwaggerでLambdaのデバッグ環境を作る(1)AWS S3にファイルがアップロードされたときにLambdaを起動するスクリプトを書こうと思っても、Lambda上でのデバッグは大変なので、ローカルでデバッグ(実行中のブレイクを入れたり、変数を参照したり)できるようにします。
S3は、本物ではなく、S3互換のMinIOを使います。
今回のローカルデバッグ環境は以下のGitHubに反映済みです。
poruruba/swagger_template
https://github.com/poruruba/swagger_templateMinIOのセットアップ
ほぼこちらに書いてある通りに進めます。
MinIO Quickstart Guide
https://docs.min.io/今回は、Distributed MinIO Quickstart Guideを採用しています。
まずは、wgetでバイナリファイルをダウンロードして、/usr/local/binにコピーします。
> wget https://dl.min.io/server/minio/release/linux-amd64/minio > chmod +x minio > cp minio /usr/local/bin > wget https://dl.min.io/client/mc/release/linux-amd64/mc > chmod +x mc > cp mc /usr/local/binminioがMinIO本体です。mcはMinIO Clientと呼ばれるもので、MinIOサーバの設定をしたり、ファイルをアップしたりするクライアントツールです。
次にMinIO用のフォルダを作成します。
> mkdir /opt/minio > mkdir /opt/minio/conf > mkdir /opt/minio/data次に、自動起動用の設定をします。systemdを使います。
vi /etc/systemd/system/minio.service
/etc/systemd/system/minio.service[Unit] Description=minio Object Storage Service After=network.target [Service] Type=simple EnvironmentFile=/opt/minio/conf/env.conf ExecStart=/usr/local/bin/minio server /opt/minio/data Restart=on-abort WorkingDirectory=/opt/minio/ [Install] WantedBy=multi-user.targetMinIOを起動するには、以下の環境変数を指定する必要があります。
vi /opt/minio/conf/env.conf
/opt/minio/conf/env.confMINIO_ACCESS_KEY=admin MINIO_SECRET_KEY=[ブラウザ用パスワード]上記の[ブラウザ用パスワード]を秘匿の値に書き換えてください。後で使います。
ちなみに、また、もしいったん上記で稼働させた後変更したい場合には以下のように書き換えて、MinIOを再起動します。
vi /opt/minio/conf/env.conf
/opt/minio/conf/env.confMINIO_ACCESS_KEY=admin MINIO_SECRET_KEY=[新ブラウザ用パスワード] MINIO_ACCESS_KEY_OLD=admin MINIO_SECRET_KEY_OLD=[旧ブラウザ用パスワード]これで準備ができました。以下の通りに実行します。
> systemctl daemon-reload > systemctl start miniodaemon-reloadは、minio.serviceを変更した場合にのみ必要です。
起動できたかどうかは以下で確認します。> systemctl status minio ● minio.service - minio Object Storage Service Loaded: loaded (/etc/systemd/system/minio.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2020-07-28 00:16:07 JST; 4s ago Main PID: 29514 (minio) Tasks: 13 (limit: 4264) CGroup: /system.slice/minio.service mq29514 /usr/local/bin/minio server /opt/minio/data ・・・PC再起動でも自動起動させたい場合は以下を実行します。
> systemctl enable minio最後に、mc(MinIO用クライアントツール)から操作できるように、このMinIOサーバの情報を登録します。
> mc config host add [MinIOの名前] http://[MinIOのホスト名]:9000 admin [ブラウザ用パスワード] > mc admin config set [MinIOの名前] region name="[リージョン名]" > systemctl restart minio[MinIOの名前]は覚えやすい適当な名前を付けてください。FQDNである必要はありません。
リージョン名も適当に入れてください。本物の場合の「ap-northeast-1」に相当します。触ってみる
まずは、ブラウザで覗いてみましょう。ポート番号は9000です。
http://[MinIOのホスト名]:9000
Access KeyにMINIO_ACCESS_KEYに指定したadminを、Secret KeyにMINIO_SECRET_KEYに指定した[ブラウザ用パスワード]を指定します。
さっそく、バケットを作ってみます。
右下の+ボタン→ Create bucket を押して出てくる小さなダイアログボックスで、任意のバケット名を入れると、バケットが出来上がります。
適当に、「testbucket」という名前のバケットを作っておきます。今度は、Node.jsで、AWS SDKを使ってファイルをアップロードしたりダウンロードしたりしてみましょう。
> mkdir s3_test > cd s3_test > npm init -y > npm install aws-sdk
vi index.js
index.jsvar AWS = require('aws-sdk'); var s3 = new AWS.S3({ accessKeyId: 'admin' , secretAccessKey: '[ブラウザ用パスワード]', endpoint: 'http://[MinIOのホスト名]:9000', s3ForcePathStyle: true, // needed with minio? signatureVersion: 'v4' }); const BucketName = '[バケット名]'; const FileName = 'test.txt'; // putObject operation. var put_params = { Bucket: BucketName, Key: FileName, Body: 'Hello from MinIO!!' }; s3.putObject(put_params, (err, data) => { if (err){ console.log(err) return; } console.log('Successfully uploaded data to ' + BucketName + '/' + FileName); // getObject operation const fs = require('fs'); var fileStream = fs.createWriteStream(FileName); var get_params = { Bucket: BucketName, Key: FileName }; var s3Stream = s3.getObject(get_params).createReadStream(); s3Stream.on('error', function(err) { console.error("s3Stream Error:", err); }); s3Stream.pipe(fileStream).on('error', (err) => { console.error('fileStream Error:', err); }).on('close', () => { console.log('Done.'); }); });実行します。
> node index.js Successfully uploaded data to testbucket/test.txt Done.ブラウザを覗くと、test.txtがアップロードされているのがわかるかと思います。
ローカルデバッグ環境の準備
今度は、MinIOにファイルがアップされたらローカルデバッグ環境のNode.jsが起動するようにします。要は、AWSのS3にファイルがアップされたらLambdaを起動させることのエミュレートです。
api\controllers\
に以下のファイルを配置します。head.js'use strict'; /* append to swagger.yaml head: x-swagger-router-controller: head operationId: s3 responses: 200: description: Success */ function s3(req, res) { console.log("[HEAD] head_s3 called"); res.json({}); } module.exports = { s3: s3 };次に、通知を受けたいエンドポイントのHEADメソッドに、このファイルが呼ばれるように
api\swagger\swagger.yaml
を編集します。
以下は、/test-s3 という[エンドポイント名]に通知が来るようにする例です。api\swagger\swagger.yaml・・・ /test-s3: head: x-swagger-router-controller: head operationId: s3 responses: 200: description: Success ・・・ローカルのデバッグ環境を立ち上げます。
次に、この通知を受けるサーバのエンドポイントをMinIOサーバに登録します。> mc admin config set [MinIOの名前] notify_webhook:1 queue_limit="0" endpoint="[通知を受けるサーバのURL]/[エンドポイント名]" queue_dir="" > systemctl restart minio > mc event add [MinIOの名前]/[バケット名] arn:minio:sqs::1:webhook --event put --suffix .[拡張子名]今回は拡張子として、.txtとします。
上記を設定すると、通知を受け付けるサーバに、以下のようにHEADメソッドが飛んできているのがわかります。[HEAD] head_s3 called [HEAD] head_s3 called次に、実際にトリガを受け付けるLambdaに相当するNode.jsを作成します。
まずは、swagger.yamlを以下のように編集します。
api\swagger\swagger.yaml・・・ /test-s3: post: x-swagger-router-controller: routing operationId: test-s3 parameters: - in: body name: body schema: $ref: "#/definitions/CommonRequest" responses: 200: description: Success schema: $ref: "#/definitions/CommonResponse" head: x-swagger-router-controller: head operationId: s3 responses: 200: description: Success ・・・headはさきほど追加したので、今回は実際のPOSTメソッドを宣言しています。
Node.jsのソースは以下の感じです。これが今回デバッグしたかった主役のソースファイルです。api/controllers/test-s3/index.js'use strict'; exports.handler = async (event, context, callback) => { console.log(event); };function.jsに宣言も追記しておきます。
api\controllers\functions.js・・・ const alexa_table = { // "test-alexa" : require('./lambda/test_alexa').handler, // "test-clova": require('./test-clova').handler, // "test-s3": require('./test-s3').handler, "test-s3": require('./test-s3').handler, };ローカル実行環境を再起動して、もう一度ファイルをアップロードしてみましょう
> node index.jsそうすると、こんな感じで、トリガを受け取れました。
もちろん、Node.jsのソースファイルにブレイクを入れることもできます。
以上