本記事では、Rapsberry Pi を使って、温湿度、気圧の情報をコンテキスト・ブローカーやコンテキスト・コンシューマにコンテキスト情報を提供する、コンテキスト・プロバイダを紹介します。
Context Provider (CPr)
コンテキスト・プロバイダ (CPr) は、コンテキスト・プロデューサ (CP) の特別な種類です。同期モードでオンデマンドでのコンテキスト情報を提供します。つまり、コンテキスト・ブローカーだけでなく、コンテキスト・コンシューマも、コンテキスト情報を取得するためにコンテキスト・プロバイダを呼び出すことができます。コンテキスト・プロバイダは特定の呼び出しに対してコンテキスト・データのみを提供します。すべてのコンテキスト・プロバイダは、適切なアナウンスをコンテキスト・ブローカーに送信することによりその可用性と機能をレジストレーション (登録) し、コンテキスト・ブローカーおよびコンテキスト・コンシューマにコンテキスト情報を提供するためにインタフェースを公開します。
前提条件
次の環境が必要となります。
- FIWARE Orion が稼働する 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 と 環境情報を収集するプログラムを1台で稼働できます。環境センサの Enviro は、発売元の Pimoroni から購入するか、国内では秋月電子通商、スイッチサイエンス等から購入できるようです。
ソースコード
使用するソースコードは、Github の https://github.com/lets-fiware/lets-fiware.tutorials から入手できます。git コマンドで、リポジトリをクローンして、”raspberrypi/02.context_provider” ディレクトリに移動してください。
git clone https://github.com/lets-fiware/lets-fiware.tutorials.git
cd ./lets-fiware.tutorials/raspberrypi/02.context_provider
システム構成
システム構成は、Raspberry Pi で動作するコンテキスト・プロデューサと、Linux サーバで動作する Orion Context Broker です。
サーバ環境の作成
docker-compose ファイル
Orion は、Docker コンテナを利用して、Linux サーバ上にデプロイします。クローンしたリポジトリには、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 コンテナの起動
次のコマンドで、Docker コンテナを起動します。これで、Orion に関連する一連のコンテナが実行されます。
docker-compose up -d
Raspberry Pi での環境変数の設定
Raspberry Pi で、Orion とコンテキスト・プロデューサにアクセスするための環境変数を設定します。Orion が稼働する Linux サーバの IP アドレスを 192.168.1.1、コンテキスト・プロデューサが稼働する Raspberry Pi の IP アドレスを 192.168.1.2 として説明しています。環境に合わせて、値を変更してください。
export ORION_URL=http://192.168.1.1:1026
export CONTEXT_PROVIDER_URL=http://192.168.1.2:8080
正常性の確認
Raspberry Pi から、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/" } } |
コンテキスト・プロバイダ環境の作成
プログラム概要
本記事で作成するコンテキスト・プロバイダは、コンテキスト・ブローカーからコンテキスト情報取得のリクエストを受け付けるために、次のエンドポイントを提供します。
POST /v1/weatherObserved/op/query
エンドポイントは、Python の Webサーバのライブラリを利用して実現します。具体的には、エンドポイントにアクセスがあると、温湿度、気圧の情報をセンサーから取得し、これらをコンテキスト情報としてレスポンスします。
プログラム全体
プログラム全体は以下のような内容です。この Pythonのプログラムがコンテキスト・プロバイダとして動作します。
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 |
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import sys import signal from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import parse_qs, urlparse import json from bme280 import BME280 try: from smbus2 import SMBus except ImportError: from smbus import SMBus def handler(signum, frame): sys.exit(0) class ContextProviderHandler(BaseHTTPRequestHandler): def do_POST(self): content_length = int(self.headers['content-length']) path = self.path if (path != '/v1/weatherObserved/op/query'): self.send_response(404) return body = json.loads(self.rfile.read(content_length).decode('utf-8')) e = body['entities'][0]['id'] if (e != device_id): self.send_response(404) return if (debug): print('path = {}'.format(path)) print('body = {}'.format(body)) response = [ { "id": device_id, "type": "WeatherObserved", '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(response) self.send_response(200) self.send_header('Content-Type', 'application/json; charset=utf-8') self.end_headers() self.wfile.write(json.dumps(response).encode('utf-8')) if __name__ == '__main__': signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGINT, handler) bus = SMBus(1) bme280 = BME280(i2c_dev=bus) device_id = 'urn:ngsi-ld:WeatherObserved:' + os.environ.get('DEVCIE_ID', 'sensor002') debug = not not os.environ.get('DEBUG_FLAG', '') debug = True print('Start Context Provider') address = ('0.0.0.0', 8080) with HTTPServer(address, ContextProviderHandler) as server: server.serve_forever() |
コンテキスト・プロバイダの実行
コンテキスト・プロバイダは、環境センサが接続された Raspberry Pi で実行します。
Docker コンテナ内での実行
Docker コンテナ・イメージの取得
コンテキスト・プロバイダ用のコンテナ・イメージを Docker Hubから取得します。次のコマンドで、fisuda/context_provider01 という名前のコンテナ・イメージを取得できます。
./pull.sh
Docker コンテナのビルド
プログラムをDocker コンテナ内で実行するため、環境センサ用コンテナをビルドします。ビルドには以下のコマンドを実行してい下さい。fisuda/context_provider01 という名前のコンテナ・イメージが作成されます。
./build.sh
Docker コンテナの起動
Dokcer コンテナを起動することで、プログラムを実行できます。起動時に、Orion の IP アドレスとポートを指定します。使用している環境に合わせて、これらの値を変更してください。
./run.sh
コンソールの出力
プログラムが正常に稼働しているかを確認するため、コンソールの出力を確認します。
./logs.sh
コマンドを実行して以下のようなメッセージが出力されば正常に稼働していることを確認できます。
1 |
Start Context Provider |
コンテキスト・プロバイダの登録
コンテキスト・ブローカーの FIWARE Orion から、このコンテキスト・プロバイダにアクセスできるように、コンテキスト・プロバイダのレジストレーションが必要です。
POST /v2/registrations
次のコマンドでレジストレーションできます。
./01.create-registration.sh
01.create-registration.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 |
#!/bin/bash : ${ORION_URL:?Not found} : ${CONTEXT_PROVIDER_URL:?Not found} curl -iX POST \ "$ORION_URL/v2/registrations" \ -H "Content-Type: application/json" \ -H "Fiware-ServicePath: /device" \ -d "{ \"description\": \"Weather Context Source\", \"dataProvided\": { \"entities\": [ { \"id\": \"urn:ngsi-ld:WeatherObserved:sensor002\", \"type\": \"WeatherObserved\" } ], \"attrs\": [ \"temperature\", \"relativeHumidity\", \"atmosphericPressure\" ] }, \"provider\": { \"http\": { \"url\": \"$CONTEXT_PROVIDER_URL/v1/weatherObserved\" } } }" |
実行結果
“201 Created” のレスポンスがあれば正常に登録できています。
1 2 3 4 5 6 |
HTTP/1.1 201 Created Connection: Keep-Alive Content-Length: 0 Location: /v2/registrations/5ed06731b10dc3f8b36b3c94 Fiware-Correlator: dddbc9de-a14c-11ea-b945-0242ac140004 Date: Fri, 29 May 2020 00:00:00 GMT |
実行結果に含まれている Location 中の文字列 ”5ed06731b10dc3f8b36b3c94” がレジストレーション ID です。レジストレーションの情報取得や削除するときに使用します。以下の環境変数に登録しておきます。
export REG_ID=5ed06731b10dc3f8b36b3c94
レジストレーションの一覧情報を取得
レジストレーションの一覧情報は以下のクエリで取得できます。
GET /v2/registrations
02.list-registrations.sh
1 2 3 |
#!/bin/bash : ${ORION_URL:?Not found} curl -sS -H "Fiware-ServicePath: /device" "$ORION_URL/v2/registrations" | jq . |
実行結果
次のような内容がレスポンスとして返却されます。
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 |
[ { "id": "5ed06731b10dc3f8b36b3c94", "description": "Weather Context Source", "dataProvided": { "entities": [ { "id": "urn:ngsi-ld:WeatherObserved:sensor002", "type": "WeatherObserved" } ], "attrs": [ "temperature", "relativeHumidity", "atmosphericPressure" ] }, "provider": { "http": { "url": "http://192.168.1.3:8080/v1/weatherObserved" }, "supportedForwardingMode": "all", "legacyForwarding": true }, "status": "active" } ] |
コンテキスト情報を取得
./run.sh でコンテキスト・プロバイダのコンテナを起動したあと、Orion にアクセスして、コンテキスト情報を取得します。次のクエリで取得できます。
GET /v2/entities/urn:ngsi-ld:WeatherObserved:sensor002
03.get_entity.sh
1 |
$ curl -sS -X GET 192.168.1.2:1026/v2/entities/urn:ngsi-ld:WeatherObserved:sensor002 | jq . |
結果
Orion にアクセスすると、Orion がコンテキスト・プロデューサから取得した、次のような情報はレスポンスとして返却されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "id": "urn:ngsi-ld:WeatherObserved:sensor002", "type": "WeatherObserved", "temperature": { "type": "Number", "value": "23.74", "metadata": {} }, "relativeHumidity": { "type": "Number", "value": "26.87305", "metadata": {} }, "atmosphericPressure": { "type": "Number", "value": "1017.254", "metadata": {} } } |
コンソールの出力
./log.sh でコンソールの出力を確認すると、エンティティ情報取得のリクエスト毎に、Orion から コンテキスト・プロバイダへのリクエストと、コンテキスト・プロバイダから Orion へのレスポンスが表示されます。
1 2 3 4 5 6 7 8 9 |
Start Context Provider path = /v1/weatherObserved/op/query body = {'entities': [{'id': 'urn:ngsi-ld:WeatherObserved:sensor002', 'type': 'WeatherObserved'}], 'attrs': ['temperature', 'relativeHumidity', 'atmosphericPressure']} [{'id': 'urn:ngsi-ld:WeatherObserved:sensor002', 'type': 'WeatherObserved', 'temperature': {'type': 'Number', 'value': '25.47'}, 'relativeHumidity': {'type': 'Number', 'value': '92.09'}, 'atmosphericPressure': {'type': 'Number', 'value': '661.89'}}] 192.168.1.3 - - [29/May/2020 00:00:00] "POST /v1/weatherObserved/op/query HTTP/1.1" 200 - path = /v1/weatherObserved/op/query body = {'entities': [{'id': 'urn:ngsi-ld:WeatherObserved:sensor002', 'type': 'WeatherObserved'}], 'attrs': ['temperature', 'relativeHumidity', 'atmosphericPressure']} [{'id': 'urn:ngsi-ld:WeatherObserved:sensor002', 'type': 'WeatherObserved', 'temperature': {'type': 'Number', 'value': '35.53'}, 'relativeHumidity': {'type': 'Number', 'value': '19.76'}, 'atmosphericPressure': {'type': 'Number', 'value': '1006.29'}}] 192.168.1.3 - - [29/May/2020 00:00:01] "POST /v1/weatherObserved/op/query HTTP/1.1" 200 - |
環境設定のクリーンアップ
レジストレーションの削除
次のクエリでレジストレーションを削除できます。
DELETE /v2/registrations/{id}
./04.delete-registrations.sh
1 2 3 4 |
#!/bin/bash : ${ORION_URL:?Not found} : ${REG_ID:?Not found} curl -isS -H "Fiware-ServicePath: /device" -X DELETE "$ORION_URL/v2/registrations/$REG_ID" |
実行結果
“204 No Content” のレスポンス・コードが返ってくれば、レジストレーションは正常に削除できています。
1 2 3 4 5 |
HTTP/1.1 204 No Content Connection: Keep-Alive Content-Length: 0 Fiware-Correlator: 36509458-a15e-11ea-a5fd-0242ac140004 Date: Fri, 29 May 2020 00:00:04 GMT |
コンテキスト・プロバイダの停止
次のコマンドを実行することで、コンテキスト・プロバイダのコンテナを停止できます。
./stop.sh