本記事では、Raspberry Pi を使った、FIWARE 対応 IoT デバイスの作成方法を紹介します。温湿度、気圧の情報を定期的に、FIWARE Orion にプッシュし、コンテキスト情報を更新するコンテキスト・プロデューサ型のデバイスです。
Context Producer (CP)
コンテキスト・プロデューサは、コンテキスト情報を生成することができるアクターです。基本的なコンテキスト・プロデューサは、内部ロジックに従って1つ以上のコンテキスト属性に関するコンテキスト情報を自発的に更新します。コンテキスト・プロデューサ (CP) からコンテキスト・ブローカー (CB) への通信はプッシュ・モードです。
前提条件
次の環境が必要となります。
- FIWARE Orion, WireCloud が稼働する Linuxサーバ環境
- Raspberry Pi (i2c を有効化)
- 環境センサ Enviro for Raspberry Pi (Pimoroni)
- git, curl, jq コマンド
FIWARE Orion, WireCloud が稼働する環境の構築方法は、「WireCloud のセットアップ」の記事を参照ください。Raspberry Pi の種類は、Raspberry Pi Zero WH, 3, 4 等です。Raspberry Pi 4 を使用すると、FIWARE Orion, WireCloud と 環境情報を収集するプログラムを1台で稼働できます。環境センサの Enviro は、発売元の Pimoroni から購入するか、国内では秋月電子通商、スイッチサイエンス等から購入できるようです。
ソースコード
使用するソースコードは、Github の https://github.com/lets-fiware/lets-fiware.tutorials から入手できます。git コマンドで、リポジトリをクローンして、”raspberrypi/01.context_producer” ディレクトリに移動してください。
git clone https://github.com/lets-fiware/lets-fiware.tutorials.git
cd ./lets-fiware.tutorials/raspberrypi/01.context_producer
システム構成
Raspberry Pi で動作するコンテキスト・プロデューサと、サーバで動作する、Orion Context Brokerと WireCloud です。
サーバ環境の作成
docker-compose ファイル
Orion, WireCloud は、Docker コンテナを利用して、サーバ上にデプロイします。クローンしたリポジトリには、x86_64 (amd64) 用 と Raspberry Pi (aarch64) 用の dokcer-compose.yml ファイルがあります。環境に応じて、以下の設定を行います。
x86_64 (amd64)
ln -s docker-compose-arm64.yml docker-compose.yml
Raspberry Pi (aarch64)
ln -s docker-compose-aarch64.yml docker-compose.yml
Docker コンテナの起動
Linux サーバで、次のコマンドを使用して Docker コンテナを起動します。これで、Orion, WireCloud に関連する一連のコンテナが実行されます。
docker-compose up -d
環境変数の設定
Raspberry Pi で、Orion にアクセスするための環境変数を設定します。コンテナが稼働するサーバの IP アドレスを 192.168.1.1 として説明しています。環境に合わせて、値を変更してください。
export ORION_URL=http://192.168.1.1:1026
正常性の確認
Orion のバージョンを取得するクエリを実行して、正しくデプロイされたことを確認してください。
GET /version
次のコマンドを実行して、レスポンスが返ってくることを確認してください。
./00.version.sh
1 2 3 4 5 6 7 8 9 10 11 12 |
{ "orion" : { "version" : "2.4.0-next", "uptime" : "0 d, 0 h, 32 m, 41 s", "git_hash" : "4f26834ca928e468b091729d93dabd22108a2690", "compile_time" : "Tue Mar 31 15:41:02 UTC 2020", "compiled_by" : "root", "compiled_in" : "d99d1dbb4d9e", "release_date" : "Tue Mar 31 15:41:02 UTC 2020", "doc" : "https://fiware-orion.rtfd.io/" } } |
コンテキスト・プロデューサ環境の作成
プログラム全体
プログラムは、Python で記述されいて、全体は以下のような内容です。プログラムを起動すると、WeatherObserved タイプのエンティティを作成して、その後、エンティティの属性値を一定時間で更新します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import signal import datetime import time import requests import json from bme280 import BME280 try: from smbus2 import SMBus except ImportError: from smbus import SMBus EXIT = False def handler(signum, frame): global EXIT EXIT = True def main(): signal.signal(signal.SIGTERM, handler) bus = SMBus(1) bme280 = BME280(i2c_dev=bus) orion_url = os.environ.get('ORION_URL', 'http://orion:1026').rstrip('/') fiware_service = os.environ.get('FIWARE_SERVICE', '') fiware_servicepath = os.environ.get('FWARE_SERVICEPATH', '/device') id = os.environ.get('DEVICE_ID', 'urn:ngsi-ld:WeatherObserved:sensor001') debug = not not os.environ.get('DEBUG_FLAG', '') headers = { 'Fiware-Service': fiware_service, 'Fiware-ServicePath': fiware_servicepath, } # Get Entity url = orion_url + '/v2/entities/' + id r = requests.get(url, headers=headers) if (r.status_code == 200): # Delete Entity r = requests.delete(url, headers=headers) # Create Entity headers['Content-Type'] = 'application/json; charset=utf-8' entity = { 'type': 'WeatherObserved', 'id': id, 'dateObserved': { 'type': 'DateTime', 'value': '{}'.format(datetime.datetime.now().isoformat(timespec='seconds')) }, 'temperature': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_temperature()) }, 'relativeHumidity': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_humidity()) }, 'atmosphericPressure': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_pressure()) }, 'location': { 'type': 'geo:json', 'value': { 'type': 'Point', 'coordinates': [ 139.7671, 35.68117 ] } } } url = orion_url + '/v2/entities' r = requests.post(url, data=json.dumps(entity), headers=headers) if r.status_code != 201: print(r.status_code) print(r.text) url = orion_url + '/v2/entities/' + id + '/attrs' while True: update = { 'dateObserved': { 'type': 'DateTime', 'value': '{}'.format(datetime.datetime.now().isoformat(timespec='seconds')) }, 'temperature': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_temperature()) }, 'relativeHumidity': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_humidity()) }, 'atmosphericPressure': { 'type': 'Number', 'value': '{:05.2f}'.format(bme280.get_pressure()) } } if (debug): print(update) # Patch Entity r = requests.patch(url, data=json.dumps(update), headers=headers) if (r.status_code != 204): print(r.status_code) time.sleep(1) if (EXIT): break if __name__ == '__main__': main() |
WeatherObserved エンティティの作成
環境センサの BME280 から取得した温湿度と気圧の情報に、情報の取得時刻と位置情報を追加して、 FIWARE データモデルの WeatherObserved の形式で、FIWARE Orion にプッシュして、エンティティを作成します。エンティティ・タイプは “WeatherObserved” で、エンティティ ID は “urn:ngsi-ld:WeatherObserved:sensor001” です。作成するエンティティのデータは以下のような内容です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ "type": "WeatherObserved", "id": "urn:ngsi-ld:WeatherObserved:sensor001", "dateObserved": { "type": "DateTime", "value": "2020-05-18T00:00:00Z" }, "temperature": { "type": "Number", "value": 24.83 }, "relativeHumidity": { "type": "Number", "value": 36.2002 }, "atmosphericPressure": { "type": "Number", "value": 1006.644 }, "location": { "type": "geo:json", "value": { "type": "Point", "coordinates": [ 139.7671, 35.68117 ] } } } |
POST メソッドを使って上記のデータを、Orion に送信を実行することで、エンティティを作成できます。
POST /v2/entities
WeatherObserved エンティティの更新
環境情報は1秒毎に更新を行います。更新する情報は、観測時刻、温度、湿度、気圧です。PATCH メソッド を使って下記のデータをOrionに送信することで、エンティティの情報を更新できます。
PATCH /v2/entities/urn:ngsi-ld:WeatherObserved:sensor001/attrs
更新に使用するデータは以下のような内容です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "dateObserved": { "type": "DateTime", "value": "2020-05-18T00:00:01Z" }, "temperature": { "type": "Number", "value": 24.96 }, "relativeHumidity": { "type": "Number", "value": 37.08203 }, "atmosphericPressure": { "type": "Number", "value": 1005.309 } } |
WeatherObserved エンティティの削除
プログラムの起動時に、WeatherObserved エンティティがすでに存在する場合、エンティティを削除します。エンティティの存在確認は以下で行います。
GET /v2/entities/urn:ngsi-ld:WeatherObserved:sensor001
HTTP のレスポンス・コードが 200 の場合、エンティティが存在するため、以下を実行して、エンティティを削除します。
DELETE /v2/entities/urn:ngsi-ld:WeatherObserved:sensor001
コンテキスト・プロデューサの実行
Docker コンテナ内での実行
Docker コンテナ・イメージの取得
コンテキスト・プロデューサ用のコンテナ・イメージを Docker Hubから取得します。次のコマンドで、fisuda/context_producer01 という名前のコンテナ・イメージを取得できます。
./pull.sh
Docker コンテナ・イメージのビルド
コンテキスト・プロデューサ用コンテナ・イメージをビルドする場合、次のコマンドを実行します。fisuda/context_producer01 という名前のコンテナ・イメージが作成されます。
./build.sh
Docker コンテナの起動
Dokcer コンテナを起動することで、プログラムを実行できます。
./run.sh
コンソールの出力
プログラムが正常に稼働しているかを確認するため、コンソールの出力を確認します。
./logs.sh
コマンドを実行して以下のようなメッセージが出力されば正常に稼働していることを確認できます。
1 2 3 4 5 |
{'dateObserved': {'type': 'DateTime', 'value': '2020-05-23T00:41:39+0900'}, 'temperature': {'type': 'Number', 'value': '25.47'}, 'relativeHumidity': {'type': 'Number', 'value': '92.09'}, 'atmosphericPressure': {'type': 'Number', 'value': '661.89'}} {'dateObserved': {'type': 'DateTime', 'value': '2020-05-23T00:41:40+0900'}, 'temperature': {'type': 'Number', 'value': '42.72'}, 'relativeHumidity': {'type': 'Number', 'value': '19.50'}, 'atmosphericPressure': {'type': 'Number', 'value': '1009.80'}} {'dateObserved': {'type': 'DateTime', 'value': '2020-05-23T00:41:41+0900'}, 'temperature': {'type': 'Number', 'value': '42.75'}, 'relativeHumidity': {'type': 'Number', 'value': '20.11'}, 'atmosphericPressure': {'type': 'Number', 'value': '1009.82'}} {'dateObserved': {'type': 'DateTime', 'value': '2020-05-23T00:41:42+0900'}, 'temperature': {'type': 'Number', 'value': '42.76'}, 'relativeHumidity': {'type': 'Number', 'value': '19.75'}, 'atmosphericPressure': {'type': 'Number', 'value': '1009.83'}} {'dateObserved': {'type': 'DateTime', 'value': '2020-05-23T00:41:43+0900'}, 'temperature': {'type': 'Number', 'value': '42.74'}, 'relativeHumidity': {'type': 'Number', 'value': '19.51'}, 'atmosphericPressure': {'type': 'Number', 'value': '1009.80'}} |
コンテナの停止
以下のコマンドを実行することで、コンテナを停止できます。
./stop.sh
Linux OS 上で直接実行
Raspberry Pi OS 上で直接実行したい場合や Raspberry Pi Zero WH で実行する場合、次のコマンドを実行します。
sudo apt install python3 python3-pip zlib1g-dev libjpeg-dev
pip3 install numpy RPI.GPIO ST7735 pillow paho-mqtt requests fonts font-roboto
python3 context-producer.py
Orion からエンティティを取得
Orion から、urn:ngsi-ld:WeatherObserved:sensor001 のコンテキスト情報を取得して、情報が更新されていることを確認できます。
GET /v2/entities/urn:ngsi-ld:WeatherObserved:sensor001
次のコマンドで、エンティティの情報を取得できます。
./21.get_entity.sh
実行結果は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
$ curl -sS -H 'Fiware-ServicePath: /device' http://192.168.11.1:1026/v2/entities/urn:ngsi-ld:WeatherObserved:sensor001 | jq . { "id": "urn:ngsi-ld:WeatherObserved:sensor001", "type": "WeatherObserved", "atmosphericPressure": { "type": "Number", "value": "1009.83", "metadata": {} }, "dateObserved": { "type": "DateTime", "value": "2020-05-23T22:51:48.00Z", "metadata": {} }, "location": { "type": "geo:json", "value": { "type": "Point", "coordinates": [ 139.7671, 35.68117 ] }, "metadata": {} }, "relativeHumidity": { "type": "Number", "value": "19.63", "metadata": {} }, "temperature": { "type": "Number", "value": "41.63", "metadata": {} } } |
WireCloud でのエンティティの情報の表示
次に、WireCloud でエンティティの情報を表示するダッシュボードを作成ます。WireCloud の環境設定の詳細は「WireCloud のセットアップ」を参照してください。
Widget のインストール
マーケットプレイスから以下の2つのウィジェットをインストールします。
- FISUDA/ngsi-source/4.2.0b2
- CoNWeT/spy-wiring/1.0.3
Widgetのワイヤーリング
新しいワークスペースを作成して、Spy wiring をワークスペースに追加します。次に、ワイヤーリング画面で、NGSI source と Spy wiring を以下のようにワイヤーリングします。
Widget の設定
NGSI Source の設定値を以下のように設定します。
- NGSI server URL: http://192.168.1.1:1026/
- NGSI proxy URL: http://192.168.1.1:3000
- FIWARE-ServicePath: /device
- Id pattern: urn:ngsi-ld:WeatherObserved:sensor001
- Monitored NGSI: temperature,relativeHumidity,atmosphericPressure
NGSI server URL には Orion の IP アドレスとポートを NGSI proxy URL には ngsiproxy の IP アドレスとポートをそれぞれ、稼働している環境に合わせて指定してください。
Monitored NGSI には、Orion に対してサブスクリプションを設定する属性名を指定します。ここでは温度、湿度、気圧の属性名を指定しています。エンティティ中のこれらの属性値が変化したときに、クライアントのWeb ブラウザが Orion からノーティフィケーションを受け取ります (ノーティフィケーションは、ngsiproxy を経由します)。ノーティフィケーションを受けると、Spy wiring の表示値が更新されます。
ワークスペースの表示
Widget の設定を終えた後、WeatherObserved エンティティを更新するプログラムを稼働させて、ワークスペースを表示すると、Spy wiring の表示値が変化することを確認できるはずです。
環境設定のクリーンアップ
コンテキスト・プロデューサ・コンテナの停止
次のコマンドで、コンテキスト・プロデューサ・コンテナを停止できます。
./stop.sh
WeatherObserved エンティティ の削除
次のコマンドで、Orion にある WeatherObserved エンティティを削除できます。
./22.delete_entity.sh