20200728のNode.jsに関する記事は3件です。

Twitterでプチバズってたスマートロックをリスペクトを込めてobnizで再現してみた

まず最初にこのTwitterの投稿をご覧ください。



先日、このスマートロックの製作者うこさんのお話を聞く機会がありました。
今まで私は、スマートロックって、なんかスゴい仕組みでスゴいことやっていて私には関係ない世界かと思っていました。
それが、うこさんの作品では、まさかサーボモーターとダブルクリップで実現できていました。
目からウロコ、まさにコロンブスの卵でした。

2020-07-28 23.00.26.png

作ったもの

さっそく、リスペクトを込めて obnizで再現してみました。
私が作ったものはこちらです。

環境

Node 14.5.0

必要なもの

obniz Board
マイクロサーボ SG-5010
・ケーブル(オスーオス)
・ダブルクリップ (100円ショップで購入)
・タッパー (100円ショップで購入)
IMG_7032.jpeg

原理

ダブルクリップで錠のつまみを掴み、サーボモータでつまみを回して開閉します。
2020-07-28 22.04.42.png

工程

錠にタッパーを合わせ、
IMG_7036.jpeg

ダブルクリップで錠のつまみを掴んで、タッパーをかぶせます
IMG_7031.jpeg

横から見た構図
IMG_7041.jpeg

構成図

scheme.png

コード

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円ショップで売っているものを有効活用する等のちょっとした工夫でスゴいものができるということを教えてもらいました。
※「ちょっとした」と言いましたが、実はその「ちょっとした」ことを思いつくのがとてもとても難しいです。コロンブスの卵の話のように。

おかげさまで、物事を見る目、電子工作の幅が広がりました。

うこさん、ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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_template

MinIOのセットアップ

ほぼこちらに書いてある通りに進めます。

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/bin

minioが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.target

MinIOを起動するには、以下の環境変数を指定する必要があります。

vi /opt/minio/conf/env.conf

/opt/minio/conf/env.conf
MINIO_ACCESS_KEY=admin
MINIO_SECRET_KEY=[ブラウザ用パスワード]

上記の[ブラウザ用パスワード]を秘匿の値に書き換えてください。後で使います。

ちなみに、また、もしいったん上記で稼働させた後変更したい場合には以下のように書き換えて、MinIOを再起動します。

vi /opt/minio/conf/env.conf

/opt/minio/conf/env.conf
MINIO_ACCESS_KEY=admin
MINIO_SECRET_KEY=[新ブラウザ用パスワード]
MINIO_ACCESS_KEY_OLD=admin
MINIO_SECRET_KEY_OLD=[旧ブラウザ用パスワード]

これで準備ができました。以下の通りに実行します。

> systemctl daemon-reload
> systemctl start minio

daemon-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

image.png

Access KeyにMINIO_ACCESS_KEYに指定したadminを、Secret KeyにMINIO_SECRET_KEYに指定した[ブラウザ用パスワード]を指定します。

image.png

さっそく、バケットを作ってみます。
右下の+ボタン→ Create bucket を押して出てくる小さなダイアログボックスで、任意のバケット名を入れると、バケットが出来上がります。
適当に、「testbucket」という名前のバケットを作っておきます。

今度は、Node.jsで、AWS SDKを使ってファイルをアップロードしたりダウンロードしたりしてみましょう。

> mkdir s3_test
> cd s3_test
> npm init -y
> npm install aws-sdk

vi index.js

index.js
var 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

そうすると、こんな感じで、トリガを受け取れました。

image.png

もちろん、Node.jsのソースファイルにブレイクを入れることもできます。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む