先日の記事では SORACOM Inventory が Public Beta になったということでデバイス管理と SORACOM Harvest との連携を試してみました。
Public Beta になったタイミングで SORACOM Inventory では LwM2M のカスタムオブジェクトが定義できるようになったので、今回は簡単に実装してみました。 SORACOM Inventory の機能概要や LwM2M のリソースモデル等については SORACOM の公式ドキュメントを参照ください。
コアライブラリとサンプル実装のダウンロード
SORACOM Inventory では下記リポジトリで Java版エージェントのコアライブラリとサンプル実装が提供されています。
まずはこちらを clone します。
$ git clone https://github.com/soracom/soracom-inventory-agent-for-java.git
$ cd soracom-inventory-agent-for-java/
環境構築
プロジェクトのビルドには Gradle が使用されています。私は IDE に Eclipse を使用しているので、下記コマンドで Eclipse 用の設定ファイルを生成します。
$ ./gradlew eclipse
また、後でコアライブラリの jar ファイルを使用するので、下記コマンドでビルドしておきます。
$ ./gradlew build
そして Eclipse のプロジェクトとしてインポートします。File
メニュー の Import
から General
> Existing Projects into Workspace
と辿って、root directory に soracom-inventory-agent-for-java ディレクトリを選択します。
次に今回作成するエージェントのプロジェクト用のディレクトリを作成します。
$ mkdir restroom-monitor-agent $ cd restroom-monitor-agent/
下記コマンドでプロジェクトを初期化します。
$ gradle init --type java-application
すると下記のようなファイルが生成されます。
$ ls -l total 40 -rw-r--r-- 1 akanuma staff 992 May 12 23:52 build.gradle drwxr-xr-x 3 akanuma staff 96 May 12 23:52 gradle -rwxr-xr-x 1 akanuma staff 5296 May 12 23:52 gradlew -rw-r--r-- 1 akanuma staff 2260 May 12 23:52 gradlew.bat -rw-r--r-- 1 akanuma staff 369 May 12 23:52 settings.gradle drwxr-xr-x 4 akanuma staff 128 May 12 23:52 src
build.gradle の内容は下記のように変更します。
$ cat build.gradle plugins { id 'java' id 'eclipse' id 'idea' id 'application' } repositories { jcenter() maven { url 'https://soracom.github.io/maven-repository/' } } def INVENTORY_AGENT_VERSION="0.0.5" dependencies { compile "io.soracom:soracom-inventory-agent-for-java-core:$INVENTORY_AGENT_VERSION" testCompile 'junit:junit:4.12' } mainClassName = 'com.akanumahiroaki.restroommonitor.agent.RestroomMonitorAgent'
Eclipse 用の設定ファイルを生成します。
$ ./gradlew eclipse
そして Eclipse にインポートします。初期化時に生成されたメインクラスは下記のように App.java になっています。
これを build.gradle の mainClassName で指定したパッケージとクラス名に合うように変更します。
パッケージとクラス名変更後の初期の実装は下記のようになっています。
package com.akanumahiroaki.restroommonitor.agent; /* * This Java source file was generated by the Gradle 'init' task. */ public class RestroomMonitorAgent { public String getGreeting() { return "Hello world."; } public static void main(String[] args) { System.out.println(new RestroomMonitorAgent().getGreeting()); } }
次に必要なライブラリにパスを通します。 LeshanClient を使用するためのライブラリは別途取得する必要があるので、私は下記サイトから依存する jar と共に取得してきました。
また、先ほどビルドしたコアライブラリの jar が下記パスに生成されています。
soracom-inventory-agent-for-java/build/libs/soracom-inventory-agent-for-java-0.0.5.jar
これらの jar ファイルを外部ライブラリとしてビルドパスに追加しておきます。
カスタムオブジェクト定義
カスタムオブジェクトを定義するには XML ファイルを作成する必要があります。今回はシンプルに読み取り用のリソースを一つだけ定義してみます。トイレセンサーを作っている想定で、その空室状況を表すステータスです。カスタムオブジェクトの使い方としてこういうステータスを扱うのが正しいのか微妙な気がしましたが、今回は実装を試すのが主目的ということでやってみます。下記のような XML ファイルを作成し、サンプルプロジェクトと同様に src/main/resources 配下に 30000.xml というファイル名で配置します。
<?xml version="1.0" encoding="UTF-8"?> <LWM2M xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://openmobilealliance.org/tech/profiles/LWM2M.xsd"> <Object ObjectType="MODefinition"> <Name>Restroom</Name> <Description1>Restroom Monitor</Description1> <ObjectID>30000</ObjectID> <ObjectURN>urn:oma:lwm2m:oma:30000</ObjectURN> <MultipleInstances>Single</MultipleInstances> <Mandatory>Optional</Mandatory> <Resources> <Item ID="0"> <Name>Status</Name> <Operations>R</Operations> <MultipleInstances>Single</MultipleInstances> <Mandatory>Mandatory</Mandatory> <Type>String</Type> <RangeEnumeration /> <Units/> <Description>Status of a restroom.</Description> </Item> </Resources> <Description2 /> </Object> </LWM2M>
実装クラス
上記で定義したカスタムオブジェクトの実装クラスを下記のように作成します。今回はテキストファイルに現在のステータスが記録されているという前提で、簡単にその内容を読み込んで返すというだけにしてあります。
AnnotatedLwM2mInstanceEnabler を継承したクラスに @LWM2MObject アノテーションでオブジェクトIDとオブジェクト名を指定します。また、値を返すメソッドには @Resource アノテーションでリソースIDとオペレーション種別を指定します。今回は読み取り専用のリソースなので、オペレーション種別は Operation.Read を指定しています。
package com.akanumahiroaki.restroommonitor.agent.object; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; import io.soracom.inventory.agent.core.lwm2m.*; @LWM2MObject(objectId = 30000, name = "Restroom") public class RestroomObject extends AnnotatedLwM2mInstanceEnabler { @Resource(resourceId = 0, operation = Operation.Read) public String readStatus() { try { List<String> lines = Files.readAllLines(Paths.get("/home/pi/work/RestroomMonitor/status.txt")); return String.join("", lines); } catch (IOException e) { e.printStackTrace(); return "unknown"; } } }
エージェントクラスの実装
ここまでで用意したカスタムオブジェクト定義と実装を利用するエージェントクラスを下記のように実装します。
lwM2mModelBuilder.addPresetObjectModels() でデフォルトのオブジェクト定義を読み込んだ後で、 lwM2mModelBuilder.addObjectModelFromClassPath("/30000.xml") で今回定義したオブジェクト定義を読み込んでいます。また、実装したオブジェクトクラスを initializer.addInstancesForObject(new RestroomObject()) で設定しています。
package com.akanumahiroaki.restroommonitor.agent; import org.eclipse.leshan.client.californium.LeshanClient; import com.akanumahiroaki.restroommonitor.agent.object.RestroomObject; import io.soracom.inventory.agent.core.initialize.InventoryAgentInitializer; import io.soracom.inventory.agent.core.initialize.LwM2mModelBuilder; import io.soracom.inventory.agent.core.lwm2m.typed_object.impl.MockDeviceObjectImpl; public class RestroomMonitorAgent { public static void main(String[] args) { InventoryAgentInitializer initializer = new InventoryAgentInitializer(); LwM2mModelBuilder lwM2mModelBuilder = new LwM2mModelBuilder(); lwM2mModelBuilder.addPresetObjectModels(); lwM2mModelBuilder.addObjectModelFromClassPath("/30000.xml"); initializer.setLwM2mModel(lwM2mModelBuilder.build()); initializer.addInstancesForObject(new MockDeviceObjectImpl()); initializer.addInstancesForObject(new RestroomObject()); LeshanClient client = initializer.buildClient(); client.start(); } }
ユーザコンソールからオブジェクト定義を登録
ユーザコンソールにもカスタムオブジェクトの定義が反映されるように、オブジェクト定義のXMLをユーザコンソールから登録します。ユーザコンソールの左メニューの SORACOM Inventory の オブジェクトモデル
を選択します。
オブジェクトモデルの追加
ボタンをクリックします。
表示されたフォームにオブジェクトモデル定義XMLの内容を貼り付けて、 追加
ボタンをクリックします。
すると下記のようにオブジェクトモデルが追加されます。
エージェントの実行
ここまでで一通り実装は完了なので、最後にデバイスへの配布用のアーカイブを下記のコマンドで生成します。
$ ./gradlew distZip
下記のようにアーカイブが生成されますので、これをエージェントを実行するデバイスへ配布します。
$ ls -ltr build/distributions/ total 2272 -rw-r--r-- 1 akanuma staff 1159199 May 13 01:44 restroom-monitor-agent.zip
配布先デバイスで下記のようにアーカイブを展開してエージェントを実行します。
$ unzip restroom-monitor-agent.zip
$ cd restroom-monitor-agent/bin
$ ./restroom-monitor-agent
すると下記のようにコンソールからカスタムオブジェクトが確認できるようになります。 Observe することも可能です。
まとめ
今回試してみたのはシンプルな内容だったので、簡単にカスタムオブジェクトを実装することができました。実際のサービスで使用する場合にはカスタムオブジェクトの前に標準で提供されているリソースモデルに対して正しい値を返すようにエージェントを実装する必要がありますので、取得したい情報全てが取得できるようにするには結構なボリュームの実装が必要そうではあります。ただ、エージェントを実装すればプラットフォームには手をかける必要がないので、うまく使えればとても便利なのではないかと思います。