11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

業務でEfento Cloudを簡単に試す機会がありました。

Efento Cloudは、Efento社が提供するIoTセンサーデータを管理するためのクラウドサービスです。Efento社は2014年にポーランドで設立された比較的新しい企業であり、温度、湿度、気圧、CO2など様々な環境データを収集・管理できるIoTセンサーデバイスを販売しています。収集したセンサーデータは、Efento Cloudで確認、分析することができます。

今回はそんなEfento Cloudの、特にAPIの利用方法を中心にまとめたいと思います。
執筆時点(2025年12月)では、日本語の技術情報を確認できなかったため、もしかすると日本初上陸の話題かもしれません。

センサーデバイス側に関しては、私の方で設置や試用の機会はなかったので、取り上げません。

Efento Cloudの概要

Efento Cloudは、前述したように、Efento社のセンサーデバイスのデータを集積し、確認できるクラウドサービスです。

Efento Cloudでは、Webインターフェースに加えて、REST APIが提供されています。今回は説明しませんが、Webhookも用意されているため、複数の手段で外部システムとの連携や自動化が可能です。
ちなみに、Webインターフェースはいわゆるシングルページアプリケーション(SPA)で、フロントエンドの裏側ではAPIを叩いてセンサーなどのデータを取得しているようです。

ダッシュボードのイメージは以下のスクリーンショットをご覧ください。ダッシュボードには、アラーム機能も搭載されています。

測定値一覧

各センサーの測定値をグラフで表示する機能も用意されています。

測定値グラフ

用語

Efento Cloud上でデータを取り扱うにあたり、理解しておきたい用語を整理しておきます。特に重要なのは、次の4つです。

  • Organization(組織)
  • Location(ロケーション)
  • Measurement point(観測点)
  • User(ユーザー)

先に関係性を図に示すと以下の通りです。詳細は各用語の説明時に解説します。

Efento Cloud

Organization(組織)

Organizationは、Efento Cloud上での最上位の管理単位です。
1つのOrganizationには、ルートとなる1つのLocationが存在し、複数のUserを所属させることができます。

規模にもよりますが、店舗などの建物単位でOrganizationと対応付けるとよいでしょう。

Location(ロケーション)

Locationは、Organizationの下位に位置する管理単位です。
Locationは物理的な場所を表し、複数のMeasurement pointを所属させることができます。ルートとなるLocationは1つのOrganizationにつき1つですが、Locationの中にLocationを入れ子で設置することも可能です。

建物内のエリアごとに設定するとよいでしょう。

Measurement point(観測点)

Measurement pointは、IoTセンサーデバイスが該当します。
Locationの配下に存在します。
使用するデバイス次第ですが、1つのセンサーには最大で6つのチャネルを設定できます。例えば温湿度センサーだと、チャネル1に温度データ、チャネル2に湿度データといった具合です。

IoTデバイスからは、専用のゲートウェイを通じてクラウドにデータが集積されます。

User(ユーザー)

Userは、Efento Cloudにアクセスするための個人アカウントです。
UserはOrganizationに所属することで、権限に応じてデータの閲覧や操作が可能です。1つのUserが複数のOrganizationに所属することができます。

Userに付与できる権限は、以下の3種類があります。Location単位で権限を付与できます。

  • Analyst:測定値やアラーム、アラームルールを閲覧可能。レポート作成やデバイス管理も可能。
  • Manager:センサーの設定やアラームルール、数式の編集が可能。Locationの編集も可能。
  • Admin:User管理やシステムログの閲覧も含めてすべての操作が可能。

Efento Cloud APIの概要

Efento Cloudでは、RESTfulなAPIが提供されており、HTTPメソッドを使用して観測データにアクセスできます。提供されているAPIは、観測データを取得するためのread-onlyな仕様です。

API利用時には、APIキーによる認証が必要です。APIキーは、Efento CloudのWebインターフェースから取得できます。

手順を簡単に説明します。まず、設定画面のAccess > API tokensを開きます。

Access

左上の「Add new API token」をクリックすると作成画面が表示されます。

トークン作成

APIキー発行時に、測定値を取得できるLocationの範囲を指定できます。

基本的なAPI操作

Efento Cloud APIの基本的な操作例を示します。

