AmbientからThingSpeakへ ― PythonのIoTデータ取得コードを移行する際の6つのポイント

みなさん、こんにちは。

前回の記事では、M5StickC側の送信プログラムをAmbientからThingSpeakへと書き換える手順について解説しました。(M5StickC Plus でも可)

今回はその続編(Python改修編)です。

我が家では、自宅の温湿度・CO2センサーのデータをもとにAlexaにアラートを喋らせる自作プログラム(heatstroke_alert)をRaspberry Pi 4上で動かしています。

このプログラムのデータ取得元をAmbientからThingSpeakへと切り替える際に直面したポイントと、具体的なコードの変更例をまとめました。


Pythonプログラム改修の背景

これまでは ambient-python-lib という専用ライブラリを使用し、Ambientから定期的にセンサーデータを読み出して判定を行っていました。

今回、データ収集基盤全体をThingSpeakに統一することにしたため、Raspberry Pi側のデータ取得用Pythonコードも対応させる必要が出てきました。対応自体はClaude Codeであっという間だったのですが、コードを確認した上で、改修ポイントを解説していきます。


移行時の主なポイントとコード変更

1. 専用ライブラリ不要! requests でREST APIを直接叩く

Ambientでは専用のPythonライブラリをセットアップしてデータを取得していましたが、ThingSpeakには公式ライブラリを使わずとも、標準的な requests モジュールだけで完結するシンプルなREST APIが用意されています。

わざわざ専用ライブラリを追加でインストールする必要がなくなり、依存関係を極めてシンプルに保てるのが嬉しいポイントです。

▼ 変更前(Ambient)
from ambient import Ambient

ambient = Ambient(AMBIENT_CHANNEL_ID, AMBIENT_WRITE_KEY, AMBIENT_READ_KEY)
data = ambient.read(n=1)  # 最新の1件のデータを取得

if data and len(data) > 0:
    temperature = data[0].get('d1')  # d1が温度
    humidity = data[0].get('d3')     # d3が湿度
▼ 変更後(ThingSpeak)
import requests

