はじめに
OpenAPIはAPI実装における標準化された手法の一つです。OpenAPIには以下のメリットがあります。
- API仕様書のフォーマットの統一
- サーバーへのリクエストテスト機能
- ツールを用いたコードの雛形の生成
本記事では、Switchbotのスマート家電からデータを取得するAPIをOpenAPIを用いて実装し、取得したデータを表示する方法を紹介いたします。
使用した環境:
- リモート環境(Ubuntu 20.04)
- Docker version 24.0.5
- Python 3.8.10:
- streamlit
- numpy
- matplotlib
また、データ取得をするスマート家電として、自宅においてある Switchbot Hub 2 を用いました。
0. 事前準備
SwitchbotのAPIを利用するためには、アプリの開発者向けオプションをオンにし、トークンを取得する必要があります。手順は以下のページを御覧ください。
本記事では、実装の簡易化のためにAPIのv1.0を利用します。API v1.1で導入された新しい認証方法には対応していません。
以下の本文で YOUR_TOKEN
と記載してある部分は、上記の手順で入手した実際のトークンに置き換えてください。
1. APIの実装
Switchbot APIの仕様を参考に、以下の2つのAPIを定義します。
-
GET /devices
:デバイスの一覧を取得する -
GET /devices/{deviceId}/status
:指定したdeviceId
のデバイスの情報を取得する
また、リクエストヘッダーで、Authorization
パラメータを定義する必要があります。
以下が実装例です。
openapi: '3.0.3'
info:
title: SwitchBot
version: "0.0.1"
servers:
- url: https://api.switch-bot.com/v1.0
security:
- Authorization: []
paths:
/devices:
get:
operationId: devicesget
responses:
200:
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/Devices"
/devices/{deviceId}/status:
get:
operationId: devicesidstatusget
parameters:
- name: deviceId
in: path
required: true
schema:
type: string
responses:
200:
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/StatusOfDevice"
components:
schemas:
Devices:
type: object
properties:
statusCode:
type: integer
message:
type: string
body:
type: object
properties:
deviceList:
type: array
items:
properties:
deviceId:
type: string
deviceName:
type: string
deviceType:
type: string
enableCloudService:
type: boolean
hubDeviceId:
type: string
infraredRemoteList:
type: array
items:
type: object
properties:
deviceId:
type: string
deviceName:
type: string
remoteType:
type: string
hubDeviceId:
type: string
StatusOfDevice:
type: object
properties:
statusCode:
type: integer
message:
type: string
body:
type: object
properties:
deviceId:
type: string
deviceType:
type: string
hubDeviceId:
type: string
humidity:
type: integer
temperature:
type: number
securitySchemes:
Authorization:
type: apiKey
in: header
name: Authorization
上記のコードの確認方法として、Switchbot Editorにコードを貼り付けると、レンダリングされた状態で確認できます。
以下のように、画面右側の部分で入力したAPIを確認できます。
2. コード生成
openapi-generator-cli
を使うことで、定義したOpenAPIのyamlファイルから、クライアントのコードを生成します。openapi-generator-cli
を使う方法はいくつかありますが、ここではdocker
を利用します。作業ディレクトリにapi.yaml
を作成してから、以下を実行します。
$ docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli generate -g python -o /local/client -i /local/api.yaml
実行後に、client
ディレクトリにpython
のコードが生成されます。この生成されたアプリケーションを以下の手順でインストールします。
$ cd client
$ python3 setup.py install --user
3. Webアプリケーションの実装
上記で生成したAPIを通じてSwitchbot Hub 2の温度を取得してグラフとして表示するWebアプリケーションを、streamlit
というフレームワークを用いて実装してみます。
まずSwitchbot Hub 2のデバイスID(以下、YOUR_DEVICE_ID
と表記します)を取得するために、以下のリクエストを実行します。
$ curl -X 'GET' \
'https://api.switch-bot.com/v1.0/devices' \
-H 'accept: application/json' \
-H 'Authorization: ${YOUR_TOKEN}'
正常なレスポンスが取得できた場合、JSON
形式でデバイス一覧情報が表示されます。このとき、body->deviceList
のリストの中で、deviceName
(ハブの名前)が一致する項目のdeviceId
がデバイスID(YOUR_DEVICE_ID
)です。
{
"statusCode": 100,
"body": {
"deviceList": [
{
"deviceId": "YOUR_DEVICE_ID",
"deviceName": "hub",
"enableCloudService": true,
"hubDeviceId": ""
}
],
"infraredRemoteList": [
]
},
"message": "success"
}
以下のコードでは、取得したデバイスIDを用いてハブの温度情報を取得し、グラフ表示します。温度情報の取得間隔は0.1秒
とし、最新1000回分をグラフで表示します。
import streamlit as st
import openapi_client
import numpy as np
import collections
import time
import datetime
from matplotlib import pyplot as plt
configuration = openapi_client.Configuration()
configuration.api_key['Authorization'] = "YOUR_TOKEN"
placeholder = st.empty()
fig = plt.figure()
ax = fig.add_subplot()
queue1 = collections.deque(maxlen=1000)
queue2 = collections.deque(maxlen=1000)
with openapi_client.ApiClient(configuration) as api_client:
api_instance = openapi_client.DefaultApi(api_client)
try:
with placeholder:
while True:
ax.clear()
response = api_instance.devicesidstatusget("YOUR_DEVICE_ID")
queue1.append(response.body.temperature)
queue2.append(datetime.datetime.now())
ax.plot(np.array(queue2, dtype=np.datetime64), np.array(queue1, dtype=np.float32))
ax.set_title(datetime.datetime.now())
placeholder.pyplot(fig)
time.sleep(0.1)
except Exception as e:
print("Exception when calling DefaultApi->devicesget: %s\n" % e)
作業ディレクトリ上にapp.py
を作成してから、アプリケーションを実行します。
$ streamlit run app.py
正常に実行できた場合、アプリケーションのURLが表示されます(例:http://localhost:8555
)。このURLにローカル環境のブラウザからアクセスすると、画面中にグラフが表示されます。
以下はその実行例です。横軸は日時、縦軸は温度/℃を表しています。
4. まとめ
本記事では、以下の機能について紹介しました。
- OpenAPIを用いたAPI定義
- openapi-generator-cliを用いたコード生成
- streamlit/matplotlibを用いたリアルタイムな情報の可視化
記事の前半部分では、OpenAPIを用いることで、実装するプログラミング言語に依存しない形でAPI定義を作成することができることが確認しました。また後半部分では、生成したクライアント側のコードを通じて、簡単にAPIを呼び出す事ができることを確認しました。