公式でも英語のAPIリファレンスが公開されていますので、あわせてご確認ください。

APIのエンドポイントはhttps://cloud.efento.io/api/v2です。

認証時は、リクエストのAuthorizationヘッダーに、前述した手順で発行したAPIトークンをBearerトークンとして指定します。

Authorization: Bearer {API_TOKEN}

一度に大量のセンサーデータを取得しようとすると、APIのレート制限に抵触することがあります。具体的な制限値は不明ですが、試した範囲では、1秒間に複数回の頻度でリクエストを送り続けると引っかかる印象です。

Organization関連

Organization一覧取得

Organizationの一覧を取得するには、以下のGETリクエストを送信します。

GET /organizations

リクエストのパラメータ
パスパラメータ
なし

クエリパラメータ

パラメータ 意味 設定例 必須 備考
order-by 並び順 name.asc, name.descなど いいえ 未指定・不正値の場合はOrganizationのIDの降順になる模様。
limit 取得数 20 いいえ 未指定時は20(おそらく)。
offset オフセット 20 いいえ 取得数制限時に指定するオフセット。

レスポンスの例

https://cloud.efento.io/api/v2/organizations?order-by=name.desc
{
    "totalCount": 2,
    "organizations": [
        {
            "id": 2345,
            "name": "Sample Warehouse Osaka",
            "createdAt": "2025-01-10 09:00:00",
            "updatedAt": "2025-01-10 09:00:00",
            "token": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
            "smsSent": 0,
            "smsLeft": 0,
            "measurementPointsCount": 120,
            "smsReminderThreshold": 10
        },
        {
            "id": 1234,
            "name": "Example Store Tokyo",
            "createdAt": "2025-01-05 10:30:00",
            "updatedAt": "2025-01-05 10:30:00",
            "token": "f9e8d7c6-b5a4-3210-9876-fedcba098765",
            "smsSent": 0,
            "smsLeft": 0,
            "measurementPointsCount": 150,
            "smsReminderThreshold": 10
        }
    ]
}

OrganizationのIDは、Efento Cloud内で一意のようです。

Location関連

Location一覧取得

Locationの一覧を取得するには、以下のGETリクエストを送信します。

GET /locations?organization-id={organizationId}

リクエストのパラメータ
パスパラメータ
なし

クエリパラメータ

パラメータ 意味 設定例 必須 備考
organization-id OrganizationのID 1234 はい
limit 取得数 20 いいえ 未指定時は20。
offset オフセット 20 いいえ 取得数制限時に指定するオフセット。

order-byは効かないようです。

レスポンスの例

https://cloud.efento.io/api/v2/locations?organization-id=1234
{
    "locations": [
        {
            "id": 1001,
            "name": "Example Store Tokyo",
            "organizationId": 1234,
            "createdAt": "2025-01-19 03:19:20",
            "parentId": 0
        },
        {
            "id": 1002,
            "name": "Air Handling Unit",
            "organizationId": 1234,
            "createdAt": "2025-01-19 03:29:53",
            "parentId": 1001
        },
        {
            "id": 1003,
            "name": "Cooling System",
            "organizationId": 1234,
            "createdAt": "2025-01-19 03:30:01",
            "parentId": 1001
        }
    ],
    "totalCount": 3
}

parentIdの値が0となっているLocationが、ルートのLocationです。その他のLocationはルートのLocationにぶら下がる構造となっています。

LocationのIDは、Efento Cloud内で一意のようです。

観測点関連

観測点一覧取得

観測点の一覧を取得するには、以下のGETリクエストを送信します。直近の観測値も同時に取得できます。フィルターのためのクエリがいくつか用意されています。

GET /measurement-points?location-ids={locationId}

リクエストのパラメータ
パスパラメータ
なし

クエリパラメータ

パラメータ 意味 設定例 必須 備考
location-ids LocationのID 1002 はい
filter-by-name-or-device-serial-number フィルターするデバイス名/シリアル Temp いいえ
filter-by-status フィルターするステータス OPERATIONAL, DISABLED, LOST, LOW_BATTERY, WARNING, LICENSE_EXPIRED, ARCHIVEDなど いいえ 複数指定は,(カンマ)区切り。
filter-by-channel-type フィルターするチャネルタイプ ATMOSPHERIC_PRESSURE, ELECTRICITY_METER_ACCUMULATIVE, HUMIDITY, TEMPERATUREなど いいえ 複数指定は,(カンマ)区切り。
exclude-by-status 除外するステータス ARCHIVEDなど いいえ 複数指定は,(カンマ)区切り。
order-by 並び順 name.asc, name.desc, status.asc, status.descなど いいえ 未指定・不正値の場合はMeasurement pointのIDの昇順になる模様。
limit 取得数 20 いいえ 未指定時は20。
offset オフセット 20 いいえ 取得数制限時に指定するオフセット。

お気づきかもしれませんが、観測点一覧の取得にはLocationのIDのみが必要であり、OrganizationのIDは不要です。次の観測値取得に関しても同様です。

なお、LocationのIDが不明な場合は、OrganizationのIDを指定してLocation一覧から取得する必要があります。

レスポンスの例

https://cloud.efento.io/api/v2/measurement-points?location-ids=1002
{
    "measurementPoints": [
        {
            "id": 1100001,
            "locationId": 1002,
            "createdAt": "2025-02-06 12:31:14",
            "name": "TempHumidity-Sensor-001",
            "unconfirmedAlertsCount": 0,
            "activeAlertsCount": 0,
            "alertsCountInfo": {
                "unconfirmedAlertsCount": 0,
                "activeAlertsCount": 0,
                "channelAlertsInfo": []
            },
            "status": "OPERATIONAL",
            "licenseAutoRenewal": true,
            "calibrationCertificateValidityInMonths": 24,
            "measurements": {
                "measuredAt": "2025-12-24 02:25:00",
                "period": 60,
                "channels": [
                    {
                        "number": 1,
                        "name": "TempHumidity-Sensor-001",
                        "type": "TEMPERATURE",
                        "value": 13.7,
                        "status": "OK",
                        "redefined": false
                    },
                    {
                        "number": 2,
                        "name": "TempHumidity-Sensor-001",
                        "type": "HUMIDITY",
                        "value": 34.0,
                        "status": "OK",
                        "redefined": false
                    },
                    {
                        "number": 3,
                        "name": "TempHumidity-Sensor-001",
                        "type": "NO_SENSOR",
                        "value": null,
                        "status": "OK",
                        "redefined": false
                    },
                    {
                        "number": 4,
                        "name": "TempHumidity-Sensor-001",
                        "type": "NO_SENSOR",
                        "value": null,
                        "status": "OK",
                        "redefined": false
                    },
                    {
                        "number": 5,
                        "name": "TempHumidity-Sensor-001",
                        "type": "NO_SENSOR",
                        "value": null,
                        "status": "OK",
                        "redefined": false
                    },
                    {
                        "number": 6,
                        "name": "TempHumidity-Sensor-001",
                        "type": "NO_SENSOR",
                        "value": null,
                        "status": "OK",
                        "redefined": false
                    }
                ],
                "controlChannels": []
            },
            "device": {
                "id": 4300001,
                "serialNumber": "2A2C024A1B2C",
                "powerStatus": "BATTERY_OK",
                "signal": -79,
                "nextCommunicationAt": "2025-12-24 02:35:00",
                "channels": [
                    {
                        "number": 1,
                        "type": "TEMPERATURE",
                        "isRedefinable": false
                    },
                    {
                        "number": 2,
                        "type": "HUMIDITY",
                        "isRedefinable": false
                    },
                    {
                        "number": 3,
                        "type": "NO_SENSOR",
                        "isRedefinable": false
                    },
                    {
                        "number": 4,
                        "type": "NO_SENSOR",
                        "isRedefinable": false
                    },
                    {
                        "number": 5,
                        "type": "NO_SENSOR",
                        "isRedefinable": false
                    },
                    {
                        "number": 6,
                        "type": "NO_SENSOR",
                        "isRedefinable": false
                    }
                ]
            },
            "isConfigurable": false
        },
        {
            "id": 1100002,
            "locationId": 1002,
            "createdAt": "2025-02-07 05:54:03",
            "name": "TempHumidity-Sensor-002",
            "unconfirmedAlertsCount": 0,
            "activeAlertsCount": 0,
            "alertsCountInfo": {
                "unconfirmedAlertsCount": 0,
                "activeAlertsCount": 0,
                "channelAlertsInfo": []
            },
            "status": "OPERATIONAL",
            "licenseAutoRenewal": true,
            "calibrationCertificateValidityInMonths": 24,
            "measurements": {
                "measuredAt": "2025-12-24 02:25:00",
                "period": 60,
                "channels": [
                    {
                        "number": 1,
                        "name": "TempHumidity-Sensor-002",
                        "type": "TEMPERATURE",
                        "value": 14.3,
                        "status": "OK",
                        "redefined": false
                    },
                    //省略
                    {
                        "number": 6,
                        "name": "TempHumidity-Sensor-002",
                        "type": "NO_SENSOR",
                        "value": null,
                        "status": "OK",
                        "redefined": false
                    }
                ],
                "controlChannels": []
            },
            "device": {
                "id": 4300002,
                "serialNumber": "2A2C024D4E5F",
                "powerStatus": "BATTERY_OK",
                "signal": -71,
                "nextCommunicationAt": "2025-12-24 02:35:00",
                "channels": [
                    {
                        "number": 1,
                        "type": "TEMPERATURE",
                        "isRedefinable": false
                    },
                    //省略
                    {
                        "number": 6,
                        "type": "NO_SENSOR",
                        "isRedefinable": false
                    }
                ]
            },
            "isConfigurable": false
        }
    ],
    "totalCount": 2
}

