API 経由での Measurement 格納

投稿日 / 投稿者名

2018.8.1 / 竹村 直也

はじめに

本レポートは、Things Cloud の利用例をより知っていただくための実利用レポートとして作成したものです。
Things Cloud は極力後方互換性を持つよう開発されていますが、今後のリリースにより、一部画面やコマンド、手順などが変更となったり、利用できない可能性があることをあらかじめご了承ください。

なお、作成にあたり、以下バージョンを用いています。

  • ver.8.15.8(backend/UI)

難易度 ★★



概要

本レポートでは、API 経由で Measurement データを格納する方法についてご紹介します。
Thins Cloud では Measurement を格納するための API が用意されており、それを利用することでプログラム Measurement データを格納することが可能です。
本レポートを読むことで、CSV で取得したデータを Python を用いて JSON 形式の Measurement に変換して、API 経由で Measurement データを格納する方法を理解することができます。

前提条件

  • 次の言語/フレームワーク/パッケージ管理システムを扱えること
    • Python3 (3.7)
    • pip3
      • requests (2.19.1)
  • テナント内にデバイスが登録済みであること(シミュレーターでも可)

シミュレーターの作成方法は SCADAウィジェットによるデータの可視化 をご参考ください



所要時間(目安)

この手順に沿って、「API 経由で Measurement データ格納」を実現するまでの所要時間。

  • 約30分


つくるもの

今回は、post_measurement.py という Python プログラム の作成を通して、「CSV で取得した温度データを TemperatureMeasurement に変換して、Things Cloud にデータを格納」する基礎を学びます。



1. 関係ファイル

本レポートでは,以下のファイルを利用します.

sample
├── post_measurement.py
└── data.csv


2. サンプルの概要

まず、本レポートで作成したサンプル post_measurement.py の概要は以下のようになっています。

  1. CSV ファイルから1行読み込む
  2. データを Measurement に変換する
  3. 作成した Measurement を Things Cloud に POST

また、Measurement を格納する方法は以下の2つの方法があります。

  • Measurement を1つずつ格納
  • Measurement Collection としてまとめて格納

Measurement を格納する際には API を利用するため、API call としてカウントされます。 大量のデータを格納するケースでは、 Measurement Collection の利用を推奨します。

本レポートで作成したサンプルは、以下の通りです。
詳細については、3. サンプルスクリプトの解説 で説明します。

post_measurement.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

########################################################################
## /**
##  * [Sample code to create and post Measurement]
##  * @param {String} <<CSV_ROW[0]>> temperature
##  * @param {String} <<CSV_ROW[1]>> time
##  * @return HTTP status code
## */
########################################################################

### import library
import csv
import json
from datetime import datetime
import requests # pip3 install --user requests

### YOUR OWN ACCOUNT INFORMATION
USER = "USER_NAME"
PASSWORD = "PASSWORD"
TENANT_NAME = "TENANT_NAME"
GLOBAL_ID = "DEVICE_GLOBAL_ID"
DOMAIN = "https://" + TENANT_NAME + ".je1.thingscloud.ntt.com"

ENDPOINT = "measurement/measurements"
URL = DOMAIN + "/" + ENDPOINT
FILE_NAME = "data.csv"

### Measurement format
measurement = {
    "c8y_TemperatureMeasurement": {
        "T": {
            "value": 0,
            "unit": "C"
        }
    },
    "time": "",
    "source": {
    	"id": GLOBAL_ID
    },
    "type": "c8y_TemperatureMeasurement"
}
### Object for Measurement Collection
measurements = {
    "measurements": []
}

### Header for Measurement
headers_1 = {
    "content-type": "application/json",
    "accept": "application/vnd.com.nsn.cumulocity.measurement+json"
}
### Header for Measurement Collection
headers_2 = {
    "content-type": "application/json",
    "accept": "application/vnd.com.nsn.cumulocity.measurementCollection+json"
}

### Read CSV
with open(FILE_NAME, "r") as f:
    reader = csv.reader(f)
    header = next(reader)
    print("Measurement")
    for row in reader:
        measurement["c8y_TemperatureMeasurement"]["T"]["value"] = int(row[0])
        # set time_value to time in CSV
        measurement["time"] = row[1]
        # # set time_value to current time
        # measurement["time"] = datetime.utcnow().isoformat()

        ##################################################
        # POST Measurement (Sequential transmission)
        ##################################################
        r = requests.post(URL, auth=(USER, PASSWORD), headers=headers_1, data=json.dumps(measurement))
        print("status : " + str(r.status_code))
        measurements["measurements"].append(measurement)

##################################################
# POST Measurement Collection (Bulk transmission)
##################################################
r = requests.post(URL, auth=(USER, PASSWORD), headers=headers_2, data=json.dumps(measurements))
print("Measurement Collection")
print("status : " + str(r.status_code))

data.csv

temperature,time
-10,2018-07-04T01:15:38.144343+09:00
-5,2018-07-04T01:25:39.017374+09:00
0,2018-07-04T01:35:39.814033+09:00
5,2018-07-04T01:45:41.088180+09:00
10,2018-07-04T01:55:41.088180+09:00


