API 経由での Measurement 格納

投稿日 / 投稿者名

2018.8.1 / 竹村 直也

はじめに

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

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

難易度 ★★



概要

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

前提条件

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



所要時間(目安)

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



つくるもの

今回は、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 を格納する際には 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 形式が利用できるため、発展としてこちらの利用もご検討ください。