センサーデータの扱いで分かりづらい点が1点あるので補足します。

Efento Cloudでは、追加で設定することでセンサーの値を変換して利用することができます。例えば、電流センサーの値を水流量に変換して扱う場合です。この場合は、レスポンスにおけるタイプ(type)が以下のようになりますので、ご注意ください。

  • measurementPoints[].measurements.channels[].type変換後の種別(前述の例ではWATER_METER)
  • measurementPoints[].device.channels[].type元々のセンサーの種別(前述の例ではCURRENT)

なお、変換されている場合は、measurementPoints[].measurements.channels[].redefinedmeasurementPoints[].device.channels[].isRedefinableがいずれもtrueになります。

serialNumberはセンサーデバイスのMACアドレスのようです。実際のMACアドレスのベンダーIDは、Efento社が取得している282C024になっていました。

測定値取得

個別の測定値を取得するには、以下のGETリクエストを送信します。時間範囲の指定が必要です。

GET /measurement-points/{measurementPointId}/measurements?from={fromTimeInUTC}&to={toTimeInUTC}

リクエストのパラメータ
パスパラメータ

パラメータ 意味 設定例 備考
measurementPointId 観測点のID 1100001

クエリパラメータ

パラメータ 意味 設定例 必須 備考
from 取得したい測定値の
時間範囲始め
2025-10-07 15:00:00 はい UTCで指定。
to 取得したい測定値の
時間範囲終わり
2025-10-07 15:09:59 はい UTCで指定。

タイムスタンプの形式は、日付と時刻の区切りが空白ではなく+(プラス)でも実際には使用できました。
例:2025-10-07+15:00:00

レスポンスの例

