まだプログラマーですが何か?

プログラマーネタとアスリートネタ中心。たまに作成したウェブサービス関連の話も http://twitter.com/dotnsf

スマホのブラウザで touchstart や touchmove、touchend イベントなどを監視することで各種タッチ処理やドラッグ、そしてスワイプといった操作を感知して処理することができます。

が、これらを使ってスワイプ(横にスライドさせるような処理)を感知しようとすると結構面倒だったりします。機種ごとの機能差についてはもちろんのこと、touchstart 時の指の場所と時間を記憶して、touchend 時の指の場所と時間を記憶し、「一定時間以内にほぼ横向きに指が移動した」ことを検知できればスワイプとみなす、といった具合に処理するわけですが、この「一定時間以内」とか、「ほぼ横向き」とか、厳密に処理するわけにもいかず、かと言ってどの程度の猶予をもたせて判断するべきか迷う要素もあったりするわけです。

そんなスワイプ処理を比較的簡単にハンドリングできるのが jQuery Mobile 内の1ファンクションである jQuery Swipe です:
2019031100


実際に jQuery Swipe を使ってスワイプ判断をするサンプルを用意しました:
<html>
<head>
<meta charset="utf8"/>
<title>swipe</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>

<script>
$(function(){
  $('#myimg').on( 'swipe', mySwipeHandler );
  function mySwipeHandler( evt ){
    alert( '#myimg swiped.' );
  }
});
</script>
</head>
<body>
<img src="https://2.bp.blogspot.com/-hvxUlVBfZUI/XG4Ga7pkzxI/AAAAAAABRrE/Q2vhHjh76T8tFTyZ7D8fFE3MCQMqiKIVgCLcBGAs/s450/champion_belt_boxing_man.png" id="myimg" width="50%"/>
</body>
</html>

HTML はシンプルに(いらすとやの)画像を1つ画面に配置しているだけです。その画像に 'swipe' イベントが発生した場合に '#myimg swiped' という警告ダイアログが表示される、というものです。jQuery と jQuery Mobile は CDN を使ってロードしています。

このコードの肝になっているのはこの部分です:
  $('#myimg').on( 'swipe', mySwipeHandler );

'#myimg' は画像に付けられた id を指定しています。つまり画像に 'swipe' イベントが発生したら mySwipeHandler 関数を実行する、という指定をしています(そして mySwipeHandler 関数では警告ダイアログが表示されます)。

この 'swipe' イベントはデフォルトだと以下の条件で発生します:
条件デフォルト値カスタマイズする場合の設定箇所
スワイプにかかる時間1000ms$.event.special.swipe.durationThreshold
横方向の移動ピクセル30ピクセル以上$.event.special.swipe.horizontalDistanceThreshold
縦方向の移動ピクセル30ピクセル以内$.event.special.swipe.verticalDistanceThreshold


つまりデフォルトではタッチ開始から終了(指を離す)まで1秒以内で、縦方向には30ピクセル以内の移動で横方向に30ピクセル以上移動するようなスワイプが発生した時に 'swipe' とみなし、そのイベントを発生させる、というものになります。変更したい場合は上述箇所を書き換えてください。


このページをアップロードし、スマホから表示するとこんな感じになります:
2019031101


イラスト部分を右や左にスワイプするとイベントが発生して、警告メッセージが表示されます:
2019031102


iPhone でも Android でも動いて楽ちん。もちろん画像以外の <div> などのパーツにも使えます。

なお、今回のサンプルでは jQuery 2.0.3 と  jQuery Mobile 1.4.5 を使っています。jQuery は 2.x であれば動くようですが、3.x だとエラーになるっぽいです(ここになかなか気づけずハマりました):
https://stackoverflow.com/questions/40172264/jquery-swipe-event-does-not-work-with-jquery-3

業務で「リモート操作で扉の鍵を施錠/解錠する」必要があり、いろいろ調査した結果 Akerun という入退室管理システムを使ってみました。その様子をメモ目的でブログにしました。
2019030400


扉の鍵をリモート操作で開ける、という需要はあると思っています。特定の条件を満たす人だけが入れる部屋を作りたい(そのためのロジックを加えて実装したい)とか、締め忘れて外出してしまった可能性のある家の扉の鍵をいま居る場所から施錠したいとかです。

で、いくつか調べてみました。Bluetooth や NFC などを使って比較的近い距離間で通信できるものは多く提供されているようでしたが、現在 REST API を使って離れた場所からも操作できるもの、となると(2019年2月に私が探した限りで※)株式会社フォトシンスから提供されている Akerun (Pro) という製品だけのようでした。

※他に探した範囲では REST API が提供されていなかったり、以前は提供されていたが現在は提供されていなかったり、日本向けの情報が提供されておらずそもそも日本で入手できるのか不明だったり・・・という結果でした。

なお、Akerun 自体には(買い取り式の)個人向け製品も存在しているのですが、REST API が提供されているのは業務用の Akerun Pro という月次レンタル製品のみとのことでした。気軽に使ってみるにはちとハードルが高いかもしれないと感じたのと、それ故かあまり技術情報をウェブで見かけることがあまりありませんでした。そんな背景もあって今回ブログで紹介しようかな、と思い立ったのでした。