3. サンプルスクリプトの解説

必要なライブラリ

スクリプトの冒頭で以下のライブラリをインポートします。

### import library
import csv
import json
from datetime import datetime
import requests # pip3 install --user requests

requests はデフォルトでは利用できないため、下記のコマンドでインストールします。

$ pip3 install --user requests



テナント情報の設定

次に、ユーザーのアカウント情報を設定します。

### YOUR OWN ACCOUNT INFORMATION
USER = "USER_NAME"
PASSWORD = "PASSWORD"
TENANT_NAME = "TENANT_NAME"
GLOBAL_ID = "GLOBAL_ID"
DOMAIN = "https://" + TENANT_NAME + ".je1.thingscloud.ntt.com"

ENDPOINT = "measurement/measurements"
URL = DOMAIN + "/" + ENDPOINT
FILE_NAME = "data.csv"

今回指定したエンドポイント measurement/measurements に対して POST リクエストを行うことで、新規 Measurement を格納することができます。
また、2つの格納方法は共に、同じエンドポイント measurement/measurements を利用します。

Measurement フォーマットの作成

以下は、(Temperature)Measurement のフォーマットです。
格納したい Measurement の種類やデバイスに応じて、以下を変更してください。

変更項目 参照方法
取り扱う Measurement measurement[“Measurement の フラグメント”]
デバイスの Global ID measurement[“source”][“id”]
取得時間 measurement[“type”]
### Measurement format
measurement = {
    "c8y_TemperatureMeasurement": {
        "T": {
            "value": 0,
            "unit": "C"
        }
    },
    "time": "",
    "source": {
    	"id": GLOBAL_ID
    },
    "type": "c8y_TemperatureMeasurement"
}

また、センサーが所得したデータを格納する際に、データごとに変更する項目は以下の2つです。

変更項目 参照方法
センサー取得値 measurement[“c8y_TemperatureMeasurement”][“T”][“value”]
取得時間 measurement[“time”]

以下は、Measurement Collection 用の配列です。
Measurement をまとめて格納するために利用します。

### Object for Measurement Collection
measurements = {
    "measurements": []
}



Header の設定

本レポートでは、2つの方法による Measurement の格納方法をご紹介します。
それぞれ設定する Header が異なる点に注意してください。


Measurement を1つずつ格納

accept***measurement+json となっていることにご注意ください。

### Header for Measurement
headers_1 = {
    "content-type": "application/json",
    "accept": "application/vnd.com.nsn.cumulocity.measurement+json"
}



Measureent Collection としてまとめて格納

accept***measurementCollection+json となっていることにご注意ください。

### Header for Measurement Collection
headers_2 = {
    "content-type": "application/json",
    "accept": "application/vnd.com.nsn.cumulocity.measurementCollection+json"
}



CSV からデータ取得

Measurement のフォーマットに対して、CSV から取得した 温度 と 取得時間 を代入します。
CSV にカラムのタイトルが存在する場合は、 header = next(reader) を実行することでタイトルを取り出すことできます。

with open(FILE_NAME, "r") as f:
    reader = csv.reader(f)
    header = next(reader)
    print("Measurement")
    for row in reader:
        measurement["c8y_TemperatureMeasurement"]["T"]["value"] = int(row[0])
        # set time_value to time in CSV
        measurement["time"] = row[1]
        # # set time_value to current time
        # measurement["time"] = datetime.utcnow().isoformat()



Measurement 格納

Measurement を1つずつ格納

requests.post(URL, auth=(USER, PASSWORD), headers=headers_1, data=json.dumps(measurement)) を実行することで、Measurement を1つずつ格納できます。
ここで用いる Header は、headers_1 であることにご注意ください。

with open(FILE_NAME, "r") as f:
    # omission
    for row in reader:

        # omission

        ##################################################
        # POST Measurement (Sequential transmission)
        ##################################################
        r = requests.post(URL, auth=(USER, PASSWORD), headers=headers_1, data=json.dumps(measurement))
        print("status : " + str(r.status_code))
        measurements["measurements"].append(measurement)



Measurement Collection としてまとめて格納

requests.post(URL, auth=(USER, PASSWORD), headers=headers_2, data=json.dumps(measurement)) を実行することで、Measurement Collection としてまとめて格納できます。
ここで用いる Header は、headers_2 であることにご注意ください。

##################################################
# POST Measurement Collection (Bulk transmission)
##################################################
r = requests.post(URL, auth=(USER, PASSWORD), headers=headers_2, data=json.dumps(measurements))
print("Measurement Collection")
print("status : " + str(r.status_code))


4. 実行結果

下図のような実行結果になっていれば、Measurement 格納成功です。
レスポンスの HTTP ステータスコードが 201 になっていることをご確認ください。

実行結果

以上が、CSV ファイルのデータを Measurement に変換し、Things Cloud に格納する方法です。

また、本レポートでは利用しませんでしたが、Things Cloud には SmartREST という機能もあります。
SmartRESTエンドポイントとの通信には CSV 形式が利用できるため、発展としてこちらの利用もご検討ください。