Skip to Content
IoT アプリ開発IronFlock SDK

IronFlock SDK

IronFlock SDK を使用すると、エッジアプリケーションから IronFlock プラットフォームと連携できます。登録済みデバイスで実行する場合、認証を自動的に処理し、データの公開、履歴のクエリ、デバイス間のリモートプロシージャ呼び出し、デバイスメタデータの更新のための関数を提供します。

SDKパッケージ必要環境
Pythonironflock(PyPI)Python 3.8+
JavaScriptironflock(npm)Node.js 18+ またはモダンブラウザ

インストール

pip install ironflock

または、アプリの requirements.txtironflock を追加してください。

クイックスタート

import asyncio from ironflock import IronFlock async def main(): while True: await ironflock.publish_to_table("sensordata", { "temperature": 22.5, "humidity": 60 }) await asyncio.sleep(5) ironflock = IronFlock(mainFunc=main) ironflock.run()

IronFlock アプリコンテナ内で使用する場合、SDK は環境から接続資格情報を自動的に読み取ります — 手動設定は不要です。

コンストラクタオプション

ironflock = IronFlock( mainFunc=main, # async function to run after connecting serial_number="abc123" # override device serial (optional) )
パラメータ説明
mainFunc接続が確立された後に実行される非同期関数
serial_numberデバイスのシリアル番号を上書きします。デフォルトでは環境変数 DEVICE_SERIAL_NUMBER が使用されます

データの公開

publishToTable / publish_to_table

フリートテーブルにデータレコードを公開します。テーブル名はアプリの data-template.yml で定義されたテーブルと一致する必要があります。SDK はデータを適切なプロジェクトデータベースに自動的にルーティングします。

await ironflock.publish_to_table("sensordata", { "temperature": 22.5, "humidity": 60, "device_id": "sensor-001" })

appendToTable / append_to_table

Pub/Sub の代わりにリモートプロシージャコールを使用してフリートテーブルにデータを追加します。データが永続化されたことの確認が必要な場合に使用します。

result = await ironflock.append_to_table("sensordata", { "temperature": 22.5, "humidity": 60 })

publishRowsToTable / publish_rows_to_table

複数の行を 1 つのメッセージで(一括挿入)フリートテーブルに公開します。プラットフォームはバッチ全体を 1 回の操作でアトミックに(オール・オア・ナッシングで)挿入します。1 行ごとにラウンドトリップを行うとコストが高すぎる高頻度データに使用してください。publishToTable と同様に、これはファイア・アンド・フォーゲットです — 確認応答はルーターへの配信を保証するものであり、データベースへの挿入を保証するものではありません。

await ironflock.publish_rows_to_table("sensordata", [ {"tsp": "2024-01-15T10:30:00.000Z", "temperature": 22.5}, {"tsp": "2024-01-15T10:30:01.000Z", "temperature": 22.7}, ])

第 2 引数は、挿入する行オブジェクトの空でないリストです。

appendRowsToTable / append_rows_to_table

複数の行を 1 つのリモートプロシージャ呼び出しで(一括挿入)フリートテーブルに追加します。プラットフォームはバッチ全体をアトミックに(オール・オア・ナッシングで)挿入します。いずれかの行が無効な場合、バッチ全体が拒否され、何も永続化されません。挿入結果が必要な場合は、publishRowsToTable / publish_rows_to_table よりもこちらを使用してください。

result = await ironflock.append_rows_to_table("sensordata", [ {"tsp": "2024-01-15T10:30:00.000Z", "temperature": 22.5}, {"tsp": "2024-01-15T10:30:01.000Z", "temperature": 22.7}, ]) # result -> {"success": True, "count": 2}

reportError / report_error

アプリケーションエラーをフリートの error-logs テーブルに記録します。これは publishToTable / appendToTable の便利なラッパーです。行に source: "app"、重大度 level、およびタイムスタンプを付与し、通常のテーブル行と同じように書き込みます。エラーは、fleetdb システムエラーが使用するのと同じ error-logs テーブル(source: "system" でタグ付けされる)に格納されるため、getHistory でクエリでき、subscribeToTable / subscribe_to_table でストリーミングでき、ボードテンプレートで使用でき、transformed.error-logs でリアルタイムに配信されます。プラットフォームのシステムエラートーストを発火させることはありません。

# Fire-and-forget (default): publishes to the error-logs table await ironflock.report_error("Sensor read timed out", level="warn") # Pass an exception to capture its traceback (falls back to the message) try: risky_operation() except Exception as err: await ironflock.report_error(err) # Use the append RPC when you want to await the insert outcome await ironflock.report_error("Calibration failed", level="error", append=True)

パラメータ:

パラメータ説明
errorstr / string または例外 / Errorエラーメッセージ、またはトレースバック/スタック(もしくはメッセージ)が記録される例外
levelstr / string、オプション重大度:"error""warn""info" または "debug"。デフォルトは "error"
appendbool / boolean、オプションtrue の場合、append RPC を使用します(挿入結果を返します)。デフォルトは false(fire-and-forget の公開)
tspstr / string、オプションISO-8601 タイムスタンプの上書き。デフォルトは現在時刻

Python ではオプションはキーワード引数です(report_error(error, level=..., append=..., tsp=...))。JavaScript ではオプションオブジェクトを介して渡します(reportError(error, { level, append, tsp }))。

publish

任意の WAMP トピックにメッセージを公開します。データベーステーブルにマッピングされないカスタムメッセージングやイベントに使用します。

await ironflock.publish("com.myapp.alerts", { "level": "warning", "message": "Temperature threshold exceeded" })

履歴データのクエリ

getHistory

フリートテーブルから履歴データを取得します。フィルタリング、時間範囲、ページネーションをサポートしています。

# Simple query data = await ironflock.getHistory("sensordata", {"limit": 100}) # Query with time range and filters data = await ironflock.getHistory("sensordata", { "limit": 500, "offset": 0, "timeRange": { "start": "2026-01-01T00:00:00Z", "end": "2026-03-01T00:00:00Z" }, "filterAnd": [ {"column": "temperature", "operator": ">", "value": 20}, {"column": "humidity", "operator": "<=", "value": 80} ] }) # Current value(s) only: the "latest" marker returns the newest row per entity current = await ironflock.getHistory("sensordata", { "limit": 100, "filterAnd": [{"latest": True}] })

クエリパラメータ:

フィールド説明
limitint / number返す最大行数(1〜10,000、必須)
offsetint / numberページネーション用のオフセット
timeRangedict / object{"start": "<ISO日時>", "end": "<ISO日時>"}
filterAndlist / arrayAND 条件のフィルタ、および/または latest マーカー(下記参照)
columnslist / array返すカラム(オプション)。tspdevice_keyauthid は常に含まれます。すべてのカラムが必要な場合は省略してください

フィルタ演算子: =, !=, >, <, >=, <=, LIKE, ILIKE, IN, NOT IN, IS, IS NOT

各フィルタは columnoperatorvalue のキーを持つオブジェクトです。

現在の値の読み取り。 filterAnd 内の {"latest": true} エントリはフィルタ条件ではなくモードの切り替えです。データバックエンドは、テーブルが maintainLatestFlagFor で宣言したエンティティキーをもとに SQL で導出した、エンティティごとの最新の行のみを返します。エンティティキーを持たないテーブルの場合は、最新の 1 行だけが返されます。

その他の条件は、想定どおりにマーカーと組み合わされます。エンティティキーのカラムに対する条件はどのエンティティを返すかを絞り込み、それ以外のすべての条件と timeRange は、得られた最新の行に対して適用されます。したがって {"latest": true}deleted フィルタを組み合わせると、削除済みのエンティティは非表示になり、その前の行が再び現れることはありません。

以前のバージョンの IronFlock は、物理的な latest_flag カラムを保存していました。このカラムはもう存在しません。レガシーな latest_flag = true フィルタは引き続き受け付けられ、マーカーとして扱われますが、新しいコードでは {"latest": true} を使用してください。latest マーカーは getSeriesHistory では利用できません。

getSeriesHistory / get_series_history

フリートテーブルから ダウンサンプリングされた時系列データ を取得します。数値カラムを時間バケットに集約します(例:1 時間ごとの平均)。長期間にわたるグラフに最適です。テーブルで利用可能です(transform では利用できません)。

series = await ironflock.get_series_history("sensordata", { "metrics": ["temperature", "humidity"], "method": "AVG", "limit": 500, "timeRange": ["2026-01-01T00:00:00Z", "2026-03-01T00:00:00Z"], "groupBy": ["device_id"] })

クエリパラメータ:

フィールド説明
metricslist / arrayダウンサンプリングする数値カラム
methodstr / stringバケットごとの集約:"AVG""SUM""COUNT""MIN""MAX""FIRST" または "LAST"
limitint / numberバケットの最大数(1〜10,000)
timeRangelist / array[start, end] — ISO 日時文字列またはエポックミリ秒の数値。null = 開区間(必須)
groupBylist / array系列をグループ化するカラム(オプション)
filterAndlist / arrayAND フィルタ条件(オプション)。フィルタ条件のみです — ここでは latest マーカーはサポートされていません。現在の値を読み取るには getHistory を使用してください

データの購読

subscribeToTable / subscribe_to_table

フリートテーブルのリアルタイム更新を購読します。テーブルに新しいデータが公開されるたびにハンドラが呼び出されます。一括挿入パス(publishRowsToTable / appendRowsToTable)で書き込まれた行は、1 行ずつハンドラに配信されるため、データの書き込み方法に関係なくハンドラのコードは変わりません。

def on_sensor_data(*args, **kwargs): print("New reading:", args, kwargs) await ironflock.subscribe_to_table("sensordata", on_sensor_data)

subscribe

カスタムリアルタイムメッセージング用に任意の WAMP トピックを購読します。

def on_alert(*args, **kwargs): print("Alert received:", args, kwargs) await ironflock.subscribe("com.myapp.alerts", on_alert)

アプリ間データアクセス

同じプロジェクト内で、別のアプリのフリートデータを自分のアプリから読み取ります。提供側のアプリは、その data-template.ymlconsumes: セクションであなたのアプリを宣言する必要があり、プロジェクトユーザーがアクセスを許可する必要があります。アクセスは 読み取り専用 です。提供側が共有するテーブルおよび transform の履歴をクエリしたり、行をリアルタイムに購読したりできますが、書き込むことはできません。消費先アプリへの接続はアプリごとにキャッシュされ、インスタンスが停止すると自動的に閉じられます。

アプリが ワイルドカード 許可(consumes: [{ app: "*" }])を保持している場合、listConsumableApps / list_consumable_appsconnectToAllApps / connect_to_all_apps(下記)を使用して、提供側を動的に検出して開くことができます。

connectToApp / connect_to_app

別のアプリのデータバックエンドへの読み取り専用接続を開き、ハンドルを返します。ハンドルは getHistory / get_historysubscribeToTable / subscribe_to_tablegetSeriesHistory / get_series_history(テーブルのみ)を公開します(自分のテーブルで使うのと同じクエリと購読です)。さらに close と、共有された tables / transforms カタログも提供します。

# Open a read-only handle on another app's data backend weather = await ironflock.connect_to_app("weather-app") # Inspect what the provider shares print([t["tablename"] for t in weather.tables]) # Query history and subscribe, just like your own tables rows = await weather.get_history("forecasts", {"limit": 100}) def on_forecast(*args, **kwargs): print("New forecast:", args) await weather.subscribe_to_table("forecasts", on_forecast)

パラメータ:

パラメータ説明
app_name / appNamestr / string提供側アプリの名前。consumes: セクションで宣言したもの
stagestr / string、オプション提供側のステージ:"dev" または "prod"。デフォルトは自分のアプリのステージ
on_error / onErrorcallable、オプション接続確立後にアクセスが拒否された場合(例:許可が後で取り消された場合)に CrossAppAccessError とともに呼び出されます

アクセスが拒否された、または誤って使用された場合、code フィールドを持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます:NO_GRANTPROVIDER_NOT_INSTALLEDUNKNOWN_APPPRIVATE_TABLE、または NOT_AUTHORIZED

Python では stageon_error はキーワード引数です。JavaScript ではオプションオブジェクトを介して渡します(connectToApp(appName, { stage, onError }))。

listConsumableApps / list_consumable_apps

プロジェクト内の すべての 非プライベートな提供側を一覧します — ワイルドカード 消費許可(data-template.yml 内の consumes: [{ app: "*" }]、プロジェクトユーザーによって許可される)を保持するアプリのための検出プリミティブです。1 回の呼び出しを実行し、接続は 一切 開きません:返されたカタログをピッカーに表示し、必要なものについて connectToApp / connect_to_app を呼び出します — または connectToAllApps / connect_to_all_apps ですべてを一度に開きます。

注意: アプリの data-template.yml で許可を宣言し、* を引用符で囲んでください — 裸の * は YAML のエイリアスであり、解析できません:

consumes: - app: "*"
providers = await ironflock.list_consumable_apps() for p in providers: print(p["app"], list(p["stages"].keys())) # e.g. "weather-app" ["dev", "prod"]

各エントリは 1 つの提供側を表します:

フィールド説明
appstr / string提供側アプリの名前
provider_app_keyint / number提供側のアプリキー
stagesdict / objectステージごとのカタログ { dev?, prod? }。提供側がそのステージのデータバックエンドを持つ場合にのみ、ステージが含まれます。各カタログは、共有される非プライベートな tablestransforms を保持します

アプリがワイルドカード許可を保持していない場合、code: NO_GRANT を持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます。

connectToAllApps / connect_to_all_apps

プロジェクト内の すべての 非プライベートな提供側への読み取り専用ハンドルを 1 回の呼び出しで開きます(ワイルドカード消費側のみ)。listConsumableApps / list_consumable_apps を介して提供側を列挙し、それぞれを開きます。要求されたステージのデータバックエンドを持たないものはスキップします。各ハンドルは connectToApp / connect_to_app と同じキーでキャッシュされるため、後続の connectToApp(name) は既にウォームアップ済みのハンドルを返します。返されたハンドルは、インスタンスが停止すると一括して閉じられます。

apps = await ironflock.connect_to_all_apps( on_error=lambda err: print("Provider skipped:", err) ) for app in apps: rows = await app.get_history(app.tables[0]["tablename"], {"limit": 10}) print(app.app, rows)

パラメータ:

パラメータ説明
stagestr / string、オプション提供側のステージ:"dev" または "prod"。デフォルトは自分のアプリのステージ
continue_on_error / continueOnErrorbool / boolean、オプションtrue(デフォルト)の場合、開くのに失敗した提供側は on_error / onError に報告され、結果から除外されます。false の場合、最初の失敗が送出/スローされます
on_error / onErrorcallable、オプション開けなかった各提供側とともに呼び出されます(continue_on_error / continueOnErrortrue の間)。また、既に開かれている接続が後で拒否された場合(例:許可が取り消された場合)に CrossAppAccessError とともに呼び出されます

正常に開かれた提供側ハンドルを返します(connectToApp / connect_to_app と同じハンドル型)。アプリがワイルドカード許可を保持していない場合、code: NO_GRANT を持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます。

Python では stageon_errorcontinue_on_error はキーワード引数です。JavaScript ではオプションオブジェクトを介して渡します(connectToAllApps({ stage, onError, continueOnError }))。

マネージドファイルストレージ

すべてのアプリのデータバックエンドは、テーブルと並んでプライベートなオブジェクトストレージを備えており、files プロパティからアクセスできます。画像、PDF、カメラフレーム、ファームウェアのバイナリなど、テーブルの行に収めるべきでないものはすべてここに保存します。セットアップは不要です:データテンプレートに files: セクションがないアプリでも、default という名前空間が 1 つ用意されます。

重要なのは、オブジェクトを保存すると 永続的な URL が返され、それをそのままテーブルのカラムに書き込めるという点です。これにより、ダッシュボードのウィジェットは追加の作業なしにそのオブジェクトを表示できます:

# Store an object and get a permanent URL back in the same call info = await ironflock.files.put("part-1.jpg", jpeg_bytes, content_type="image/jpeg") # The URL is safe to store in a table column — a dashboard widget can then # render <img src="{{photo_url}}"> without any extra round trip await ironflock.publish_to_table("inspections", part_id="1", photo_url=info.url) # Read it back data = await ironflock.files.get("part-1.jpg") # Walk every object under a prefix (pages are fetched for you) async for obj in ironflock.files.iter(prefix="2026/"): print(obj.key, obj.size)

この URL が期限切れになることはありませんが、公開リンクでは ありません:このデータバックエンドに対する READ 権限を持つ認証済みのリクエスト元だけが読み取ることができ、認証プロキシがリクエストのたびにそれを再確認します。したがって、データベースに保存しても安全です。

名前空間

名前空間 は、ポリシー(保持期間、共有ルール、許可されるコンテンツタイプ)を伴うキーのプレフィックスです。個別のバケットではありません。アプリのすべての名前空間は、そのアプリの単一のストレージ領域の中に存在します。宣言するのは、あるオブジェクト群に 異なるルール が必要な場合だけにしてください。それ以外の場合は default のままにして、2026/03/part-1.jpg のようなキーのパスでオブジェクトを整理します。

追加の名前空間は data-template.yml で宣言します:

files: # Storage budget the app suggests for itself. The project user can change it, # and their setting is the one that gets enforced. quotaBytes: 5368709120 namespaces: - name: frames description: Raw camera frames, one JPEG per inspected part. contentTypes: ["image/jpeg"] maxObjectBytes: 20971520 retention: { deleteAfter: 30 days }

この予算は名前空間ごとではなく、アプリ全体に対して一度だけ宣言される点に注意してください。名前空間はアプリの単一のストレージ領域の中にあるキーのプレフィックスにすぎないため、プレフィックスごとの予算を課す対象が存在しません。maxObjectBytes名前空間ごと です — これは合計ではなく、単一のオブジェクトの上限を定めます。

以下のすべてのメソッドは名前空間をオプション引数として受け取り、デフォルトは default です。

オブジェクトの保存と読み取り

# Bytes in, bytes out info = await ironflock.files.put("reports/march.pdf", pdf_bytes, content_type="application/pdf") data = await ironflock.files.get("reports/march.pdf") # Or straight from/to a local file — these stream on the large-object path, # so a multi-gigabyte file never has to fit in memory await ironflock.files.put_file("firmware/v2.bin", "/data/build/v2.bin") await ironflock.files.get_to_file("firmware/v2.bin", "/tmp/v2.bin")
メソッド説明
put(key, data, …)オブジェクトを保存します(Python では bytes、JavaScript では Uint8Array)。url を含むオブジェクトのメタデータを返します
get(key, namespace?)オブジェクトの内容を返します
put_file(key, path, …) / get_to_file(key, path, …)Python のみ。 ローカルファイルから保存、またはローカルファイルへ書き出します。ラージオブジェクトのパスではストリーミングされます
delete(key, namespace?)オブジェクトを削除します
copy(key, to, …)オブジェクトをコピーします。別の名前空間へコピーすることもできます
move(key, to, …)コピーしてから削除します。アトミックではありません — サービスに move の動詞がないため、削除に失敗すると両方のコピーが残ります

JavaScript にファイルパス用のヘルパーがないのは、パッケージが Node とブラウザの両方に対して単一のビルドを提供しているためです — ローカルファイルの読み書きは fs で自分で行ってください。

put が受け取るもの: content_type / contentType(MIME タイプ。名前空間によって許可されるものが制限される場合があります)と namespace。Python ではこれらはキーワード引数です。JavaScript ではオプションオブジェクトに渡します。

一覧取得と検査

メソッド説明
list(…)オブジェクトの 1 ページ分。objectsprefixesis_truncated / isTruncated、および次のページを取得するために渡す cursor を返します
iter(…) / iterate(…)プレフィックス配下の すべての オブジェクトを走査する非同期イテレータで、ページングは自動的に行われます。Python では iter、JavaScript では iterate という名前です
stat(key, namespace?)内容を転送せずに、1 つのオブジェクトのメタデータを取得します
exists(key, namespace?)オブジェクトが存在するかどうか
namespaces()このアプリが使用できる名前空間
usage(…)アプリがどれだけのストレージを使用しているか — 下記を参照
catalog()名前空間と、サーバーが発行する制限値およびクォータ。最初の呼び出し以降はキャッシュされます

オブジェクトは、どちらの SDK でも同じフィールドで表現され、名前は各言語の命名スタイルに従います:namespacekeysizeetagcontent_type / contentTypelast_modified / lastModifiedchecksum_sha256 / checksumSha256url

ストレージ使用量とクォータ

usage は 1 回の呼び出しでオブジェクトストアから直接回答するため、合計値は SDK が足し合わせたものではなく正確な値です:

u = await ironflock.files.usage() print(u.size_bytes, u.object_count, u.quota_bytes, u.free_bytes) # Break the total down per namespace (costs one listing per namespace) detailed = await ironflock.files.usage(detail=True) print(detailed.per_namespace) # {"default": 1048576, "frames": 73400320}
フィールド意味
size_bytes / sizeBytes現在保存されているバイト数
object_count / objectCount保存されているオブジェクトの数
quota_bytes / quotaBytes実際に課される 予算。0 は無制限を意味します
free_bytes / freeBytes残りのバイト数。-1 は無制限を意味します — ここで 0 を返すと「いっぱい」と読めてしまうためです
per_namespace / perNamespace名前空間ごとのバイト数。詳細な内訳を要求したときに のみ 含まれます

名前空間ごとの内訳がデフォルトで無効になっているのは、ストアがそれに直接答えられないためです:ストアはストレージ領域単位で集計しており、名前空間は単なるプレフィックスにすぎないため、SDK が各名前空間を一覧してサイズを足し合わせる必要があります。必要なときに要求してください。ホットパスでは使わないでください。

2 つの異なるクォータが登場するので、区別しておく価値があります。catalog() はその両方を返します:

フィールド意味
quota_bytes / quotaBytes実際に 課される 値で、オブジェクトストアから読み取られます — プロジェクトユーザーの設定です
suggested_quota_bytes / suggestedQuotaBytesアプリのデータテンプレートが要求した値。何も要求していない場合は 0

この 2 つは、ユーザーがアプリの予算を引き上げたり引き下げたりした場合に食い違います。実際に課される値をテンプレートではなくストアから読み取るのはそのためです — アプリを再デプロイしたときに、ユーザーの選択が黙って上書きされてはいけません。UI では両方を表示できます(「アプリの推奨は X ですが、あなたは Y に設定しています」)。実際の制限には常に前者が使われます。

オブジェクトの共有

リンクには 2 種類あり、その違いが重要です:

メソッド有効期間読み取れる相手
url(key, …)永続的このデータバックエンドに対する READ 権限を持つ認証済みのリクエスト元のみ — リクエストのたびに再確認されます。テーブルのカラムに保存しても安全です
share_url / shareUrl有効期限あり(デフォルト 15 分、サーバー側で上限が適用されます)リンクを持っている人なら誰でも。 使用時に認可が再確認されることはありません

share_url / shareUrl はベアラー型のケーパビリティです:一時的なアクセスが必要な人に渡すためのものであり、データベースに保存しないでください。ダッシュボードが表示するものには url を使用してください。

デプロイに HTTP エッジがない場合(たとえばプレーン HTTP のアプライアンス)、urlNone / undefined を返します — これは get にフォールバックすべきという合図です。オブジェクトの etagversion 引数として渡すと、ブラウザはレスポンスをイミュータブルなものとしてキャッシュできます。

upload_url / uploadUrl は、直接アップロードを受け付ける有効期限付きの URL を発行し、urlmethodheadersexpires_in / expiresIn を返します。返されたヘッダーをそのとおりに送信してください。そうしないと署名が検証されません。

ラージオブジェクト

SDK は サイズ に応じて転送方法を自動的に選択します — 設定するものは何もありません:

オブジェクトのサイズ転送経路
インライン制限まで(現在は 6 MiB)メッセージルーターを経由する 1 回の呼び出し
それより大きい場合ルーターを経由せず、HTTPS でオブジェクトストレージへ直接転送

正確な制限値は、実行時にサーバーから catalog()inline_max_bytes / inlineMaxBytes として報告されるため、SDK のリリースなしに引き上げることができます。

上限は 2 つ残っており、どちらの場合も、どちらの上限に達したのかを示す理由とともに TOO_LARGE が報告されます:

  • 5 GiB — オブジェクトストアの単一アップロードの上限です。マルチパートアップロードはまだ実装されていません。
  • 直接エンドポイントがない環境でのインライン制限 — エアギャップされたアプライアンスでは、ラージオブジェクトをそもそも転送できません。リトライしても、チャンクを小さくしても解決せず、メッセージにもそのように記載されます。

直接転送のパスでは、デバイスがルーターだけでなくオブジェクトストレージのホストにも到達できる必要があります。現場でよく起きる 2 つの失敗には、認可の問題のように見えてしまわないよう、専用のコードが用意されています:PRESIGN_UNREACHABLE(ルーターのみを許可しているプロキシ)と CLOCK_SKEW(オブジェクトストアは 15 分以上ずれたリクエストを拒否します — デバイスの NTP を確認してください)。

ファイルストレージのエラー

すべてのファイル操作は、安定した code と人間が読める reason を持つ FileStoreError を送出(Python)/スロー(JavaScript)します。分岐は必ず code で行い、reason では決して行わないでください。

from ironflock.filestore import FileStoreError try: await ironflock.files.put("huge.bin", payload) except FileStoreError as e: if e.code == "QUOTA_EXCEEDED": print("Filestore is full:", e.reason) else: raise
コード意味
NOT_AUTHORIZED呼び出し元はこの操作を実行できません
NO_SUCH_NAMESPACEその名前空間はデータテンプレートで宣言されていません
NO_SUCH_OBJECTそのキーは存在しません
TOO_LARGE1 回の呼び出しでの転送制限を超えています
OBJECT_TOO_LARGE名前空間自身の maxObjectBytes を超えています
QUOTA_EXCEEDEDファイルストアが満杯です
CONTENT_TYPE_NOT_ALLOWED名前空間が contentTypes を制限しています
NOT_SUPPORTEDバックエンドはこれを実行できません
NOT_AVAILABLEこのデプロイにはファイルサービスがありません
PRESIGN_UNREACHABLEオブジェクトストレージに直接到達できません(プロキシが原因かもしれません)
CLOCK_SKEWデバイスのクロックのずれが大きすぎます
INTERNALそれ以外のすべて

新しいサーバーは、この SDK リリースが知らないコードを導入する場合があります。それらはまとめられることなく code としてそのまま渡されるため、認識できない値は一般的な失敗として扱ってください。

Python では FileStoreErrorironflock.filestore からインポートします。JavaScript ではパッケージルートからエクスポートされています(import { FileStoreError } from "ironflock")。

デバイス間通信

registerDeviceFunction / register_device_function

同じプロジェクト内の他のデバイスが呼び出せるプロシージャを登録します。SDK は現在のデバイスに対してプロシージャを自動的に名前空間化します。

def add(a, b): return a + b await ironflock.register_device_function("com.myapp.add", add)

register()register_device_function() のエイリアスです。

callDeviceFunction / call_device_function

別のデバイスが登録したプロシージャを呼び出します。SDK はターゲットデバイスのキーを使用して完全な WAMP トピックを自動的に組み立てます。

result = await ironflock.call_device_function( 42, # target device key "com.myapp.add", # procedure name args=[3, 5] # arguments ) print(result) # 8

call

完全な WAMP URI を使用してリモートプロシージャを呼び出します。正確なトピックがわかっている場合の直接呼び出しに使用します。

result = await ironflock.call("some.full.wamp.topic", args=[42])

デバイスメタデータ

setDeviceLocation / set_device_location

プラットフォーム上のデバイスの GPS 位置を更新します。変更は IronFlock マップにリアルタイムで反映されます。

await ironflock.set_device_location(long=8.6821, lat=50.1109)
パラメータ範囲
long-180 〜 180
lat-90 〜 90

位置履歴は保存されません。位置を時系列で追跡するには、専用テーブルを作成して publish_to_table / publishToTable を使用してください。

getRemoteAccessUrlForPort

デバイス上の指定ポートのパブリックリモートアクセス URL を返します。

url = ironflock.getRemoteAccessUrlForPort(8080) # "https://<device_key>-<app_name>-8080.app.ironflock.com"

接続プロパティとライフサイクル

プロパティ説明
is_connectedboolプラットフォームへの接続がアクティブかどうか
connectionCrossbarConnection基盤となる接続インスタンス(上級者向け)
メソッド説明
run()接続を開始し、mainFunc を実行します(ブロッキング)
await start()接続を非同期で開始します
await stop()接続を停止し、実行中のタスクをキャンセルします
await run_async()接続を開始し、非同期で維持します

エラー処理

SDK のすべてのメソッドは、失敗を明示的に通知します。引数が不正な場合、接続が失われた場合、プラットフォームから拒否された場合には、操作名・トピック・理由を示すメッセージとともに例外を送出(Python)またはリジェクト(JavaScript)します。エラーが暗黙のうちに握りつぶされることはないため、処理を継続させたい呼び出しは try ブロックで囲んでください。

try: rows = await ironflock.getHistory("sensordata", {"limit": 100}) except ValueError as e: # Invalid parameters — e.g. limit out of range, or a malformed filter print(f"Bad query: {e}") except RuntimeError as e: # Not connected, table not in the data-template, or the platform rejected the call print(f"Query failed: {e}")

JavaScript では、プラットフォームに起因する失敗は WampError のインスタンスです。これは通常の Error のサブクラスで、加えて WAMP エラー URI を error に、エラーペイロードを args / kwargs に保持します。それ以外(パラメータの不正、未接続)はプレーンな Error です。

**移行時の注意:**以前のバージョンの SDK は、呼び出しが失敗するとメッセージをログに出力して None / null を返していました。現在は代わりに例外を送出するため、if result is None: のような形のコードでは失敗を検出できません。try / except(または try / catch)を使用してください。

ブラウザでの使用(JavaScript のみ)

JavaScript SDK はモダンブラウザで動作します。ブラウザには環境変数がないため、すべての設定をコンストラクタで渡してください:

import { IronFlock } from "ironflock"; const ironflock = new IronFlock({ serialNumber: "device-serial-from-server", deviceKey: "my-device-key", appName: "MyWebApp", swarmKey: 10, appKey: 20, env: "PROD", }); await ironflock.start(); await ironflock.publishToTable("sensordata", [{ temperature: 22 }]);

資格情報をハードコードする代わりに、IronFlock.fromServer() を使用してバックエンドから設定を取得できます:

const ironflock = await IronFlock.fromServer("/api/ironflock-config"); await ironflock.start();

バックエンドのエンドポイントは、接続オプション(serialNumberdeviceKeyappNameswarmKeyappKeyenv)を含む JSON オブジェクトを返す必要があります。

AI エージェント関数の登録

SDK は AI エージェントから呼び出し可能な関数を登録できます。プロシージャを登録し、そのトピックを ai-template.yml で参照してください:

def get_sensor_reading(sensor_id): """Returns the latest reading from a sensor.""" reading = read_from_hardware(sensor_id) return { "sensor_id": sensor_id, "temperature": reading.temp, "humidity": reading.hum, "timestamp": reading.ts } await ironflock.register_device_function("sensors.get_latest", get_sensor_reading)

ユーザーがリアルタイムのセンサーデータを必要とする質問をした場合、AI エージェントはこの関数を呼び出すことができます。

登録した WAMP トピックを AI エージェントに接続するには、アプリの .ironflock/ai-template.yml で参照してください:

sensor_agent: tool_description: | ユーザーがセンサーの読み取り値、ライブデバイスデータ、または 現在の環境条件について質問した場合に、このエージェントに委任してください。 system_prompt: | あなたはセンサーデータの専門家です。get_current を使って任意のセンサーから 最新の読み取り値を取得してください。回答には必ず単位を含めてください。 main: true max_context_tokens: 30000 max_iterations: 5 tools: get_current: description: センサーの最新の読み取り値を返します。 topic: sensors.get_latest parameters: sensor_id: type: string description: クエリ対象のセンサー識別子。 required: true

topic の値(sensors.get_latest)は、エッジコードで register_device_function / registerDeviceFunction に渡した名前と一致している必要があります。IronFlock は、関数が登録されているデバイスに自動的に呼び出しをルーティングします。

ai-template.yml の完全なリファレンスについては、エージェントとツールの定義を参照してください。

環境変数

以下の変数は、アプリコンテナ内で IronFlock ランタイムによって自動的に設定されます:

変数説明
DEVICE_NAMEデバイスの表示名
DEVICE_SERIAL_NUMBER一意で不変のデバイス識別子
DEVICE_KEY認証用のデバイスキー
SWARM_KEYプロジェクト識別子
APP_KEYアプリ識別子
APP_NAMEアプリ名
ENV環境:DEV または PROD
import os device_name = os.environ.get("DEVICE_NAME") serial = os.environ.get("DEVICE_SERIAL_NUMBER") project_key = os.environ.get("SWARM_KEY")
Last updated on