【システム構成】
まず Akerun Pro を使った今回のシステム構成はこんな感じになります:
2019022601


Akerun(今回利用するのは正確には "Akerun Pro" ですが、以下 "Akerun" と表記します)は既存のドアに設置可能なデバイスです。外部から信号を送ってドアのサムターン部分を回して解錠/施錠します(要はサムターンが回せる位置に Akerun を取り付けて使う、というものです)。実際には NFC などのカードを使って開閉することもできます(注 Akerun Pro では一式揃っています)が、今回は使いません。

特に REST API でリモート操作する場合は、Akerun デバイスに加えて Akerun Remote と呼ばれるインターネットとのルーターとなるデバイスを追加設置します(Akerun Remote も Akerun Pro に含まれています)。上図のように Akerun と Akerun Remote は Bluetooth で接続されます。Akerun Remote は有線または無線LANでインターネットに接続します(私は WiFi テザリングで試しました)。無線 LAN の設定等はスマホ用の専用アプリを使って Akerun Remote に設定することができます。

このようにして Akerun Remote をインターネットに接続した後は管理用画面や API を使って解錠/施錠の指示を出すことができるようになります。それらの指示はインターネットを経由して Akerun Remote へ伝わり、Akerun Remote から Akerun へ Bluetooth による指示が送られてサムターンが(指示されたように)動く、というものです。


【準備】
API の使用は申込み制となっていて、こちらのページ内の「こちらのお申込みフォーム」と書かれたリンクから申し込みを行う必要があります:
https://developers.akerun.com/#introduction

申込時に名前やメールアドレス、電話番号等を登録していくのですが、 OAuth 認証のリダイレクト URI を指定する箇所があります:
2019022602

 
この URI は実在している必要はないのですが、実在しない場合はエラー時にリダイレクトされない URI である必要があります(OAuth リダイレクト時のパラメーターを受け取る必要があるため、実在しない場合でもパラメータを保持した URI でエラー表示される必要があります)。また https:// の URI である必要がある点に注意が必要です。ここで指定した URI は後で使うのでメモしておきましょう。ここでは仮に https://myapp_for_akerun.mybluemix.net/callback という URI を指定したものとして以下を紹介します。

申し込みの手続きが完了すると(数日後に) OAuth 認証用の client_id と client_secret が記載されたメールが送信されてきます。ここでは仮に
 client_id: "my_client_id"
 client_secret: "my_client_secret"
という値が送られてきたものと仮定して以下を紹介します(実際にはランダムな文字列です)。

ここまで完了するとアクセストークンの発行ができるようになります。


【アクセストークンの取得】
ウェブブラウザで以下の URL にアクセスします:
https://api.akerun.com/oauth/authorize/?client_id=(送られてきた client_id の値)&redirect_uri=(申込時に指定したリダイレクト URI の値)&response_type=code

上記の前提であれば、具体的には以下の URL となります:
https://api.akerun.com/oauth/authorize/?client_id=my_client_id&redirect_uri=https://myapp_for_akerun.mybluemix.net/callback&response_type=code


正しい値が指定されていると redirect_uri のアドレスにリダイレクトされます。その時の URI に code 
というパラメータが付与されているので、この値を取り出します。例えばリダイレクト先が
 https://myapp_for_akerun.mybluemix.net/callback?code=XXXXXXXXXX
という URI であれば、XXXXXXXXXX 部分が該当します。この値を code 値として以下を続けます(code 値は取得から 30 分間有効なので、取得から 30 分以内に以下のアクセストークンの取得を行ってください)。

取得した code 値と HTTP POST を実行できるツール(curl など)を使って、以下の HTTP POST リクエストを実行します(実際には改行せず一行で入力します):
$ curl -X POST "https://api.akerun.com/oauth/token"
  -d grant_type=authorization_code
  -d client_id=(client_id の値)
  -d client_secret=(client_secret の値)
  -d code=(code の値)
  -d redirect_uri=(申込時に指定したリダイレクト URI の値)



上記までに取得した例の場合だと、このような(一行の)リクエストになります:
$ curl -X POST "https://api.akerun.com/oauth/token"
  -d grant_type=authorization_code
  -d client_id=
my_client_id
  -d client_secret=
my_client_secret
  -d code=XXXXXXXXXX
  -d redirect_uri=
https://myapp_for_akerun.mybluemix.net/callback


成功すると以下のような JSON がレスポンスとして返されます:
{
  "access_token": "**********",
  "token_type": "bearer",
  "refresh_token": "xxxxxxxxxx.....",
  "expires_in": 7776000,
  "created_at": 1500853017
}



この結果の "access_token" の値(********** 部分)がアクセストークンです。


【REST API の実行】
ここまでの手順でアクセストークンが取得できていれば、その値を HTTP リクエストヘッダを使って、
 Authorization: Bearer (アクセストークンの値)

