1. はじめに
こんにちは!今回はおんどとり WebStorage APIを使ったデータ取得方法の第3弾です。前回の記事(下記リンク)で紹介したAPI取得の応用バージョンをお届けします。
前回はRTR503Bのみを想定していましたが、今回は新たに2つの機種を追加して動作確認を行いました。(おそらく他の機種でも動作すると思います。)
- RTR503B(温度・湿度)
- TR501B(温度のみ)
- RTR-576(温度・湿度・CO2)
ちなみに、今回は温度・湿度のデータのみを使用し、CO2の値は無視します。
2. レスポンスデータ(JSON)の確認
機種ごとに応答データが少し異なるので、それぞれについて説明します。
-
RTR503B
温度がch1、湿度がch2に格納されています。
"channel":[
{
"name":"ch1",
"num":1,
"unit":"C"
},{
"name":"ch2",
"num":2,
"unit":"%"
}],
"data":[
{
"unixtime": 1234560000,
"data-id":101,
"ch1":23.5,
"ch2":65
},
{
"unixtime": 1234560030,
"data-id":102,
"ch1":25.5,
"ch2":68
},
... ,
{
"unixtime": 1235040000,
"data-id":16100,
"ch1":21.5,
"ch2":60
}
]
-
TR501B
温度のみで、ch1に温度が格納されています。
"channel": [
{
"name": "ch1",
"num": "1",
"unit": "C"
}
],
"data": [
{
"ch1": "26.2",
"data-id": "63702",
"unixtime": "1725438716"
},
{
"ch1": "26.2",
"data-id": "63703",
"unixtime": "1725438776"
},
.... ,
{
"ch1": "26.2",
"data-id": "63704",
"unixtime": "1725438836"
}
]
-
RTR-576
温度がch2、湿度がch3に格納されています。CO2は無視します。
"channel": [
{
"name": "ch1",
"num": "1",
"unit": "ppm"
},
{
"name": "ch2",
"num": "2",
"unit": "C"
},
{
"name": "ch3",
"num": "3",
"unit": "%"
}
],
"data": [
{
"ch1": 839,
ch2: 27.6,
ch3: 64,
data-id: 1,
unixtime: 1725500843
},
.... ,
{
ch1: 885,
ch2: 27.5,
ch3: 58,
data-id: 2,
unixtime: 1725501443
}
]
3. Pythonコードの修正
前回作成したコードを以下の方針で修正しました。
- レスポンスデータから温度と湿度のみを抽出してデータフレームに保存
- 温度・湿度以外のデータは無視
- 温度または湿度のどちらか一方しかない場合は、その片方だけをデータフレームに保存し、もう一方は空欄に
- 温度・湿度どちらもない場合はデータフレームに保存しない
修正したコードはこちらです。
import requests
import pandas as pd
from datetime import datetime, timedelta
import os
from dotenv import load_dotenv
# データフレームの表示で改行を防ぐために、出力幅を広げる
pd.set_option('display.width', 1000)
# おんどとり関連の環境変数をセット
load_dotenv(dotenv_path='./ondotori.env')
# 環境変数から情報を取得
API_KEY = os.getenv('API_KEY')
LOGIN_ID = os.getenv('LOGIN_ID')
LOGIN_PASS = os.getenv('LOGIN_PASS')
REMOTE_SERIAL = os.getenv('REMOTE_SERIAL')
BASE_SERIAL = os.getenv('BASE_SERIAL')
# データを取得してデータフレーム形式へ変換
# 現在の時刻と24時間前の時刻をUNIXタイムスタンプで取得
now = datetime.now()
unixtime_to = int(now.timestamp())
unixtime_from = int((now - timedelta(days=1)).timestamp())
# APIエンドポイントとヘッダー
url = 'https://api.webstorage.jp/v1/devices/data-rtr500'
headers = {
'Content-Type': 'application/json',
'X-HTTP-Method-Override': 'GET'
}
# リクエストボディ
payload = {
'api-key': API_KEY,
'login-id': LOGIN_ID,
'login-pass': LOGIN_PASS,
'remote-serial': REMOTE_SERIAL,
'base-serial': BASE_SERIAL,
'unixtime-from': unixtime_from,
'unixtime-to': unixtime_to,
'type': 'json'
}
# APIリクエスト
response = requests.post(url, headers=headers, json=payload)
# レスポンスのステータスコードを確認
if response.status_code != 200:
raise Exception(f'API request failed with status code {response.status_code}: {response.json().get("error", {}).get("message")}')
# JSONデータを取得
data = response.json()
# チャンネル情報を取得し、変換マッピングを作成
channel_map = {ch['name']: 'temperature' if ch['unit'] == 'C' else 'humidity' if ch['unit'] == '%' else None for ch in data['channel']}
channel_map = {k: v for k, v in channel_map.items() if v is not None}
# データフレームを作成
df = pd.DataFrame(data['data'])
# チャンネル名を変換
df = df.rename(columns={name: channel_map[name] for name in channel_map})
# 必要な列を追加
df['remote_serial'] = data.get('remote-serial')
df['base_serial'] = data.get('base-serial')
df['time'] = pd.to_datetime(df['unixtime'].astype(int), unit='s')
df['id'] = df.apply(lambda row: f"{row['remote_serial']}-{row['base_serial']}-{row['data-id']}-{row['time']}", axis=1)
# temperatureとhumidityのどちらか一方のみのデータの場合、欠損値を設定
if 'temperature' not in df.columns:
df['temperature'] = None
if 'humidity' not in df.columns:
df['humidity'] = None
# 不要な列を削除
df = df[['remote_serial', 'base_serial', 'data-id', 'time', 'temperature', 'humidity', 'id']]
# データフレームを表示
print(df)
今回は以上です!