Webエンジニアです。
突然ですが、KDDIさんから、LTE-M Leafというモノをお借りしました。
なんと、SORACOM のSIM とセットで。ありがとうございます!
前回、STM32を使ったLチカ をやったのは、この LTE-M Leafが使いたかったからなんですね。
今回はようやく本番。LTE-M Leaf を使ったプロトタイピングに挑戦してみようと思います。
LTE-M Leaf とは?
KDDI製のLTE-M通信用のモジュールです。
LeafonyにLTE-Mを使ったセルラー通信機能を追加できます。
2枚セットですが、どうやら下記が正式名称のようです。
ただ残念なことに、まだ一般販売はされていません。
トリリオンノード研究会のサイトを見ると、会員向けに貸し出しをおこなっているようです。
https://trillion-node.org
ところで、LTE-M とは?
こちらの記事の説明を読めばバッチリです!
https://time-space.kddi.com/ict-keywords/kaisetsu/20171116/2163
開発情報
今回お借りしたのは、Ver.4 という最新バージョンです。
小型で他のLeafonyと組み合わせやすくなっています。
インターネットを検索すると、1つ前のVer.の情報が結構見つかりますが、形が全く違うので惑わされないようにしましょう。
例: https://trillion-node.org/developers/20201209-01/
先ほどの製品情報を中心に、下記情報が見つかりました。
- AC04 LTE-M King M (LTE-M通信用のリーフ)
- AC05 LTE-M King S (AC04専用の電源用リーフ)
- LTE-Mを使ったIoTサービス
- LTE-M Leaf V4用ライブラリ
回路(特にバスの配線周り)と、ライブラリの情報が見つかったので、これで進められそうです。
今回のプロトタイピングで作るもの
IoTと言われるシステムをデータの流れに注目して大雑把に分類してみると下記のようになるのかなと思います。
-
モノ(情報)→ヒト(活用する)
情報の可視化、センサー情報をグラフで表示とか -
ヒト(情報)→モノ(制御される)
モノを制御する。動きのある機械などを遠隔制御したりする
あとは、1. 2. の組み合わせだったり、変化系だったりする。
よく見るのは下記のようなパターン。
-
ヒト(情報)→モノ(中継)→ヒト(活用する)
見守り等。このパターンは俯瞰すると 1. の変化系。 -
モノ(情報)→モノ(制御される)
M2Mとか言われてるやつだが、全てのシステムが最終的にヒトの社会のために存在すると考えると、俯瞰してみてもこのパターン、というのは存在しないと思う。おそらく、俯瞰してみると、ヒト(情報)→モノ(中継)→モノ(制御される)
であったり、モノ(情報)→モノ(中継)→ヒト(活用する)
のいずれかのパターンの切り取りではないか。
そして、世の中のIoTシステムは、1. だったり、 2. だったり、それらを複雑に構成したりして作られている。
少々脱線した。
話を戻すとLeafonyに限らず、よく見るIoTの作例に関する情報って、1.が多い気がします。みんなグラフ見るの好きだな!
と感じているので、 2.の簡単な作例を増やしましょう、という企画です。
下記のようなプロトタイピングしてみたいと思います。
- モノはクリスマスらしく、サンタのパネル!
- サンタの目にLEDが仕込まれており、インターネット経由で点灯パターンを変更できる
シンプルだけど ヒト(情報)→モノ(制御される)
ですね!
これなら前回やったLチカ の延長でできそう!ということで。
使うもの
1. Leafony
2. 部品等
- LED x 2
- 抵抗 x 1
- ダンボール紙
- 普通の印刷用の紙
- セロテープ
- 配線用のより線
- ピンヘッダ
- のり
3. PCや工具等
- PC(今回も Macbook Air 2021 M1 を利用)
- カラープリンター
- USBケーブル
- ハンダごて/はんだ
- ハサミ or カッター
- ニッパー/ワイヤーストリッパ等
4. ソフトウエア
- Arduino IDE
- サンタの絵 (いらすとやさん、ありがとうございます)
5. インフラ
- Soracom(SIMカード)
- クラウドサーバ(AWSやVPS等。筆者は契約している ubuntu 20.04 が動作するVPSを利用してテストしました。)
プロトタイピングの手順
0. Soracom SIM の設定を確認する。
今回は SIMをアクティベートした状態でお借りしたため、アクティベート手順は不要でしたが、通常は下記ページの手順に従い実施するようです。
1. Arduino IDEに STM32 Core を導入する
前回記事 に記載しましたので、この手順通りに導入します。
2. LTE-M Leaf用のライブラリを導入する
LTMライブラリ をダウンロードして解凍したフォルダを、下記パスに入れます(Macの場合)
~/Documents/Arduino/libraries
Arduino IDEを再起動すれば導入完了です。
3. Arduinoのスケッチを書く
今回は、HTTP GETを定期的に実施するスケッチを作成します。
1から作るのは大変なので、ベースとなるサンプルコードを修正する形で作ります。
こちらをベースに、下記のように書き換えます。
今回は HTTPSは使わないので、HTTPSのコードは削除しています。
// base :
#include <LpwaV4.h>
#include "arduino_secrets.h"
const char GPRS_APN[] = SECRET_GPRS_APN;
const char GPRS_LOGIN[] = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;
char serverAddress[] = "サーバープログラムをデプロイしたURL"; // server address
char path[] = "/pattern";
int port = 4000;
LpwaHttpClient client = LpwaHttpClient(serverAddress, port);
GPRS gprs;
LpwaAccess lpwaAccess;
int now_pattern = 0;
int gCnt = 0;
int lCnt = 0;
#define GCNT_MAX 6000 // 300sec <- debug終わったらこのくらいで。
// #define GCNT_MAX 1200 // 60sec <- debug用。課金怖い
#define LCNT_MAX 20 // 1sec
#define LED_1 13
#define LED_2 2
int led1_pattern[5][20] = {
{
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW,
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH,HIGH,HIGH,HIGH, LOW, LOW, LOW, LOW, LOW,
HIGH,HIGH,HIGH,HIGH,HIGH, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH, LOW, LOW,HIGH,HIGH, LOW, LOW,HIGH,HIGH,
LOW, LOW,HIGH,HIGH, LOW, LOW,HIGH,HIGH, LOW, LOW
}
};
int led2_pattern[5][20] = {
{
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW,
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW
},
{
LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW, LOW,
HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH,HIGH
},
{
HIGH,HIGH,HIGH,HIGH,HIGH, LOW, LOW, LOW, LOW, LOW,
HIGH,HIGH,HIGH,HIGH,HIGH, LOW, LOW, LOW, LOW, LOW
},
{
HIGH,HIGH, LOW, LOW,HIGH,HIGH, LOW, LOW,HIGH,HIGH,
LOW, LOW,HIGH,HIGH, LOW, LOW,HIGH,HIGH, LOW, LOW
}
};
void setup() {
Serial.begin(115200);
Serial.println("Starting http client.");
bool connected = false;
while (!connected) {
if ((lpwaAccess.begin() == LPWA_READY) &&
(gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
connected = true;
} else {
Serial.println("connecting.");
delay(1000);
}
}
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
digitalWrite(LED_1, LOW);
digitalWrite(LED_2, LOW);
Serial.println("LPWA connected");
delay(5000); // wait for first request (about 5sec)
}
void loop() {
if(gCnt == 0){
Serial.println("making GET request");
client.clrHeader();
client.addHeader("Accept", "*/*");
client.get(path);
int statusCode = client.responseStatusCode();
String response = client.responseBody();
Serial.print("Status code: ");
Serial.println(statusCode);
Serial.print("Response: ");
Serial.println(response);
if((response[0] >= '0')&&(response[0] <= '4')){
Serial.print("get OK pattern=");
now_pattern = (int)(response[0]) - 0x30;
Serial.println(now_pattern);
}else{
Serial.println("get Failed");
}
}
digitalWrite(LED_1,led1_pattern[now_pattern][lCnt]);
digitalWrite(LED_2,led2_pattern[now_pattern][lCnt]);
delay(50);
gCnt = ((gCnt + 1) % GCNT_MAX);
lCnt = ((lCnt + 1) % LCNT_MAX);
}
ちょっとコードの解説
- だいたい300秒(約5分)に1度、サーバーへパターン情報の取得をリクエストしています。パターン情報は、なんと
0
〜4
の数字がtext/plain
で返却されます。2022年に書くプログラムとは思えないほど単純!よって、パースも簡単です。文字列から数字に変換するだけ!- Arduino側が処理しやすいように、サーバー側の仕様を好き勝手に作れるのもプロトタイピングの良いところですね。一緒に作ってるから自由です。
- C++でJSONパースとか書くのはめんどくさいですけど、サーバー処理を行うJavaScript側で制約の多いArduino側が処理しやすいようにプロトコルを合わせ込むのは簡単なことです。
-
delay(300000)
等とやってしまうと、その間 LEDの点滅用のスケッチが動けなくなるので、delay(50)
を 6000回やったらリクエスト、というインターバルにしています。 - 同様に、Lチカの部分も、
delay(50)
のインターバルでパターンデータを参照してHIGH
とLOW
を切り替えるようにしています。
割り込みやタイマーを使っても並列処理書けると思いますが、今回は単純に上記のようにしました。
4. Leafonyの組み立て
コードを書き込む前に、Leafonyを組み立てます。
Basic Kit 2 と LTE-M Leaf から、下記リーフを組み立てます。
重ね順(上から) | 部品名 | 説明 |
---|---|---|
1 | AX02 29pin | IO外だし用モジュール→ここに頑張ってLEDを繋ぐ |
2 | AZ01 USB | USBシリアル通信モジュール→STM32書き込み用兼電源。LTE-M Leafを利用する時は本来不要。後述の事情で今回書き込み用として利用することに |
3 | AP03 STM32 MCU | STM32L4モジュール→ここにLチカのプログラムを書く |
4 | AC04 LTE-M King M | LTE-MリーフV4の通信モジュール |
5 | AC05 LTE-M King S | LTE-MリーフV4の電源モジュール。本当はこちらから書き込むらしいが今回は書き込みには使ってない。理由は後述 |
あれ?っと思った方は鋭い!
これ、かなり変な構成になっています。
4-1. あれ? XR21B1411 の Appleシリコン版ドライバーはいずこ?
AC05 LTE-M King S を見ると、その中の「USBドライバインストール」の項で下記のような説明があります。
下記からご使用のOSにあったドライバーをダウンロードし、解凍して下さい。Windowsの場合は、解凍すると「V2.6.0.0 Drivers」のフォルダが出来ます。以降、Windowsの場合を説明します。
https://www.maxlinear.com/product/interface/uarts/usb-uarts/xr21b1411
そこで、Mac用のドライバーを探すと、最終更新が 2013年 10月となっています。
一応、ダウンロード後解凍して、中にある README.txt を読み、その手順通りにインストールを試みましたが、エラーでインストールできないようです。
ドライバーは kext で提供されていますが、そもそも現在のMacOSでは kext 自体が非推奨扱いです。
9年前からMacを取り巻く環境は大きく変わったので、無理矢理インストールしよう、というのは諦めました。
4-2. プログラムの書き込み時は AC05 LTE-M King S の代わりに AZ01 USB を使う(自己責任)
AC04 LTE-M King M のページを見ても下記のように記載されています。
LTE-M King Mの電源供給には、LTE-M king Sが必要になります。必ず、LTE-M king Sを下に配置してご使用下さい。
うーむ。どうしろと。
ちょっとだけ悩んで、まーやってみればいいかの精神で、下記のように運用する想定で、今回の構成となりました。
- AP03 STM32 MCU へのプログラムの書き込みは、AZ01 USB で行えるので、そちらで実施(書き込み時はUSB電源なので、AZ01 USBからLTE-M Leafにも電源供給される。心配な人はLTE-M Leafを外しておくべき)
- スタンドアロンで動作させるときは、AC05 LTE-M King S から電源供給する。
とはいえ、デバッグ全然しないわけにもいかないし、AZ01 USBをいちいち外してられない、というのが本音ですが、くれぐれも自己責任で危険なコトをやってるという自覚があり、後始末に責任が持てる方のみ真似してください。
基本は真似しないでください!!!
もっと良い解決策がわかったら追記します。
4-3. スケッチの書き込み
というわけで、M1 Macしか手元にない私は、仕方なく AZ01 USB経由でスケッチを書き込みました。
スケッチの書き込み方は、前回の記事 と同じなので省略します。
5. サンタのパネルをダンボールプロトタイピング
IoTは「モノのインターネット」です。モノがないと始まりません。
その「モノ」をダンボールプロトタイピングで作ります。
5-1. イラストをプリント
まず、好きなサンタの絵を印刷します。
私は「いらすとや」さんの下記イラストを印刷しました。
家のプリンターのインクの調子が悪くて、印刷後の色がちょっと変ですが気にしない。
5-2. イラストを切り抜く
「はさみ」もしくは「カッター」をつかって印刷イラストを切り抜きます。
ハサミだけでも切り抜けました。
5-3. ダンボールに切り抜いたイラストを貼る
のりを使ってダンボールに貼ります。
5-4. 目の場所に穴を開ける
目になる位置に、キリ状の工具で穴を開けましょう。紙なので簡単に開きます。
5-5. 2個のLEDを穴に差し込んで「目」にする。
今回は3mmの砲弾型LEDを使いました。
5-6. LEDの後側の「足」をカソードコモンではんだづけする
LEDは2つですが、配線を少なくしたいので、カソード(マイナス)側を1つにまとめます。
そのためにLEDの足(の短い方)を曲げて2本を束ねてはんだ付けします。
画像は目の穴にLEDを後ろから差し込んで、LEDの足を曲げたところ。
5-7. カソード側に抵抗を入れる
Lチカの時は手抜きで抵抗を入れませんでしたが、今回は一応抵抗を入れることにします。
LEDは明るさ調整のため本来はアノード側に入れた方が良いですが、これも部品(と手間)をケチるためカソード側に入れます。ダンボールプロトタイピングは手抜きが重要!
5-8. LEDに電線をハンダ付して、電線の反対側にピンヘッダをはんだ付け
Leafonyとサンタの位置関係をあまり考えたくないので、長めの電線でLeafonyをLEDを接続します。
前回のLチカではLEDの足をバネのように広げて、AX02 29pin に差し込みましたが、今回も同様の作戦で AX02 29pinに接続できるようにするために、ピンヘッダを穴の間隔より少し広げるように曲げてバネ構造にします。
AX02 29pinと サンタパネルに突き刺さったLEDが接続できたら、今回の「モノ」は完成です。
LED(の先につなげたケーブルの先につなげたピンヘッダ)と、AX02 29PINは下記のように接続します。
LED側 | AX29 PINのPIN番号 |
---|---|
LED1のアノード | 21 |
LED2のアノード | 22 |
LEDのカソード | 27 |
サンタのパネルはこんな感じになりました!
6. 制御用のUIとAPIを作る
node.js + express + html で制御用のAPIとUIをサクっと作ります。
import http from 'http';
import express from 'express';
import cors from 'cors';
const LISTEN_IP = "127.0.0.1";
const LISTEN_PORT = 4000;
let webServer;
let app;
let _pattern = 0; // 0: stop, 1: slow 2: pingpong 3: normal 4: fast
const PATTERN_NUM = 5;
try {
await runExpressApp();
await runWebServer();
} catch (err) {
console.error(err);
}
async function runExpressApp() {
app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(cors());
app.get('/pattern',(req,res)=>{
console.log("GET /pattern");
res.header('Content-Type', 'text/plain;charset=utf-8');
res.end(""+_pattern);
});
app.post('/pattern', (req,res)=>{
console.log("POST /pattern pattern="+req.body.pattern);
let jobj = {status:"OK",pattern:req.body.pattern};
let pattern = Number(req.body.pattern);
if((isNaN(pattern))||(pattern < 0)||(pattern >= PATTERN_NUM)){
jobj.status = "NG";
res.status(401).json(jobj);
}else{
_pattern = pattern;
res.json(jobj);
}
});
app.use('/',express.static("./www"));
}
async function runWebServer() {
webServer = http.createServer(app);
webServer.on('error', (err) => {
console.error('starting web server failed:', err.message);
});
await new Promise((resolve) => {
webServer.listen(LISTEN_PORT, () => {
console.log('server is running PORT:'+LISTEN_PORT);
resolve();
});
});
}
{
"name": "LED blink pattern",
"version": "1.0.0",
"description": "LED blink pattern",
"type": "module",
"main": "app.mjs",
"scripts": {
"start": "node app.mjs"
},
"author": "D.F.Mac. @TripArts Music",
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.18.1"
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>LED点灯パターン変更</title>
<style>
button{font-size:24px;width:160px;height:60px;}
</style>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>ON/OFF</h1>
<button id="b_0">STOP</button><button id="b_1">遅い</button><button id="b_2">往復</button><button id="b_3">通常</button><button id="b_4">速い</button>
<script>
const PATTERN_MAX = 5;
let btns = [];
for(let cnt=0;cnt<PATTERN_MAX;cnt++){
let $btn = document.querySelector("#b_"+cnt);
((_cnt)=>{
$btn.onclick = async (e) => {
await setPattern(_cnt);
};
})(cnt);
btns.push($btn);
}
async function setPattern(_pattern){
return await axios.post('/pattern', {pattern:_pattern});
}
</script>
</body>
</html>
エンドポイントは下記の通りです。
-
GET /pattern
: パターンの番号を取得する。0
〜4
が返却される。これは Leafonyから定期的に呼び出す。 -
POST /pattern
: 制御用のWebアプリから指定するパターン番号をポストします。0
〜4
-
GET /
: 制御用のUI。ボタンを押すとPOST /pattern
でパターンを変更します。
できたら、お好みのサーバーにデプロイしましょう。
7. テスト
いよいよテストです!
LeafonyとUSB電源を接続して、Leafonyを起動します。
(AP03 STM32 MCU のスライドスイッチを書き込みモードから戻すのを忘れずに!)
すると、サーバーへ一定のインターバルでリクエストが飛び始めます。
この間、通信量がかかりますので、使い終わったらLeafonyの電源を切りましょう!
この状態でデプロイしたサーバーのURLをブラウザで叩くと、下記のようなボタンが表示されますので、適当に押します。
今回のスケッチで指定したLeafonyからサーバーへのポーリングインターバルは5分に1度です。なので、なかなか変わりませんが、ブラウザのボタンを押した後に5分以内くらいで、サンタの目のLED点灯パターンを変えることができます。
ピンクのLEDにしたら、絶対悪いこと考えてそうな魔界からの使者みたいになってしまった......
まとめ(やってみた感想含む)
- LTE-Mリーフはまだ売ってないけどWIFIと違って自由に外に持ち出して通信できるようになるのは楽しい!
- 現時点では、Appleシリコンの Mac へ AC05 LTE-M King S が採用したシリアル通信モジュール XR21B1411 のドライバのインストール方法がわからないのでWindowsで使うのが無難そうだ。 一応AZ01 USB でも(USB給電では)使えたが、何か問題があるかもしれない。最悪PCやLeafonyが壊れるかもしれないので、真似はオススメはしない! 要継続調査案件。 情報求む!
- 今回は全くセキュリティのケアがないのでセキュリティのケアが必要な用途には、SORACOMのサービスを使った方が良い(手順は LTE-Mを使ったIoTサービス を参照すべし)
- ダンボールプロトタイピングは楽しい!w