aptpod Tech Blog

株式会社アプトポッドのテクノロジーブログです

SDK入門①〜社用車で走ったとこ全部見せます〜

もっと柔軟にintdashを活用したいみなさん、

こんにちは。ソリューションアーキテクトの伊勢です。

近年、お客様やパートナー様が自らカスタム機能を実装する場面が増えています。

intdashではサーバーAPIにアクセスするためのSDKを提供しています。 構成を刷新したintdash SDKが2024年6月バージョンより正式リリースとなりました。1

SDKは非常に幅広い使い方が可能です。

入門シリーズとして実践的な内容に落とし込んで解説していきます。

はじめに

intdash APIとは

産業向けIoTデータ伝送プラットフォームであるintdashが、製品群やサーバー外にデータを受け渡すためのインタフェースです。

2つのAPIがあります。

種類 概要 通信プロトコル 用途
REST API いわゆるGETやPOSTのリクエスト・レスポンス HTTP/HTTPS ユーザー/エッジ/計測などの参照・更新
リアルタイムAPI 高速データ伝送向けの特殊なAPI aptpod独自のiSCP 計測データのストリーム2

intdash SDKとは

intdash APIを利用するためのクライアントライブラリーです。

各種プログラミング言語向けに対応しています。

intdash SDK

各種プログラミング言語の使いどころはこんな感じです。

言語 特徴・用途
Python 入門向け、プロトタイピング、AI/機械学習
Go 高速・並列サーバー処理、バックエンドシステム構築
Rust 高速・メモリ安全性、リソースが限られるエッジ処理
TypeScript ブラウザ・フロントエンド
Swift iPhoneアプリ
C# Windowsプラットフォーム、Unityアプリ
Kotlin Androidアプリ、Java互換

この入門シリーズではintdash SDK for Pythonを使って説明します。

intdash API/SDKでできること

intdash APIへのデータフローは

2つのAPI ✖️データ取得/データ送信

に大別され、これを組み合わせてカスタム処理を実装します。

入門シリーズでもこの順で説明していきます。

# データフロー 適用例
REST APIで計測データ取得 データ分析、レポーティング
REST APIで計測データ送信 データ登録、保留データアップロード
リアルタイムAPIで計測データ取得 遠隔監視、リアルタイムデータ分析
リアルタイムAPIで計測データ送信 遠隔制御、リアルタイムデータ登録

目的別のインストール手順・必要ソフトウェア

実現したいことによって対応した手順が必要です。

# SDKインストール手順 必要ソフトウェア
OpenAPI Generatorで生成 Java、npm
OpenAPI Generatorで生成
Protocol Buffersエンコーダーを生成
Java、npm、Buf CLI

パッケージをインストール 各言語のパッケージ管理ツール

具体的な手順は記事ごとに説明します。3

インストール

今回はREST APIでデータ取得するためのインストール方法を説明します。

手順

少し多いため、説明しながら進めていきます。

  • OpenAPI GeneratorでSDK生成
    • Javaインストール
    • npmインストール
    • OpenAPI Generatorインストール
    • intdash SDK for Python生成
  • Python実行環境設定
    • Pythonインストール
    • Python仮想環境の設定
    • 依存パッケージインストール
  • 動作確認
    • import確認
    • エッジ一覧取得
  • Python開発環境整備
    • Pythonパス設定
    • フォーマッター、Linterの整備
  • サンプルプログラム準備
    • 利用パッケージインストール
  • サンプルプログラム実行

OpenAPI GeneratorでSDK生成

REST API用のSDKをOpenAPI Generatorで生成します。

Javaインストール

OpenAPI Generator を実行するためにJava実行環境が必要です。

Javaが実行できるか確認します。

java --version

存在しない場合はインストールします。

brew install openjdk

OpenJDKのインストールと確認

npmインストール

OpenAPI Generator をインストールするために、Node.jsのパッケージ管理ツール npmが必要です。

npmはNode.jsに含まれているため、Node.jsをインストールします。

brew install node
npm -v

Node.jsのインストール

OpenAPI Generatorインストール

OpenAPI Generator は、API仕様に基づいてクライアントライブラリー、ドキュメントなどを自動生成するツールです。

インストールしてバージョンを確認します。

npm install @openapitools/openapi-generator-cli
npx @openapitools/openapi-generator-cli version  

OpenAPI Generatorのインストール

intdash SDK for Python生成

intdashのAPI仕様からSDKを生成します。

OpenAPI Specificationファイルのバージョンを指定します。

package-nameで指定するパッケージ名でディレクトリが生成されます。