url = f"{THINGSPEAK_BASE_URL}/channels/{THINGSPEAK_CHANNEL_ID}/feeds.json"
params = {
    "api_key": THINGSPEAK_READ_API_KEY,
    "results": 1,
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
data = response.json()
feeds = data.get("feeds")

if feeds:
    latest = feeds[-1]
    temperature = latest.get("field1")  # field1が温度
    humidity = latest.get("field3")     # field3が湿度

プロジェクトの requirements.txt も、Git直接指定からPyPIのパッケージ指定になりスッキリしました。

- git+https://github.com/AmbientDataInc/ambient-python-lib.git
+ requests

2. データ項目名が「d1, d2…」から「field1, field2…」に変わる

AmbientのAPIレスポンスに含まれるデータ項目のキーは d1, d2, d3… でしたが、ThingSpeakでは field1, field2, field3… というキー名に変わります。

送信側のマイコン(M5StickCなど)でどのフィールドに何を割り振ったかを確認し、あらかじめ以下のような対応表を作っておくと移植作業がとてもスムーズになります。

【今回のプロジェクトにおける対応例】

フィールド割り当てデータ
field1温度
field2二酸化炭素濃度(CO2)
field3湿度
field4バッテリー電圧

3. 【ハマりどころ】レスポンスの値が「文字列型」で返ってくる

Ambientのライブラリでは値が数値型(int / float)として返ってきていましたが、ThingSpeakの feeds.json APIは、各フィールドの値を文字列型(string)で返します。

そのため、取得した値を数値比較や計算で使いたい場合は、明示的に float()int() でキャストしなければなりません。見落としがちな型差分ですので注意しましょう。

co2 = feeds[-1].get("field2")

if co2 is None:
    logger.error("ThingSpeakからのデータでCO2濃度が取得できませんでした")
    return None

return float(co2)  # ⚠️ 文字列型で返ってくるため float へのキャストをお忘れなく!

4. 最新データの取り出し方に注意([0] ではなく [-1]

Ambientの ambient.read(n=1) は配列の先頭に最新データが入る設計でしたが、ThingSpeakの feeds.json?results=1 は古い順(昇順)で配列が返ってきます。

1件だけリクエストしている場合は [0] でも動きますが、複数件取得した際にAmbient時代の data[0] という書き方を引きずってしまうと、「最新データではなく過去のデータ」を参照するバグに繋がります。最新データを取り出す際は、配列の末尾を示す [-1] を指定するのが確実です。

feeds = data.get("feeds")
if feeds:
    latest = feeds[-1]  # 最新データは配列の末尾(-1)

5. 認証情報がシンプルに(チャネルID + Read APIキー)

Ambientではデータ受信(読み取り)専用のスクリプトであっても、「チャネルID」「ライトキー」「リードキー」の3つを設定保持する必要がありました。

対するThingSpeakでは、読み取り用途であれば「チャネルID」と「Read APIキー」の2つだけで完結します(チャネルをPublic公開設定にしていればRead APIキーすら省略可能です)。環境変数や設定ファイルのパラメータ数が減り、コードの管理が楽になりました。

# Before (Ambient)
AMBIENT_CHANNEL_ID = ""
AMBIENT_WRITE_KEY = ""
AMBIENT_READ_KEY = ""

# After (ThingSpeak)
THINGSPEAK_CHANNEL_ID = ""
THINGSPEAK_READ_API_KEY = ""

6. エラーハンドリングは requests の標準的な流儀に

専用ライブラリ内部で自動処理されていたHTTP通信エラーも、requests を直接使う場合は自前でハンドリングを行います。

response.raise_for_status() を使ってステータスコード異常(4xx / 5xx)を捕捉するのと併せて、timeout を明示的に指定してネットワーク不通時の永久ハングを防ぐのがポイントです。

try:
    response = requests.get(url, params=params, timeout=10)
    response.raise_for_status()
    data = response.json()
    feeds = data.get("feeds")
    if feeds:
        ...
    else:
        logger.error("ThingSpeakからのデータが空です")
except Exception as e:
    logger.error(f"データ取得中にエラーが発生しました: {str(e)}")

return None

移行作業のまとめ

AmbientからThingSpeakへPythonスクリプトを移行する際のポイントをまとめました。

  1. 専用ライブラリは不要
    ⇒ requests でREST APIを直接コールすればOK
  2. キー名の変更
    ⇒ d1/d2 から field1/field2 に変更
  3. データ型に注意
    ⇒ 取得値は「文字列型」なので float() などの数値変換が必要
  4. 配列の並び順
    ⇒ 取得データ配列の末尾([-1])が最新データ
  5. 認証パラメータの削減
    ⇒ チャネルID+Read APIキーの2つのみでスッキリ
  6. 通信処理の自前実装
    ⇒ timeout 設定と raise_for_status() による例外処理を追加

サービスごとにAPIの設計思想(公式同期ライブラリを使うか、標準REST APIか/データ型/レスポンスの配列順)が異なります。単なるAPI URLの書き換えにとどめず、実際のJSONレスポンスをよく確認しながら1ステップずつ移植していくのが安全です。

これでM5StickCからのデータ送信側だけでなく、Raspberry Pi側のデータ取得・アラート通知処理も無事にThingSpeakへの切り替えが完了しました!

GitHubのリポジトリはThingSpeak版にアップデートしているので、困っている方がいたら参考にしてください。

参考:https://github.com/taoman26/heatstroke_alert


「自分もIoTで何か作ってみたい」と思われた方、そのアイデア、頭の中で寝かせておくのはもったいないかもしれません。

ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、現場で「使い続けられる」ものづくりを支援しています。

アイデアを短期間で「動くもの」にし、PoCで終わらせず、実運用まで伴走します。まずは「これ、作る価値ありますか?」という壁打ちからでも大歓迎です。

▶ PoC・MVP開発サービスの詳細はこちら

気になることがあればお気軽にご相談ください。

本日も最後までお読みいただきありがとうございました。

それでは、よいIoTライフを!

カテゴリ: IoT, Raspberry Pi

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール