IronFlock SDK
IronFlock SDK を使用すると、エッジアプリケーションから IronFlock プラットフォームと連携できます。登録済みデバイスで実行する場合、認証を自動的に処理し、データの公開、履歴のクエリ、デバイス間のリモートプロシージャ呼び出し、デバイスメタデータの更新のための関数を提供します。
| SDK | パッケージ | 必要環境 |
|---|---|---|
| Python | ironflock(PyPI) | Python 3.8+ |
| JavaScript | ironflock(npm) | Node.js 18+ またはモダンブラウザ |
インストール
Python
pip install ironflockまたは、アプリの requirements.txt に ironflock を追加してください。
クイックスタート
Python
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 は環境から接続資格情報を自動的に読み取ります — 手動設定は不要です。
コンストラクタオプション
Python
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 はデータを適切なプロジェクトデータベースに自動的にルーティングします。
Python
await ironflock.publish_to_table("sensordata", {
"temperature": 22.5,
"humidity": 60,
"device_id": "sensor-001"
})appendToTable / append_to_table
Pub/Sub の代わりにリモートプロシージャコールを使用してフリートテーブルにデータを追加します。データが永続化されたことの確認が必要な場合に使用します。
Python
result = await ironflock.append_to_table("sensordata", {
"temperature": 22.5,
"humidity": 60
})publishRowsToTable / publish_rows_to_table
複数の行を 1 つのメッセージで(一括挿入)フリートテーブルに公開します。プラットフォームはバッチ全体を 1 回の操作でアトミックに(オール・オア・ナッシングで)挿入します。1 行ごとにラウンドトリップを行うとコストが高すぎる高頻度データに使用してください。publishToTable と同様に、これはファイア・アンド・フォーゲットです — 確認応答はルーターへの配信を保証するものであり、データベースへの挿入を保証するものではありません。
Python
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 よりもこちらを使用してください。
Python
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 でリアルタイムに配信されます。プラットフォームのシステムエラートーストを発火させることはありません。
Python
# 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)パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
error | str / string または例外 / Error | エラーメッセージ、またはトレースバック/スタック(もしくはメッセージ)が記録される例外 |
level | str / string、オプション | 重大度:"error"、"warn"、"info" または "debug"。デフォルトは "error" |
append | bool / boolean、オプション | true の場合、append RPC を使用します(挿入結果を返します)。デフォルトは false(fire-and-forget の公開) |
tsp | str / string、オプション | ISO-8601 タイムスタンプの上書き。デフォルトは現在時刻 |
Python ではオプションはキーワード引数です(
report_error(error, level=..., append=..., tsp=...))。JavaScript ではオプションオブジェクトを介して渡します(reportError(error, { level, append, tsp }))。
publish
任意の WAMP トピックにメッセージを公開します。データベーステーブルにマッピングされないカスタムメッセージングやイベントに使用します。
Python
await ironflock.publish("com.myapp.alerts", {
"level": "warning",
"message": "Temperature threshold exceeded"
})履歴データのクエリ
getHistory
フリートテーブルから履歴データを取得します。フィルタリング、時間範囲、ページネーションをサポートしています。
Python
# 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}]
})クエリパラメータ:
| フィールド | 型 | 説明 |
|---|---|---|
limit | int / number | 返す最大行数(1〜10,000、必須) |
offset | int / number | ページネーション用のオフセット |
timeRange | dict / object | {"start": "<ISO日時>", "end": "<ISO日時>"} |
filterAnd | list / array | AND 条件のフィルタ、および/または latest マーカー(下記参照) |
columns | list / array | 返すカラム(オプション)。tsp、device_key、authid は常に含まれます。すべてのカラムが必要な場合は省略してください |
フィルタ演算子: =, !=, >, <, >=, <=, LIKE, ILIKE, IN, NOT IN, IS, IS NOT
各フィルタは column、operator、value のキーを持つオブジェクトです。
現在の値の読み取り。 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 では利用できません)。
Python
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"]
})クエリパラメータ:
| フィールド | 型 | 説明 |
|---|---|---|
metrics | list / array | ダウンサンプリングする数値カラム |
method | str / string | バケットごとの集約:"AVG"、"SUM"、"COUNT"、"MIN"、"MAX"、"FIRST" または "LAST" |
limit | int / number | バケットの最大数(1〜10,000) |
timeRange | list / array | [start, end] — ISO 日時文字列またはエポックミリ秒の数値。null = 開区間(必須) |
groupBy | list / array | 系列をグループ化するカラム(オプション) |
filterAnd | list / array | AND フィルタ条件(オプション)。フィルタ条件のみです — ここでは latest マーカーはサポートされていません。現在の値を読み取るには getHistory を使用してください |
データの購読
subscribeToTable / subscribe_to_table
フリートテーブルのリアルタイム更新を購読します。テーブルに新しいデータが公開されるたびにハンドラが呼び出されます。一括挿入パス(publishRowsToTable / appendRowsToTable)で書き込まれた行は、1 行ずつハンドラに配信されるため、データの書き込み方法に関係なくハンドラのコードは変わりません。
Python
def on_sensor_data(*args, **kwargs):
print("New reading:", args, kwargs)
await ironflock.subscribe_to_table("sensordata", on_sensor_data)subscribe
カスタムリアルタイムメッセージング用に任意の WAMP トピックを購読します。
Python
def on_alert(*args, **kwargs):
print("Alert received:", args, kwargs)
await ironflock.subscribe("com.myapp.alerts", on_alert)アプリ間データアクセス
同じプロジェクト内で、別のアプリのフリートデータを自分のアプリから読み取ります。提供側のアプリは、その data-template.yml の consumes: セクションであなたのアプリを宣言する必要があり、プロジェクトユーザーがアクセスを許可する必要があります。アクセスは 読み取り専用 です。提供側が共有するテーブルおよび transform の履歴をクエリしたり、行をリアルタイムに購読したりできますが、書き込むことはできません。消費先アプリへの接続はアプリごとにキャッシュされ、インスタンスが停止すると自動的に閉じられます。
アプリが ワイルドカード 許可(consumes: [{ app: "*" }])を保持している場合、listConsumableApps / list_consumable_apps と connectToAllApps / connect_to_all_apps(下記)を使用して、提供側を動的に検出して開くことができます。
connectToApp / connect_to_app
別のアプリのデータバックエンドへの読み取り専用接続を開き、ハンドルを返します。ハンドルは getHistory / get_history、subscribeToTable / subscribe_to_table、getSeriesHistory / get_series_history(テーブルのみ)を公開します(自分のテーブルで使うのと同じクエリと購読です)。さらに close と、共有された tables / transforms カタログも提供します。
Python
# 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 / appName | str / string | 提供側アプリの名前。consumes: セクションで宣言したもの |
stage | str / string、オプション | 提供側のステージ:"dev" または "prod"。デフォルトは自分のアプリのステージ |
on_error / onError | callable、オプション | 接続確立後にアクセスが拒否された場合(例:許可が後で取り消された場合)に CrossAppAccessError とともに呼び出されます |
アクセスが拒否された、または誤って使用された場合、code フィールドを持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます:NO_GRANT、PROVIDER_NOT_INSTALLED、UNKNOWN_APP、PRIVATE_TABLE、または NOT_AUTHORIZED。
Python では
stageとon_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: "*"Python
providers = await ironflock.list_consumable_apps()
for p in providers:
print(p["app"], list(p["stages"].keys())) # e.g. "weather-app" ["dev", "prod"]各エントリは 1 つの提供側を表します:
| フィールド | 型 | 説明 |
|---|---|---|
app | str / string | 提供側アプリの名前 |
provider_app_key | int / number | 提供側のアプリキー |
stages | dict / object | ステージごとのカタログ { dev?, prod? }。提供側がそのステージのデータバックエンドを持つ場合にのみ、ステージが含まれます。各カタログは、共有される非プライベートな tables と transforms を保持します |
アプリがワイルドカード許可を保持していない場合、code: NO_GRANT を持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます。
connectToAllApps / connect_to_all_apps
プロジェクト内の すべての 非プライベートな提供側への読み取り専用ハンドルを 1 回の呼び出しで開きます(ワイルドカード消費側のみ)。listConsumableApps / list_consumable_apps を介して提供側を列挙し、それぞれを開きます。要求されたステージのデータバックエンドを持たないものはスキップします。各ハンドルは connectToApp / connect_to_app と同じキーでキャッシュされるため、後続の connectToApp(name) は既にウォームアップ済みのハンドルを返します。返されたハンドルは、インスタンスが停止すると一括して閉じられます。
Python
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)パラメータ:
| パラメータ | 型 | 説明 |
|---|---|---|
stage | str / string、オプション | 提供側のステージ:"dev" または "prod"。デフォルトは自分のアプリのステージ |
continue_on_error / continueOnError | bool / boolean、オプション | true(デフォルト)の場合、開くのに失敗した提供側は on_error / onError に報告され、結果から除外されます。false の場合、最初の失敗が送出/スローされます |
on_error / onError | callable、オプション | 開けなかった各提供側とともに呼び出されます(continue_on_error / continueOnError が true の間)。また、既に開かれている接続が後で拒否された場合(例:許可が取り消された場合)に CrossAppAccessError とともに呼び出されます |
正常に開かれた提供側ハンドルを返します(connectToApp / connect_to_app と同じハンドル型)。アプリがワイルドカード許可を保持していない場合、code: NO_GRANT を持つ CrossAppAccessError が送出(Python)/スロー(JavaScript)されます。
Python では
stage、on_error、continue_on_errorはキーワード引数です。JavaScript ではオプションオブジェクトを介して渡します(connectToAllApps({ stage, onError, continueOnError }))。
マネージドファイルストレージ
すべてのアプリのデータバックエンドは、テーブルと並んでプライベートなオブジェクトストレージを備えており、files プロパティからアクセスできます。画像、PDF、カメラフレーム、ファームウェアのバイナリなど、テーブルの行に収めるべきでないものはすべてここに保存します。セットアップは不要です:データテンプレートに files: セクションがないアプリでも、default という名前空間が 1 つ用意されます。
重要なのは、オブジェクトを保存すると 永続的な URL が返され、それをそのままテーブルのカラムに書き込めるという点です。これにより、ダッシュボードのウィジェットは追加の作業なしにそのオブジェクトを表示できます:
Python
# 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 です。
オブジェクトの保存と読み取り
Python
# 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 ページ分。objects、prefixes、is_truncated / isTruncated、および次のページを取得するために渡す cursor を返します |
iter(…) / iterate(…) | プレフィックス配下の すべての オブジェクトを走査する非同期イテレータで、ページングは自動的に行われます。Python では iter、JavaScript では iterate という名前です |
stat(key, namespace?) | 内容を転送せずに、1 つのオブジェクトのメタデータを取得します |
exists(key, namespace?) | オブジェクトが存在するかどうか |
namespaces() | このアプリが使用できる名前空間 |
usage(…) | アプリがどれだけのストレージを使用しているか — 下記を参照 |
catalog() | 名前空間と、サーバーが発行する制限値およびクォータ。最初の呼び出し以降はキャッシュされます |
オブジェクトは、どちらの SDK でも同じフィールドで表現され、名前は各言語の命名スタイルに従います:namespace、key、size、etag、content_type / contentType、last_modified / lastModified、checksum_sha256 / checksumSha256、url。
ストレージ使用量とクォータ
usage は 1 回の呼び出しでオブジェクトストアから直接回答するため、合計値は SDK が足し合わせたものではなく正確な値です:
Python
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 のアプライアンス)、url は None / undefined を返します — これは get にフォールバックすべきという合図です。オブジェクトの etag を version 引数として渡すと、ブラウザはレスポンスをイミュータブルなものとしてキャッシュできます。
upload_url / uploadUrl は、直接アップロードを受け付ける有効期限付きの URL を発行し、url、method、headers、expires_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 では決して行わないでください。
Python
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_LARGE | 1 回の呼び出しでの転送制限を超えています |
OBJECT_TOO_LARGE | 名前空間自身の maxObjectBytes を超えています |
QUOTA_EXCEEDED | ファイルストアが満杯です |
CONTENT_TYPE_NOT_ALLOWED | 名前空間が contentTypes を制限しています |
NOT_SUPPORTED | バックエンドはこれを実行できません |
NOT_AVAILABLE | このデプロイにはファイルサービスがありません |
PRESIGN_UNREACHABLE | オブジェクトストレージに直接到達できません(プロキシが原因かもしれません) |
CLOCK_SKEW | デバイスのクロックのずれが大きすぎます |
INTERNAL | それ以外のすべて |
新しいサーバーは、この SDK リリースが知らないコードを導入する場合があります。それらはまとめられることなく code としてそのまま渡されるため、認識できない値は一般的な失敗として扱ってください。
Python では
FileStoreErrorはironflock.filestoreからインポートします。JavaScript ではパッケージルートからエクスポートされています(import { FileStoreError } from "ironflock")。
デバイス間通信
registerDeviceFunction / register_device_function
同じプロジェクト内の他のデバイスが呼び出せるプロシージャを登録します。SDK は現在のデバイスに対してプロシージャを自動的に名前空間化します。
Python
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 トピックを自動的に組み立てます。
Python
result = await ironflock.call_device_function(
42, # target device key
"com.myapp.add", # procedure name
args=[3, 5] # arguments
)
print(result) # 8call
完全な WAMP URI を使用してリモートプロシージャを呼び出します。正確なトピックがわかっている場合の直接呼び出しに使用します。
Python
result = await ironflock.call("some.full.wamp.topic", args=[42])デバイスメタデータ
setDeviceLocation / set_device_location
プラットフォーム上のデバイスの GPS 位置を更新します。変更は IronFlock マップにリアルタイムで反映されます。
Python
await ironflock.set_device_location(long=8.6821, lat=50.1109)| パラメータ | 範囲 |
|---|---|
long | -180 〜 180 |
lat | -90 〜 90 |
位置履歴は保存されません。位置を時系列で追跡するには、専用テーブルを作成して
publish_to_table/publishToTableを使用してください。
getRemoteAccessUrlForPort
デバイス上の指定ポートのパブリックリモートアクセス URL を返します。
Python
url = ironflock.getRemoteAccessUrlForPort(8080)
# "https://<device_key>-<app_name>-8080.app.ironflock.com"接続プロパティとライフサイクル
Python
| プロパティ | 型 | 説明 |
|---|---|---|
is_connected | bool | プラットフォームへの接続がアクティブかどうか |
connection | CrossbarConnection | 基盤となる接続インスタンス(上級者向け) |
| メソッド | 説明 |
|---|---|
run() | 接続を開始し、mainFunc を実行します(ブロッキング) |
await start() | 接続を非同期で開始します |
await stop() | 接続を停止し、実行中のタスクをキャンセルします |
await run_async() | 接続を開始し、非同期で維持します |
エラー処理
SDK のすべてのメソッドは、失敗を明示的に通知します。引数が不正な場合、接続が失われた場合、プラットフォームから拒否された場合には、操作名・トピック・理由を示すメッセージとともに例外を送出(Python)またはリジェクト(JavaScript)します。エラーが暗黙のうちに握りつぶされることはないため、処理を継続させたい呼び出しは try ブロックで囲んでください。
Python
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();バックエンドのエンドポイントは、接続オプション(serialNumber、deviceKey、appName、swarmKey、appKey、env)を含む JSON オブジェクトを返す必要があります。
AI エージェント関数の登録
SDK は AI エージェントから呼び出し可能な関数を登録できます。プロシージャを登録し、そのトピックを ai-template.yml で参照してください:
Python
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: truetopic の値(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 |
Python
import os
device_name = os.environ.get("DEVICE_NAME")
serial = os.environ.get("DEVICE_SERIAL_NUMBER")
project_key = os.environ.get("SWARM_KEY")