先日 ウフルさんで行われた IoTパートナーコミュニティでの総会で、EnOceanを使った投票ボタンを作ったので、そちらの報告です
IoTパートナーコミュニティでの様子
EnOceanとは?
EnOceanとは光や温度、振動など比較的微弱なエネルギーを集めて電力に変換する環境発電技術を使った無線通信です
今回使ったオプテックス製 CSW-S2-Jは、ボタンを押したときの力で発電&電波発信をするという、電池レスな製品です。しかもIPX5と、生活防水にも耐えられるので、屋外でも使えてしまう、そんな製品です
システム構成と解説範囲
今回このブログで紹介するのは「責任分界点」の左側になります
右側は誰かが書いてくれることを期待しております
構成のポイント
- EnOceanパース&UDP送信をしている Node.js のコードをシンプルにする
- エッジに行けば行くほどコード変更コストが高いため。今回はエンドポイントURLが頻繁に変わるということもあり、書き換えされることが想定されていた
- リリース時(ボタンを離したとき)のデータを上位に送らないようにしている以外のロジックを入れていません
- 3Gでの送信には UDP を利用
- 要件的に、データ欠損が発生しても誰も死なない
- そもそも 3G/LTE通信は下のレイヤーの信頼性が高い
- データ量/料を削減するため
- UDP最大ペイロードサイズ 65KB 以内に収まるデータなのでフラグメント処理不要
- コードもシンプルにできる
- 要件的に、データ欠損が発生しても誰も死なない
コンポーネント解説
3G通信モデム AK-020 & Raspberry Pi 3
Raspbian上で setup_air.sh を実行すればセットアップできます
EnOcean受信USBモジュール USB400J
USB400J は UARTデバイスとして /dev/ttyUSB*
として見えます
後述する Node.js においては、このデバイスを指定するだけですので、簡単にEnOceanデバイスとの通信を実現することができます
EnOceanパース&UDP送信(Node.js)
/dev/ttyUSB*
で受信したEnOceanデータを解析して、UDPで送信します
構成のポイントでも説明しましたが、リリース時(ボタンを離したとき)のデータを上位に送らないようにしている以外のロジックは入れてません
var host = 'beam.soracom.io';
var port = 23080;
var enoceanPort = '/dev/ttyUSB4';
var enocean = require('node-enocean-utils');
enocean.teach({
'id' : '00 00 00 2C BC EB',
'eep' : 'F6-02-04',
'name': 'CSW-S2-J',
'manufacturer': 'OPTEX'
});
enocean.startMonitor({'path': enoceanPort});
enocean.on('data-known', (telegram) => {
var message = telegram['message'];
if (message['crc'] && message['value'].pressed != 0) {
var json = JSON.stringify(message);
console.log(json);
var dgram = require('dgram');
var client = dgram.createSocket("udp4");
client.send(json, 0, json.length, port, host, function(err) {
client.close();
});
}
});
IDやEEPの拾い方: 製品の裏面に書いてあります
ちなみに /dev/ttyUSB4
で狙い撃ちしているのは、後述の「ちょっと困っていること」に書いてあります
データ転送支援サービス / SORACOM Beam
SORACOM Beam を利用した理由は以下の通りです
課題
- enebular のエンドポイントが頻繁に変わる※
→ いちいち Node.js のコードは書き替えずにエンドポイントを切り替えたい - 通信量&料を削減するため※にUDPを採用
→ UDPなデータを安全な状態 かつ enebular で受信できるプロトコルに変換したい
これらの課題と要求を満たすために SORACOM Beam を使っています
※これは「テスト環境であるため」だからで、本番はそんなこと無いらしいです
※私個人のSIMなんで、懐具合も心配なんです
※この通信量だったら低トラヒック向け料金「Low Data Volume」で十分だった!そうすればもっと安くできたなー
実際の画面
SORACOM Air でつながったデバイスから udp://beam.soracom.io:23080
に送ると https://HOST:443/iotpc
にデータが送信されます
これならばエンドポイントが変更されてもこの画面上で変更が可能となります
SORACOM Beam から出力されるデータは下記のようなJSONとなります
{
"payload": "<BASE64 encoded 文字列>"
}
詳細は SORACOM Beam をご覧ください
責任分界点における開発の分担
SORACOM Beam から出力される JSON を双方で共有しておけば「こういうデータが来るはずだ」という共通認識のもとで開発可能です
そのため SORACOM Beam から出てくるJSON と、Base64 decodeした後のpayloadの二つを理解しておけばOKとなります
実際に使ったドキュメントはGoogle Driveで公開してますのでご自由にご覧下さい
ちょっと困ってること
USB400JとAK-020を同時に挿した状態で起動すると、AK-020が認識できないという現象に困っております
現在は AK-020 が認識できた後に USB400J を挿すといったworkaroundで対応してます
AK-020は /dev/ttyUSB[0-3]
を占有するため、 USB400J が必然的に /dev/ttyUSB4
となり、Node.jsでそれを見るようにしています
(超格好悪い)
原因は usbserial ドライバの認識順にありそうです
USB400Jは usbserial の ftdi_sio ドライバで動いているのですが、 AK-020 は usbserial の Generic なドライバで動きます。どうやら ftdi_sio のドライバが先にloadされると、Generic なほうがloadされないっぽいのです
ただ AK-020 は、最初にストレージデバイスとして認識されるタイプのデバイスであるため、それを解除→usbserialに切り替えている最中に、USB400Jが認識されてしまうという。
もう困った。
費用とか諸々
この構成、おおむね2日で作りました。費用については、判明している範囲で書いておきます
物品費用
価格(税抜&概算) | |
---|---|
CSW-S2-J | オプテックスさんにお問い合わせくださいー |
Raspberry Pi 3 Model B | 5600円 |
USB400J | 3780円 |
AK-020 | 4980円 |
SORACOM Air SIMカード (日本向け/データ通信) | 1313円 |
合計: 15673円 + CSW-S2-J
SORACOM費用
QTY | 価格(税抜) | |
---|---|---|
SORACOM Air SIM 基本料 | 1日 | 10円 |
SORACOM Air 通信量(上り) | 375KiB | 約0.11円 |
〃(下り) | 194KiB | 約0.18円 |
SORACOM Beam(UDP受信) | 239回 | 約0.21円 |
SORACOM Beam(HTTPS送信) | 239回 | 約0.21円 |
合計: 約11円
※Raspberry PiのNTPが結構な頻度で動いていることを忘れてしまい、下りの通信が発生してしまった。。。失敗失敗
※240回近くも押したのか。おまえら、押しすぎ
あとがき
そのあと、飲み会参加者の人数カウントにも使われたとさ。めでたしめでたし