また、開発時に参照するドキュメントを生成しています。

VERSION=v2.7.0
SRC_DIR="."
./node_modules/.bin/openapi-generator-cli version-manager set 6.1.0
./node_modules/.bin/openapi-generator-cli generate \
-g python -i https://docs.intdash.jp/api/intdash-api/${VERSION}/openapi_public.yaml \
    --package-name=intdash \
    --additional-properties=generateSourceCodeOnly=true \
    --global-property=modelTests=false,apiTests=false,modelDocs=true,apiDocs=true \
    --http-user-agent=SDK-Sample-Python-Client/Gen-By-OASGenerator \
    -o "$SRC_DIR"
ls -l intdash

intdash SDKの生成

Python実行環境設定

Pythonプログラムを実行する環境を構築します。

Pythonインストール

Pythonが実行できるか確認します。

python --version

存在しない場合はインストールします。

brew install python
python --version

Pythonのインストール

Python仮想環境作成

Python仮想環境を作成します。

ローカルPCのPythonバージョンアップが開発中のプログラムに影響するのを防ぐため、仮想環境は有効です。

Pythonと任意のバージョンを指定して仮想環境を作成します。 作成後に有効化して、Pythonとパッケージ管理ツール pipのバージョンを確認します。

python3.xx -m venv venv
. ./venv/bin/activate
python --version
pip --version

Python仮想環境の作成

依存パッケージインストール

intdash SDKが利用するPythonパッケージをインストールします。

  • pydantic: データバリデーションおよびデータモデルライブラリ
  • python-dateutil: 日付と時刻の操作ライブラリ
  • urllib3: HTTPクライアントライブラリ
pip install pydantic python-dateutil urllib3

必要パッケージのインストール

これでSDKを利用できる準備が整いました。

動作確認

簡単なリクエストを試してみます。

import確認

Pythonを起動してpackage-nameで指定したパッケージをimportします。

エラーが出なければ、正常に読み込めています。

python
>>> import intdash

import確認

エッジ一覧取得

最も簡単な例としてエッジ一覧を取得してみます。

intdash APIの認証方法には3種類あります。

  • ユーザーで認証:
    • ユーザーに紐づくAPIトークンで認証
    • ユーザー情報に基づいてアクセストークンを払い出して認証
  • エッジで認証:
    • エッジ情報に基づいてアクセストークンを払い出して認証

今回はAPIトークンで認証します。

intdashのUIであるWeb ConsoleのMy Pageで払い出します。

APIトークン払い出し

エッジサービスのAPIオブジェクトを生成してエッジ一覧の取得メソッドを呼びます。

from intdash import ApiClient, Configuration
from intdash.api import authentication_service_edges_api

# APIトークンで認証
client = ApiClient(
    Configuration(
        host="https://example.intdash.jp/api",
        api_key={
            "IntdashToken": "YOUR_API_TOKEN"
        },
    )
)

# エッジサービスのAPIオブジェクトを生成
api = authentication_service_edges_api.AuthenticationServiceEdgesApi(client)

# エッジ一覧の取得
edges = api.list_edges()
print(edges)

エッジ一覧取得

intdash SDKでREST APIにアクセスできました。

基本的にはこのように

  • 認証
  • 各サービスAPIのメソッドでREST APIにアクセス

を実装していきます。

Python開発環境整備

開発効率を高めるために開発環境の整備は重要です。

開発者によって好みが分かれるところですが、このサンプル作成に使ったVS Code設定をご紹介します。

なお、作成した仮想環境をVS CodeのSelect Interpreterで指定しておくとターミナル起動時に楽です。

Pythonパス設定

生成したSDKを含めてPython実行時にサンプルプログラムを参照できるように環境変数PYTHONPATHにワークスペースを設定します。

    "terminal.integrated.env.osx": {
        "PYTHONPATH": "${workspaceFolder}"
    },
フォーマッター、Linterの整備

VS Codeの拡張機能で以下をインストールします。

  • Ruff:Python向けの高速なフォーマッター兼Linter
  • My Type Checker:Pythonの静的型チェックツール

Ruffの設定です。

保存時に自動でフォーマット、Lintエラー修正、importの整列・削除をさせています。

    "[python]": {
        "editor.formatOnSave": true,
        "editor.defaultFormatter": "charliermarsh.ruff",
        "editor.codeActionsOnSave": {
            "source.fixAll.ruff": "explicit",
            "source.organizeImports.ruff": "explicit",
        },
    },

My Type Checkerの設定です。