https://cloud.efento.io/api/v2/measurement-points/1100001/measurements?from=2025-10-07 15:00:00&to=2025-10-07 15:09:59
{
    "measurements": [
        {
            "measuredAt": "2025-10-07 15:09:00",
            "receivedAt": "2025-10-07 15:10:33",
            "period": 60,
            "channels": [
                {
                    "number": 1,
                    "value": 13.9,
                    "status": "OK"
                },
                {
                    "number": 2,
                    "value": 35.0,
                    "status": "OK"
                },
                {
                    "number": 3,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 4,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 5,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 6,
                    "value": null,
                    "status": "OK"
                }
            ]
        },
        {
            "measuredAt": "2025-10-07 15:08:00",
            "receivedAt": "2025-10-07 15:09:31",
            "period": 60,
            "channels": [
                {
                    "number": 1,
                    "value": 13.9,
                    "status": "OK"
                },
                {
                    "number": 2,
                    "value": 34.0,
                    "status": "OK"
                },
                {
                    "number": 3,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 4,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 5,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 6,
                    "value": null,
                    "status": "OK"
                }
            ]
        },
        //省略
        {
            "measuredAt": "2025-10-07 15:00:00",
            "receivedAt": "2025-10-07 15:00:57",
            "period": 60,
            "channels": [
                {
                    "number": 1,
                    "value": 13.9,
                    "status": "OK"
                },
                {
                    "number": 2,
                    "value": 34.0,
                    "status": "OK"
                },
                {
                    "number": 3,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 4,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 5,
                    "value": null,
                    "status": "OK"
                },
                {
                    "number": 6,
                    "value": null,
                    "status": "OK"
                }
            ]
        }
    ],
    "measurementPoint": {
        "id": 1100001,
        "locationId": 1002,
        "createdAt": "2025-02-06 12:31:14",
        "name": "TempHumidity-Sensor-001",
        "unconfirmedAlertsCount": 0,
        "activeAlertsCount": 0,
        "status": "OPERATIONAL",
        "licenseAutoRenewal": true,
        "calibrationCertificateValidityInMonths": 24,
        "measurements": {
            "measuredAt": "2025-12-24 04:55:00",
            "period": 60,
            "channels": [
                {
                    "number": 1,
                    "name": "TempHumidity-Sensor-001",
                    "type": "TEMPERATURE",
                    "value": 13.9,
                    "status": "OK",
                    "redefined": false
                },
                {
                    "number": 2,
                    "name": "TempHumidity-Sensor-001",
                    "type": "HUMIDITY",
                    "value": 31.0,
                    "status": "OK",
                    "redefined": false
                },
                {
                    "number": 3,
                    "name": "TempHumidity-Sensor-001",
                    "type": "NO_SENSOR",
                    "value": null,
                    "status": "OK",
                    "redefined": false
                },
                {
                    "number": 4,
                    "name": "TempHumidity-Sensor-001",
                    "type": "NO_SENSOR",
                    "value": null,
                    "status": "OK",
                    "redefined": false
                },
                {
                    "number": 5,
                    "name": "TempHumidity-Sensor-001",
                    "type": "NO_SENSOR",
                    "value": null,
                    "status": "OK",
                    "redefined": false
                },
                {
                    "number": 6,
                    "name": "TempHumidity-Sensor-001",
                    "type": "NO_SENSOR",
                    "value": null,
                    "status": "OK",
                    "redefined": false
                }
            ],
            "controlChannels": []
        },
        "device": {
            "id": 4300001,
            "serialNumber": "2A2C024A1B2C",
            "powerStatus": "BATTERY_OK",
            "signal": -66,
            "nextCommunicationAt": "2025-12-24 05:05:00",
            "channels": [
                {
                    "number": 1,
                    "type": "TEMPERATURE",
                    "isRedefinable": false
                },
                {
                    "number": 2,
                    "type": "HUMIDITY",
                    "isRedefinable": false
                },
                {
                    "number": 3,
                    "type": "NO_SENSOR",
                    "isRedefinable": false
                },
                {
                    "number": 4,
                    "type": "NO_SENSOR",
                    "isRedefinable": false
                },
                {
                    "number": 5,
                    "type": "NO_SENSOR",
                    "isRedefinable": false
                },
                {
                    "number": 6,
                    "type": "NO_SENSOR",
                    "isRedefinable": false
                }
            ]
        },
        "isConfigurable": false
    },
    "measuredByDevices": [
        {
            "id": 4300001,
            "serialNumber": "2A2C024A1B2C",
            "from": "2025-10-07 15:00:00",
            "to": "2025-10-07 15:09:59"
        }
    ]
}

その他のAPI

公式ドキュメントに記載されていないため明記は避けますが、ブラウザの開発者ツールで通信を確認すると、上記で示した以外にも例えば以下のようなAPIが存在しているようです。

  • Organizationオーナー情報取得
  • User情報取得
  • アラーム一覧取得

これらのAPIは仕様が公開されていないため、突然仕様が変わったり廃止されたりする可能性があります。自己責任でご確認ください。

おわりに

今回はIoTセンサークラウドEfento Cloudについて、提供されているAPIの利用方法を中心にまとめました。

Efento Cloudは、まだ日本国内では知名度がありませんが、今後普及していくかもしれません。API経由で他のサービスと連携することにより、データの利活用の幅が広がります。センサーデータを有効活用した新たなサービスを考えてみたいところです。

今後もアップデートがあるか注視していきたいと思います。

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?