のように指定して、各種 REST API を実行することができるようになります。例えばアクセストークンのオーナーが所属する組織 ID の一覧は GET https://api.akerun.com/v3/organization で取得できるのですが、このリクエスト時に
 Authorization: Bearer **********
という HTTP リクエストヘッダを付与することで正しい権限で実行できます。

例えば組織 ID : OOO1、アケルン ID : AAA1 の鍵をリモートで解錠するには、以下の HTTP リクエストを発行します:
$ curl -X POST "https://api.akerun.com/v3/organizations/OOO1/akeruns/AAA1/jobs/unlock"
  -H "Authorization: Bearer **********"



同様にして、同じ鍵をリモートで施錠する場合は以下になります:
$ curl -X POST "https://api.akerun.com/v3/organizations/OOO1/akeruns/AAA1/jobs/lock" 
  -H "Authorization: Bearer **********"




なお、開発者向けの API 情報はこちらです:
https://developers.akerun.com/#introduction


1つの Node-RED 環境に普通に複数人がアクセスすると同じ環境を使うことになります。これを複数人で、それぞれ個人ごとの環境で(個人ごとにフローを保存したりして)使う方法です。

Node-RED をインストールした後、通常だと以下のような node-red コマンドで Node-RED を起動します(青字は起動メッセージ)。この例だと 1880 番ポートで待ち受け状態になっています:
$ node-red

13 Feb 08:55:02 - [info]

Welcome to Node-RED
===================

13 Feb 08:55:02 - [info] Node-RED バージョン: v0.19.5
13 Feb 08:55:02 - [info] Node.js  バージョン: v6.11.2
13 Feb 08:55:02 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 08:55:03 - [info] パレットノードのロード
    :
    :
13 Feb 08:55:03 - [info] フローを開始します
13 Feb 08:55:03 - [info] フローを開始しました
13 Feb 08:55:03 - [info] サーバは http://127.0.0.1:1880/ で実行中です

この node-red コマンドにパラメータを渡して実行環境をカスタマイズすることができます。例えば以下のような settings1.js ファイルを用意します(実行ポート番号を 1881 に指定しています):
module.exports = {
  uiPort: 1881
}

更に自分のフローを保存するためのフォルダ(~/tmp/userDir1)を作っておきます:
$ mkdir -p ~/tmp/userDir1

この状態から以下のようにパラメータを指定して node-red を実行します(青字は起動メッセージ):
$ node-red -s settings1.js -u ~/tmp/userDir1

13 Feb 09:04:35 - [info]

Welcome to Node-RED
===================

13 Feb 09:04:35 - [info] Node-RED バージョン: v0.19.5
13 Feb 09:04:35 - [info] Node.js  バージョン: v6.11.2
13 Feb 09:04:35 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 09:04:35 - [info] パレットノードのロード
    :
    :
13 Feb 09:04:36 - [info] サーバは http://127.0.0.1:1881/ で実行中です
13 Feb 09:04:36 - [info] フローを開始します
13 Feb 09:04:36 - [info] フローを開始しました

今回は 1881 番ポートで Node-RED が起動しています。またここで記録したフローは ~/tmp/userDir1 内に保存されます:
2019021301


同様にして settings2.js ファイルと ~/tmp/userDir2 フォルダを作り、これらをパラメータ指定して起動すると、異なるポートで異なる記録フォルダを持つ Node-RED が(もう1つ)起動できます:
$ cat settings2.js
module.exports = {
  uiPort: 1882
}

$ mkdir -p ~/tmp/userDir2

$ node-red -s settings2.js -u userDir2
13 Feb 09:11:15 - [info]

Welcome to Node-RED
===================

13 Feb 09:11:15 - [info] Node-RED バージョン: v0.19.5
13 Feb 09:11:15 - [info] Node.js  バージョン: v6.11.2
13 Feb 09:11:15 - [info] Linux 4.4.0-121-generic x64 LE
13 Feb 09:11:15 - [info] パレットノードのロード
    :
    :
13 Feb 09:11:16 - [info] フローを開始します
13 Feb 09:11:16 - [info] フローを開始しました
13 Feb 09:11:16 - [info] サーバは http://127.0.0.1:1882/ で実行中です


フローの記録フォルダも別々に指定しているので、一方でフローを作成済みであっても他方には影響しません:
2019021302


同様にして3人以上で利用する場合もそれぞれの settingsXX.js とフロー用フォルダを作成し、それらを指定して起動することで複数人が別環境の Node-RED を使うような感じで1サーバー内の Node-RED を使うことができるようになります。まあ充分なディスクとメモリ、CPU があれば、という前提ですけど。


Node-RED の設定ファイルでカスタマイズできる内容と指定方法についてはこちらを参照ください:
https://nodered.jp/docs/configuration

なお、今回のように起動ポートとフロー保存フォルダを指定するだけであれば、settingsXX.js ファイルを用意する必要はなく、Node-RED 起動時のコマンドラインから以下のように(-p で起動ポートも)指定することができます。ただカスタマイズの範囲をどこまでにするかによっては設定ファイルを用意した方が便利だとは思っています:
$ node-red -p 1881 -u ~/tmp/userDir1






このページのトップヘ