型チェック中に見つからないインポートがあってもエラーを無視します。外部ライブラリで型情報が不足している場合に有効です。

    "mypy-type-checker.args": [
        "--disallow-untyped-defs",
        "--ignore-missing-imports",
    ],
    "mypy-type-checker.showNotifications": "onError",

やってみた

特定のエッジの計測のうち、GPSデータを全部取り出して地図上にプロットします。

サンプルプログラムをGitHubで公開しています。

github.com

対象とするエッジはこちらです。

歴戦の社用車

社用車には当社製エッジコンピューター EDGEPLANT T1が搭載されています。

開発用(上段)と営業デモ用(下段)

準備

追加で実行前の準備があります。

利用パッケージインストール

サンプルプログラムに必要なパッケージをインストールします。

pip install folium matplotlib
  • folium: OpenStreetMap表示
  • matplotlib: 地図プロット時のカラー情報制御

実行結果

PYTHONPATHが指定されていないときは設定します。

echo $PYTHONPATH
export PYTHONPATH=/path/to/your_workspace:

実行します。

python lesson1/src/gnss_plot.py --api_url https://example.intdash.jp --api_token <YOUR_API_TOKEN> --project_uuid <YOUR_PROJECT_UUID> --edge_uuids <YOUR_EDGE_UUID1> <YOUR_EDGE_UUID2> <YOUR_EDGE_UUID3>

社用車のエッジUUIDは何回か変わっているため、複数指定できるようにしました。

実行
HTMLが出力されます。

1都10県

GPSデータの緯度経度をプロットしています。

  • 2020年1月からの計測1,400件を取得
  • 取り出したGPSデータの緯度経度を10分ごとにサンプリング
  • 会社からの距離が近いほど青く遠いほど赤く描画
  • 訪問先でエッジを起動した場合はルート途中は描画されない

サンプルプログラム説明

REST APIアクセス部分を解説します。

構成図

時系列データベースに蓄積された計測データをREST APIから取り出します。

GSPデータを取得して地図描画

計測リスト取得

プロジェクトUUID、エッジUUIDを指定して計測のリストを取得しています。

    api = measurement_service_measurements_api.MeasurementServiceMeasurementsApi(client)
    measurements = api.list_project_measurements(
        project_uuid=project_uuid, edge_uuid=edge_uuid, limit=LIMIT
    )

開発中の大量データ取得防止のためlimitで取得件数を絞っています。

データポイントリスト取得

計測ごとにデータポイントを取得します。

取得対象を緯度経度に限定します。

data_id_filterで以下のいずれかを指定していします。

  • #:0/GNRMC
    • T1から収集されるNMEAフォーマットの緯度経度を含むGNRMC
  • #:1/gnss_coordinates
    • iPhoneアプリ intdash Motion V2で収集されるフォーマットの緯度経度
    api = measurement_service_data_points_api.MeasurementServiceDataPointsApi(client)
    stream = api.list_project_data_points(
        project_uuid=project_uuid,
        name=meas_uuid,
        data_id_filter=[
            "#:0/GNRMC",  # NMEA
            "#:1/gnss_coordinates",  # intdash Motion
        ],
    )

データポイントは複数行に分かれたJSONであるJSONLines形式で取得されます。

1行ごとにJSON化して、データを取り出します。

  • #:0/GNRMC
    • JSONのdata.sから取得
      • 旧プロトコルiSCPv1で送信されたデータの格納形式
      • 社用車のT1がiSCPv1で送信するため
    • NMEAフォーマットのCSV形式をパースして緯度経度を取得
  • #:1/gnss_coordinates
    • JSONのdata.dから取得
      • 新プロトコルiSCPv2の格納形式
    • BASE64文字列をデコードしてバイナリ値を取得
    • 2次元ベクトルであるバイナリ値から64ビット浮動小数点数値を2つ取得
        line_json = json.loads(line.decode())
        if "data" in line_json:
            # iSCPv1 NMEA
            if "s" in line_json["data"]:
                x, y = parse_gnrmc(line_json["data"]["s"])

            # iSCPv2
            elif "d" in line_json["data"]:
                base64_encoded = line_json["data"]["d"]
                bin_data = base64.b64decode(base64_encoded)
                x, y = struct.unpack(">dd", bin_data)

おわりに

今回はシリーズ初回としてSDKの概要とREST APIでのデータ取得をご紹介しました。

次回はより高度な使い方を試していきます。

今回少し触れた取得データの形式についてもより詳細に説明します。


  1. 2022年11月バージョンからPublic Beta版を利用できました。
  2. ストリームとは
  3. 記事ではMacでの手順を説明します。GitHubにWindowsの手順も掲載します。