---
# System prepended metadata

title: Foreaider Restful API

---

Foreaider RESTful API
===

[TOC]

## Server
* Dashboard : http://iot.foreaider.xtaiwan.org
* Restful API : http://api.foreaider.xtaiwan.org
* MQTT Server : http://api.foreaider.xtaiwan.org

---

## 共用說明

### 驗證金鑰
所有 API 都需要傳入 `key` 參數進行身份驗證：
```
key: "3a9afa4abefbaa81e38c4f60ab641afce4d7ce4d3d5c3f87df6fa246038f1231"
```

### 帳號層級 (level)
| 層級 | 說明 |
|------|------|
| `admin` | 管理員 |
| `agent` | 代理商 |
| `user` | 一般使用者 (預設) |

### 通用錯誤回應
| status | 說明 |
|--------|------|
| `Error Key` | 驗證金鑰錯誤 |
| `Account Not Found` | 帳號不存在或密碼錯誤 |

---

## Account API

### Create Account
建立新帳號

**POST** `/createAccount`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "email": "xxx@xxx.xxx",
    "level": "user",
    "vendor": "fa",
    "devices": ["ForeAider01", "ForeAider02"],
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| account | Y | 帳號名稱 |
| password | Y | 密碼 |
| email | N | 電子郵件 |
| level | N | 權限層級，預設 `user` |
| vendor | N | 廠商識別 |
| devices | N | 設備陣列，預設空陣列 |
| key | Y | 驗證金鑰 |

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 建立成功 |
| `Duplicate` | 帳號已存在 |
| `Error Key` | 驗證金鑰錯誤 |
| `Create Account DB Error` | 資料庫錯誤 |

---

### Delete Account
刪除帳號

**POST** `/deleteAccount`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 刪除成功 |
| `Account Not Found` | 帳號不存在 |
| `Delete Account Error` | 密碼錯誤 |
| `Delete Account DB Error` | 資料庫錯誤 |

---

### Get Account Info
取得帳號資訊

**POST** `/getAccountInfo`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK",
    "email": "xxx@xxx.xxx",
    "level": "user",
    "vendor": "fa",
    "devices": ["deviceId1", "deviceId2"]
}
```

| status | 說明 |
|--------|------|
| `OK` | 查詢成功 |
| `Account Not Found` | 帳號不存在 |
| `Get Account Info Error` | 密碼錯誤 |

---

### Update Account Info
更新帳號資訊

**POST** `/updateAccountInfo`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "email": "new@email.com",
    "devices": ["device1", "device2"],
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 更新成功 |
| `Account Not Found` | 帳號不存在 |
| `Update Account Error` | 密碼錯誤 |
| `Update Account DB Error` | 資料庫錯誤 |

---

### Forgot Password
忘記密碼，寄送重設連結至信箱

**POST** `/forgotPassword`

#### Request
```json
{
    "account": "帳號名稱",
    "email": "xxx@xxx.xxx",
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| account | N | 帳號名稱 (account 或 email 擇一) |
| email | Y | 電子郵件 |
| key | Y | 驗證金鑰 |

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 已寄送重設連結 |
| `Account Not Found` | 帳號或信箱不存在 |
| `Account or Email can not be empty` | 信箱為空 |

---

### Change Password (via Token)
透過 Token 變更密碼 (配合 forgotPassword 使用)

**POST** `/changePassword`

#### Request
```json
{
    "token": "加密的重設 Token"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 變更成功 |
| `Invalid` | Token 無效或過期 |
| `Account Not Found` | 帳號不存在 |

---

### Change Password (Direct)
直接變更密碼 (需原密碼驗證)

**POST** `/change_password`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "原密碼",
    "newPassword": "新密碼",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 變更成功 |
| `Account not found` | 帳號不存在 |
| `account / password / newPassword can not be empty` | 參數不完整 |

---

## Device API

### Create Device
建立新設備並綁定到帳號

**POST** `/createDevice`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "vendor": "fa",
    "device": "deviceId1",
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| account | Y | 帳號名稱 |
| password | Y | 密碼 |
| vendor | Y | 廠商識別 |
| device | Y | 設備 UUID |
| key | Y | 驗證金鑰 |

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 建立成功 |
| `Vendor Not Found` | 未提供廠商 |
| `Device Not Found` | 未提供設備 ID |
| `Account Not Found` | 帳號不存在或密碼錯誤 |
| `Update Account DB Error` | 資料庫錯誤 |

**說明**: 新建設備預設類型為 `ESP`，會自動初始化 bedInfo 結構。

---

### Delete Device
刪除設備

**POST** `/deleteDevice`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "device": "deviceId1",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 刪除成功 |
| `Account Not Found` | 帳號不存在或密碼錯誤 |
| `Device Not Found` | 設備不存在 |
| `Delete Device DB Error` | 資料庫錯誤 |

---

### Get Device List
取得所有設備列表

**POST** `/getDeviceList`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK",
    "devices": [
        {
            "uuid": "deviceId1",
            "vendor": "fa",
            "deviceType": "ESP",
            "account": ["user1", "user2"],
            "bedInfo": {
                "title": "床位名稱",
                "info": "備註",
                "alert": { ... }
            }
        }
    ]
}
```

| status | 說明 |
|--------|------|
| `OK` | 查詢成功 |
| `Account Not Found` | 帳號不存在 |
| `Invalid Password` | 密碼錯誤 |
| `No Devices Found` | 無設備資料 |

---

### Get Device Info
取得單一設備詳細資訊

**POST** `/getDeviceInfo`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "device": "deviceId1",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK",
    "uuid": "deviceId1",
    "vendor": "fa",
    "deviceType": "ESP",
    "account": ["user1"],
    "bedInfo": {
        "title": "床位名稱",
        "info": "備註資訊",
        "alert": {
            "enabled": "false",
            "start": "09:00",
            "end": "18:00",
            "heartStart": 40,
            "heartEnd": 90,
            "breathStart": 5,
            "breathEnd": 15,
            "delay": 3
        }
    }
}
```

---

### Update Device Info
更新設備資訊

**POST** `/updateDeviceInfo`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "device": "deviceId1",
    "bedInfo": {
        "title": "新床位名稱",
        "info": "新備註",
        "alert": {
            "enabled": "true",
            "start": "08:00",
            "end": "20:00",
            "heartStart": 50,
            "heartEnd": 100,
            "breathStart": 8,
            "breathEnd": 20,
            "delay": 5
        }
    },
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 更新成功 |
| `Account Not Found` | 帳號不存在或密碼錯誤 |
| `Device Not Found` | 設備不存在 |
| `Update Device DB Error` | 資料庫錯誤 |

**注意**: `account` 和 `password` 欄位不會被更新到設備資料中。

---

### Add Account Device
將現有設備綁定到帳號

**POST** `/addAccountDevice`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "device": "deviceId1",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 綁定成功 |
| `Account Not Found` | 帳號不存在或密碼錯誤 |
| `Account can not be empty` | 帳號為空 |
| `Device can not be empty` | 設備為空 |
| `Device doesn't exist` | 設備不存在 |
| `Device already in this account` | 設備已綁定此帳號 |
| `Update Account DB Error` | 資料庫錯誤 |

---

### Delete Account Device
從帳號解除設備綁定

**POST** `/deleteAccountDevice`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "device": "deviceId1",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 解除綁定成功 |
| `Account Not Found` | 帳號不存在或密碼錯誤 |
| `Device doesn't exist in this account` | 此帳號未綁定該設備 |
| `Update Account DB Error` | 資料庫錯誤 |

**注意**: 如果設備不再綁定任何帳號，設備資料會被自動刪除。

---

## Data API

### Get Current Data
取得設備即時資料

**POST** `/getCurrentData`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "devices": ["deviceId1", "deviceId2"],
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK",
    "deviceId1": {
        "vendor": "fa",
        "status": "onbed",
        "heart": 72,
        "breath": 16,
        "hg": 98,
        "on": 1,
        "wf": [],
        "time": "1704067200000"
    },
    "deviceId2": "No Data"
}
```

#### 設備資料欄位說明
| 欄位 | 說明 |
|------|------|
| vendor | 廠商識別 |
| status | 狀態 (onbed/offbed/...) |
| heart | 心率 (次/分) |
| breath | 呼吸率 (次/分) |
| hg | 血紅素數值 |
| on | 開機狀態 (1/0) |
| wf | 波形數據 |
| time | 時間戳記 (毫秒) |

| status | 說明 |
|--------|------|
| `OK` | 查詢成功 |
| `Account Not Found` | 帳號不存在 |
| `No devices` | 未提供設備列表 |
| `Get Current Data Error` | 密碼錯誤或系統忙碌 |

---

### Get Historical Data
取得歷史資料

**POST** `/getHistoricalData`

#### Request
```json
{
    "account": "帳號名稱",
    "password": "密碼",
    "devices": "deviceId1",
    "from": "20220510000000",
    "end": "20220510120000",
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| account | Y | 帳號名稱 |
| password | Y | 密碼 |
| devices | Y | 設備 UUID (單一字串) |
| from | Y | 起始時間，格式 `YYYYMMDDHHmmss`，`-1` 代表最早 |
| end | Y | 結束時間，格式 `YYYYMMDDHHmmss`，`-1` 代表現在 |
| key | Y | 驗證金鑰 |

#### Response
```json
{
    "status": "OK",
    "data": [
        {
            "vendor": "fa",
            "status": "onbed",
            "heart": 72,
            "breath": 16,
            "hg": 98,
            "on": 1,
            "wf": [],
            "time": "1704067200000"
        },
        {
            "vendor": "fa",
            "status": "offbed",
            "heart": 0,
            "breath": 0,
            "hg": 0,
            "on": 1,
            "wf": [],
            "time": "1704067260000"
        }
    ]
}
```

| status | 說明 |
|--------|------|
| `OK` | 查詢成功 |
| `Account Not Found` | 帳號不存在 |
| `No devices` | 未提供設備 |
| `Time format or time range error` | 時間格式錯誤 |
| `Get Historical Data Error` | 密碼錯誤 |

---

## Event API

### Insert Event
新增事件

**POST** `/insertEvent`

#### Request
```json
{
    "id": "event001",
    "type": "alert",
    "message": "心率異常",
    "deviceId": "deviceId1",
    "timestamp": 1704067200000,
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| id | Y | 事件 ID (唯一) |
| key | Y | 驗證金鑰 |
| ... | N | 其他自訂欄位 |

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 新增成功 |
| `Need to define id` | 未提供 id |
| `ID Duplicated !` | ID 已存在 |

---

### Find Event
查詢事件

**POST** `/findEvent`

#### Request
```json
{
    "keyword": "{type:'alert'}",
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| keyword | Y | 查詢條件 (MongoDB 格式字串) |
| key | Y | 驗證金鑰 |

#### keyword 範例
```javascript
// 查詢所有 alert 類型
"{type:'alert'}"

// 查詢特定設備
"{deviceId:'deviceId1'}"

// 查詢所有事件
"{}"
```

#### Response
```json
{
    "status": "OK",
    "data": [
        {
            "id": "event001",
            "type": "alert",
            "message": "心率異常",
            "deviceId": "deviceId1",
            "timestamp": 1704067200000
        }
    ]
}
```

| status | 說明 |
|--------|------|
| `OK` | 查詢成功 |
| `Need to define keyword` | 未提供 keyword |

---

### Update Event
更新事件

**POST** `/updateEvent`

#### Request
```json
{
    "id": "event001",
    "message": "更新後的訊息",
    "resolved": true,
    "key": "KEY"
}
```

| 參數 | 必填 | 說明 |
|------|------|------|
| id | Y | 事件 ID |
| key | Y | 驗證金鑰 |
| ... | N | 要更新的欄位 |

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 更新成功 |
| `Need to fill id` | 未提供 id |
| `id not found !` | ID 不存在 |

---

### Delete Event
刪除事件

**POST** `/deleteEvent`

#### Request
```json
{
    "id": "event001",
    "key": "KEY"
}
```

#### Response
```json
{
    "status": "OK"
}
```

| status | 說明 |
|--------|------|
| `OK` | 刪除成功 |
| `Need to fill id` | 未提供 id |
| `id not found` | ID 不存在 |

---

## 資料結構說明

### bedInfo 結構
```json
{
    "title": "床位名稱",
    "info": "備註資訊",
    "alert": {
        "enabled": "true/false",
        "start": "09:00",
        "end": "18:00",
        "heartStart": 40,
        "heartEnd": 90,
        "breathStart": 5,
        "breathEnd": 15,
        "delay": 3
    }
}
```

| 欄位 | 說明 |
|------|------|
| title | 床位顯示名稱 |
| info | 備註資訊 |
| alert.enabled | 是否啟用警報 |
| alert.start | 警報開始時間 |
| alert.end | 警報結束時間 |
| alert.heartStart | 心率下限 |
| alert.heartEnd | 心率上限 |
| alert.breathStart | 呼吸率下限 |
| alert.breathEnd | 呼吸率上限 |
| alert.delay | 警報延遲 (分鐘) |

---

## NodeJS Example

時間 GMT +8

```javascript
let kkey = '3a9afa4abefbaa81e38c4f60ab641afce4d7ce4d3d5c3f87df6fa246038f1231';

let client = primer.HttpClient({
    host: 'api.foreaider.xtaiwan.org',
    path: '/createAccount',
    port: 80,
    secure: false,
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: {
        account: 'Willman',
        password: '123456',
        key: kkey
    },
}, (err, res, rbody) => {
    if (err)
        console.log(err.message);
    try {
        console.log(rbody.toString());
    } catch (e) {}
});
```

---

## API 總覽

| 類別 | API | 方法 | 說明 |
|------|-----|------|------|
| Account | `/createAccount` | POST | 建立帳號 |
| Account | `/deleteAccount` | POST | 刪除帳號 |
| Account | `/getAccountInfo` | POST | 取得帳號資訊 |
| Account | `/updateAccountInfo` | POST | 更新帳號資訊 |
| Account | `/forgotPassword` | POST | 忘記密碼 |
| Account | `/changePassword` | POST | Token 變更密碼 |
| Account | `/change_password` | POST | 直接變更密碼 |
| Device | `/createDevice` | POST | 建立設備 |
| Device | `/deleteDevice` | POST | 刪除設備 |
| Device | `/getDeviceList` | POST | 取得設備列表 |
| Device | `/getDeviceInfo` | POST | 取得設備資訊 |
| Device | `/updateDeviceInfo` | POST | 更新設備資訊 |
| Device | `/addAccountDevice` | POST | 綁定設備到帳號 |
| Device | `/deleteAccountDevice` | POST | 解除設備綁定 |
| Data | `/getCurrentData` | POST | 取得即時資料 |
| Data | `/getHistoricalData` | POST | 取得歷史資料 |
| Event | `/insertEvent` | POST | 新增事件 |
| Event | `/findEvent` | POST | 查詢事件 |
| Event | `/updateEvent` | POST | 更新事件 |
| Event | `/deleteEvent` | POST | 刪除事件 |