![圖片](./media/products/Bellwin-Redfish/media/cover.jpeg)

# 使用者資訊

製造商保有修改與變更本說明書所包含的資訊、文件與規格表的權利，且不需事前通知；製造商不會保證、明示、暗示或法定聲明其內容或特別否認其對於特殊用途的可銷售性與適用性；本說明書中所描述的任何被銷售與授權的製造商軟體亦同。

如果購買後證明軟體程式瑕疵，購買者（及非製造商、其經銷商或其購買商家）將需承擔所有因軟體瑕疵所造成的必要的服務費用、修理責任和任何偶發事件或間接損害。

本系統製造商並不擔負任何未經授權調整本裝置後所造成的收音機及／或電視干擾之責任，使用者必須自行修正干擾。

操作前如未正確選擇操作電壓的設定，製造商將不擔負因此所導致的任何損害之責任；使用前請務必確認電壓設定為正確的。

本廠向原始一般使用者（購買者）保證，本產品由購買日期起 1 年內，無任何材質或製造技術之缺陷。在保固期間及依購買證明，若產品因製造技術和／或材質有瑕疵而發生任何故障時，本廠將自行定奪，在不收取任何零件或人力費用下修理或更換缺陷產品或元件，以在其視為必要之範圍內，將產品或元件回復至正常操作狀態。任何更換將包含新的或重新製造功能相當之等值或更高價值的產品，更換內容將由本廠自行定奪，但若產品已經過修改、誤用、變造、因天災或不正常運作狀態而受損，則不適用本保固。

本保固將完全不適用於因任何第三人（包括但不限於本廠之客戶或一般使用者）安裝或使用、操作疏失和／或不當使用、未經本廠事先核準之修改、進行與本廠書面指示說明不符之維修、正常耗損、拆解產品、將產品連接至不相容的設備或軟體、將產品變更、轉換或整合至非本廠計畫內指定運用本產品之系統中、將不相容之硬體和／或軟體連接至本產品，以及一般使用者電腦網路上含有病毒、電信業者和／或服務供應商網路經修改、變更或中斷、產品經由非經本廠授權之人員維修，而造成產品和／或任何零件產生缺陷或不符規格。

若您的裝置無法正常運作，請聯絡裝置包裝內所附之支援及保固卡上所標示的服務供應商。

# 前言

本手冊收錄 **Pelx Redfish** 完整整合指南與 API 規格，供 DCIM、監控平台與 SI 整合使用。

> 對外整合入口：`https://<host>/redfish/v1`。


## 合規驗證

**單一入口：** spec/validation.md（Redfish **1.16.0**、OCP Rack PDU／Baseline Profile、`rf_service_validator` + `rf_interop_validator`、日期與範圍）。

Interop 實測：OCP Rack PDU v1.0.0（2026-07-06）**884 Pass／0 Fail**；OCP Baseline Hardware Management v1.1.1（2026-07-22）**203 Pass／0 Fail**。指令見 「讀取流程」章節、前置條件見 overview.md。

手動探查單一 API 可用 [redfishtool](https://github.com/DMTF/redfishtool)，範例見 「讀取流程」章節「redfishtool 測試」。

# 第一部分 第三方整合指南

本部分說明 DCIM、監控平台與 SI 整合 Pelx 設備的建議流程與主要 API。

## 第三方整合指南

本指南供 **DCIM、監控平台、SI** 使用：以 **OCP Rack PDU Profile v1.0.0** 為主線，必要時搭配 **Pelx 擴充**。JSON 範例與欄位定義見本手冊 API 規格章節。

> 對外唯一整合入口：`https://<host>/redfish/v1`。

## 整合原則

| 場景 | 通道 | 必要 API |
|------|------|----------|
| **大量即時**（多點即時看板） | **MQTT** | 先 `GET /redfish/v1` 讀 `Oem.Pelx.MqttEndpoint`，再訂閱 `/updates/local`、`/update/local/#`；詳「MQTT Discovery」章節 |
| **第三方 DCIM / OCP** | **Redfish REST** | `Metrics`、`Mains`、`Outlets`、`Chassis/Sensors`、`EventService/Subscriptions`；輪詢 **15～60 秒** |

不需把 MQTT 包成 Redfish、DCIM 不必接 MQTT、不必實作 SSE。詳見 MQTT / WebSocket。

## 整合流程

```mermaid
flowchart TB
  subgraph core[OCP 必填 — 建議先打通]
    C1[1 整合準備] --> C2[2 設備識別]
    C2 --> C3[3 即時監控]
    C3 --> C4[4 電源控制]
    C2 --> C5[5 告警與事件]
    C2 --> C6[6 操作與稽核日誌]
  end
  subgraph ops[Baseline 維運 — 依需求]
    C8[8 韌體更新]
    C9[9 組態備份還原]
  end
  subgraph ext[選配與 OEM — 非 OCP 必填]
    C7[7 歷史趨勢]
    C4b[4b 插座群組]
    C10[10 進階擴充]
    C11[11 MQTT / WebSocket]
  end
  C2 --> C8
  C2 --> C9
  C3 --> C7
  C4 --> C4b
  C3 --> C10
  C3 --> C11
```

## 章節導讀

| 章 | 主題 | 整合方要做的事 | 主要 Redfish API | OCP |
|----|------|----------------|------------------|-----|
| 1 | 整合準備 | 連線、認證、探索 Service Root | `GET /redfish/v1`、`SessionService` | ✅ Baseline |
| 2 | 設備識別 | 型號、序號、機架位置 | `Chassis`、`Managers`、`RackPDUs` | ✅ |
| 3 | 即時監控 | 進線／插座電力、感測器 | `Mains`、`Outlets`、`Metrics`、`Chassis/Sensors` | ✅ |
| 4 | 電源控制 | 開關／重啟插座、群組控 | `Outlet.PowerControl`、`OutletGroups` | 控制 ✅／群組非 OCP |
| 5 | 告警與事件 | 訂閱、查目前告警 | `EventService/Subscriptions`、`Events` | 訂閱 ✅ |
| 6 | 操作與稽核日誌 | 查操作／登入紀錄 | `Managers/.../LogServices` | ✅ Baseline |
| 7 | 歷史趨勢 | 圖表、時序資料 | `TelemetryService` | DMTF 標準（非 OCP） |
| 8 | 韌體更新 | 上傳映像、查進度 | `UpdateService`、`TaskService` | ✅ Baseline |
| 9 | 組態備份還原 | 匯出／還原參數 | `PelxConfiguration` | Pelx OEM |
| 10 | 進階擴充 | ATS、全介面、DI/DO、排程、RS485／VNode／圖控／Flow | `TransferSwitches`、`Oem/Pelx/*` | 非 OCP |
| 11 | MQTT / WebSocket | 高頻即時推送、多點即時儀表板 | MQTT `/update`、`/query`；對照 Redfish | Pelx OEM |

## 上線與驗收

* checklists — **OutboundConnection 上線**、**OCP 合規**、**DCIM 整合** 三份勾選表

## 合規驗證

**實測進度參考**（Redfish Interop Validator，`--authtype Session`，2026-07-06）：

| Profile | Pass | Fail | Warning | Not Tested |
|---------|------|------|---------|------------|
| OCP Rack PDU v1.0.0 | 884 | 0 | 0 | 0 |
| OCP Baseline Hardware Management v1.1.1 | 271 | 0 | 0 | 0 |

兩項皆 **Validation SUCCEEDED**。

設備以 DMTF **Service Validator** 與 **Interop Validator** 驗證（詳見validation.md）。Interop：**OCP Rack PDU v1.0.0**（2026-07-06，884 Pass）與 **OCP Baseline Hardware Management v1.1.1**（2026-07-22，203 Pass），皆 0 Fail。自測指令見 「讀取流程」章節。

# 第 1 章：整合準備

2. 建立專用帳號（建議 `viewer` 唯讀監控、`manager` 含控制）
3. 選擇認證方式：**Basic Auth**（腳本／Validator）或 **Session Token**（長時間輪詢）
4. 匿名 `GET /redfish/v1` 應回 **200**（OCP Validator 需求）；子資源須認證

## 主要 Redfish API

| API | 用途 |
|-----|------|
| `GET /redfish/v1` | Service Root，取得資源連結 |
| `GET /redfish/v1/SessionService` | Session 設定（可匿名） |
| `POST /redfish/v1/SessionService/Sessions` | 建立 Session，回傳 `X-Auth-Token` |
| `DELETE /redfish/v1/SessionService/Sessions/{id}` | 登出 |
| `POST /redfish/v1/AccountService/Accounts` | 建立整合帳號（須 Administrator） |
| `GET /redfish/v1/AccountService/Accounts` | 列出帳號 |

## OCP 範圍

✅ **OCP Service Baseline** 必填（Session、Account 等）

## 建議流程

```
GET /redfish/v1（可不帶認證）
  → POST /SessionService/Sessions（或全程 Basic）
  → 後續請求帶 X-Auth-Token 或 Authorization: Basic
  → 完成後 DELETE Session
```

## curl 範例

```bash
# Service Root（對外）
curl -sk https://<host>/redfish/v1

# 建立 Session
curl -sk -u dcim-read:'<password>' -X POST \
  https://<host>/redfish/v1/SessionService/Sessions \
  -H 'Content-Type: application/json' -d '{}'
# 回應標頭 X-Auth-Token 用於後續請求

# 或全程 Basic
curl -sk -u dcim-read:'<password>' https://<host>/redfish/v1/PowerEquipment

curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","TokenLifetimeSeconds":300,"Language":"zh-TW"}'
curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","ClientIp":"203.0.113.50","TokenLifetimeSeconds":300}'
curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","ReturnPath":"/eng/Peripheral","ClientIp":"203.0.113.50","TokenLifetimeSeconds":300}'

# 建立整合帳號（須 admin／Administrator）
curl -sk -u admin:'<password>' -X POST \
  https://<host>/redfish/v1/AccountService/Accounts \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"dcim-read","Password":"ChangeMe-Strong1","RoleId":"ReadOnly"}'
```

帳號建立見 「認證」章節 — AccountService（`POST .../Accounts`；`RoleId` 對應 `ReadOnly`／`Operator`／`Administrator`）。Web 管理亦可使用 auth `POST /users`。

# 第 2 章：設備識別

取得設備型號、韌體版本、序號、UUID、機架位置（Rack／Row／Offset），供資產管理與告警關聯。

## 主要 Redfish API

| 資源 | 典型欄位 |
|------|----------|
| `GET /redfish/v1` | `Product`、`Vendor`、`RedfishVersion` |
| `GET /redfish/v1/Chassis/1` | `SerialNumber`、`PartNumber`、`UUID`、`Location`、`PowerState`、`ThermalSubsystem` |
| `GET /redfish/v1/Managers/1` | `FirmwareVersion`、`DateTime`、`UUID` |
| `GET /redfish/v1/PowerEquipment/RackPDUs/1` | `UserLabel`、`EquipmentType`、`SerialNumber`、`PartNumber`、`Branches`、`Location` |

## OCP 範圍

✅ **OCP Rack PDU Profile** 必填（Chassis、Manager、RackPDU 識別欄位）

## 建議讀取順序

```
GET /redfish/v1
  → Chassis/1
  → Managers/1
  → PowerEquipment/RackPDUs/1
```

`Chassis.Links.PowerDistribution` 為**單一物件**（非陣列），與 `RackPDUs` 互相連結，可交叉驗證同一台 PDU。

**序號／料號 fallback**：`SerialNumber` 優先 `devinfo.serialNumber`，否則以 MAC（`ethaddr`）填入；`PartNumber` 優先 `devinfo.partNumber`，否則以 `Model` 填入。兩欄位在 Chassis 與 RackPDU 上**一律輸出**（OCP Interop 必填）。

## curl 範例

```bash
curl -sk -u dcim-read:'<password>' https://<host>/redfish/v1/Chassis/1
curl -sk -u dcim-read:'<password>' https://<host>/redfish/v1/Managers/1
curl -sk -u dcim-read:'<password>' https://<host>/redfish/v1/PowerEquipment/RackPDUs/1
```

# 第 3 章：即時監控

輪詢進線（Mains）與插座（Outlets）之電壓、電流、功率、能耗；必要時讀取機櫃級彙總（Metrics）與標準感測器路徑（Chassis/Sensors）。

## 主要 Redfish API

| 資源 | 內容 |
|------|------|
| `.../RackPDUs/1/Metrics` | 總功率 `PowerWatts`、能耗 `EnergykWh`、負載 `PowerLoadPercent` |
| `.../RackPDUs/1/Mains/{id}` | 進線電壓、功率、能耗 |
| `.../RackPDUs/1/Outlets/{id}` | 插座即時讀值、`PowerState` |
| `GET /redfish/v1/Chassis/1/Sensors/{id}` | **OCP 驗證路徑**；`Mains`／`Outlets` 的 `DataSourceUri` 指向此處 |

> Interop Validator 僅驗證 `Chassis/{id}/Sensors`；`PowerEquipment/.../Sensors` 為 DSP2056 快速查詢路徑，兩者成員一致。

## OCP 範圍

✅ **OCP Rack PDU Profile** 必填（Mains、Outlets、Metrics、Sensor）

## 建議讀取順序

```
RackPDUs/1/Metrics          # 機櫃彙總
  → Mains                   # 進線列表 → Mains/{id}
  → Outlets                 # 插座列表 → Outlets/{id}
  → Chassis/1/Sensors       # 標準感測器（輪詢深度資料）
```

高頻輪詢建議 Session Token；唯讀帳號設 `viewer` 即可。

## 減少請求次數

OCP **沒有**單一 API 一次回所有插座即時讀值，但可用下列標準方式降低往返：

| 需求 | API | 說明 |
|------|-----|------|
| 整機功率／能耗／負載 | `.../Metrics` | **OCP 必填**；一次回 `PowerWatts`、`EnergykWh`、`PowerLoadPercent` |
| 所有插座完整 JSON | `.../Outlets?$expand=.` | 須 Service Root 宣告 `ExpandQuery`；不支援則逐筆 `GET Members` |
| 歷史多筆讀值 | `TelemetryService/MetricReports/{id}` | `MetricValues[]` 批量時序；見 歷史趨勢 |

## 多點網頁即時監控

> **多點即時**：指同時監控多個介面／量測點的即時更新（變更即推），**不限定**固定點數。

依 整合原則：**大量即時走 MQTT**；**DCIM 走 Redfish 常規輪詢**（見下表），兩者分工，不需額外擴充 API。

### 方案取捨

| 場景 | 通道 | 必要 API | 刷新 |
|------|------|----------|------|
| **多點即時看板摘要** | Redfish | `.../Metrics` | 5 秒 |
| **Pelx 告警** | Redfish | `EventService/Subscriptions` | 事件推送 |
| **第三方 DCIM** | Redfish | `Metrics`、`Outlets`、`Mains`、`Sensors` | **15～60 秒** |
| **歷史趨勢** | Redfish | `TelemetryService/MetricReports` | **≥ 5 秒** |

> **勿**以 Redfish 高頻輪詢（含 100 次逐筆 GET、`Interfaces` 1～2 秒輪詢）取代 MQTT；`Oem/Pelx/Interfaces` 集合維持 Redfish 慣例（`Members` 為連結），供探索與單筆讀取即可。

### 專屬頁（多點即時）

```
① GET /redfish/v1                   # 讀 MqttEndpoint
② GET .../Metrics                   # 頂部摘要（5 秒）
③ MQTT 訂閱 /updates/local、/update/local/#  # 多點即時（見第 11 章）
④ POST .../EventService/Subscriptions  # 告警
⑤ 控制 → Outlet.PowerControl        # Redfish
```

### 第三方 DCIM

```
Metrics + Outlets/Mains/Sensors（15～60 秒）
告警 → EventService 訂閱
歷史 → Telemetry MetricReports
```

### 刷新頻率

| 場景 | 間隔 |
|------|------|
| Pelx 多點即時 | **MQTT 變更即推** |
| 一般 DCIM 輪詢 | **15～60 秒** |
| Telemetry 報告 | **≥ 5 秒** |
| 告警 | **Event 推送**，非加頻輪詢 |

### UI 建議

* **Health Rollup** 摘要（如 1 Critical、99 OK），點擊再展開明細
* **虛擬捲動**：大量列僅渲染可見區域
* 依 `Status.Health` 綠／黃／紅標色

詳見 「總覽與合規」章節 — 一次回應多筆資料、「OEM 介面」章節。

```bash
# 彙總量測（推薦：監控儀表板首選）
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Metrics

# 展開所有插座（若設備支援 $expand）
curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets?$expand=.'
```

## curl 範例

```bash
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Metrics

curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1

curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/Chassis/1/Sensors/Outlet1Current
```

# 第 4 章：電源控制

1. 單路插座：開、關、重啟（`PowerCycle`）
2. （選用）插座群組：一次控制多路插座

需 **manager** 或以上角色（Operator）。

## 主要 Redfish API

| API | 說明 | OCP |
|-----|------|-----|
| `POST .../Outlets/{id}/Actions/Outlet.PowerControl` | 單路控制 | ✅ |
| `GET .../Outlet.PowerControlActionInfo` | 允許參數（`On`／`Off`／`PowerCycle`） | ✅ |
| `POST .../OutletGroups/{id}/Actions/OutletGroup.PowerControl` | 群組批次控制 | DSP2056（非 OCP 必填） |

## 請求範例

```json
{
  "PowerState": "On"
}
```

重啟：`"PowerState": "PowerCycle"`。可選延遲：

```json
{
  "PowerState": "On",
  "Oem": { "Pelx": { "OnDelaySec": 10, "OffDelaySec": 10 } }
}
```

## 建議流程

```
GET Outlets/{id}                    # 確認 PowerState
  → GET Outlet.PowerControlActionInfo
  → POST Outlet.PowerControl
```

群組控制：

```
GET RackPDUs/1/OutletGroups
  → GET OutletGroups/{id}（確認 Links.Outlets）
  → POST OutletGroup.PowerControl
```

## curl 範例

```bash
# 關閉插座 1
curl -sk -u dcim-ctrl:'<password>' -X POST \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1/Actions/Outlet.PowerControl \
  -H 'Content-Type: application/json' \
  -d '{"PowerState":"Off"}'
```

# 第 5 章：告警與事件

1. **訂閱**（OCP）：建立 `EventService/Subscriptions`，指定主機 `Destination` URL
2. **查目前告警**（Pelx 擴充）：輪詢 `EventService/Events` 快照

> 訂閱持久化於設備本機；告警狀態變更時會 POST Redfish Event 至 `Destination`（含重試）。若需僅查目前告警而不訂閱，可輪詢 `Events`。

## 主要 Redfish API

| API | 說明 | OCP |
|-----|------|-----|
| `GET /redfish/v1/EventService` | 服務能力、`Subscriptions` 連結 | ✅ |
| `POST /redfish/v1/EventService/Subscriptions` | 建立訂閱 | ✅ Baseline |
| `GET .../Subscriptions/{id}` | 查訂閱 | ✅ |
| `DELETE .../Subscriptions/{id}` | 刪除訂閱 | ✅ |
| `GET /redfish/v1/EventService/Events` | 目前告警列表 | Pelx 擴充 |

## 建議流程

**標準訂閱（OCP）**

```
GET EventService
  → POST Subscriptions（Destination、EventTypes、Context）
  → 主機接收 POST 事件（格式依 Redfish Event）
```

**僅需目前告警快照**

```
GET EventService/Events
  → 必要時 GET Events/{eventId}
```

## OEM 擴充做法（建議）

若需兼容舊版事件欄位，請維持標準 `POST /EventService/Subscriptions`，並在 request body 加入 `Oem.Pelx` 參數；未來啟用實際推送時，事件 payload 也以 `Oem.Pelx` 附帶相容欄位。  
重點是：**擴充標準訂閱，不另開一套取代 `Subscriptions` 的私有 API**。

## curl 範例

```bash
# 建立訂閱（範例）
curl -sk -u dcim-ctrl:'<password>' -X POST \
  https://<host>/redfish/v1/EventService/Subscriptions \
  -H 'Content-Type: application/json' \
  -d '{
    "Destination": "https://dcim.example.com/redfish/events",
    "EventTypes": ["Alert"],
    "Context": "dcim-prod"
  }'

# 查目前告警
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/EventService/Events
```

# 第 6 章：操作與稽核日誌

查詢設備上的**操作紀錄**（插座控制、參數變更等）與**登入／稽核紀錄**，供合規與故障追溯。**統一中控**補同步缺失事件時，另用 **seq 區間** API（見下表）。

## 主要 Redfish API

| API | 說明 |
|-----|------|
| `GET /redfish/v1/Managers/1/LogServices` | 日誌服務列表 |
| `GET .../LogServices/Operational` | 操作日誌 |
| `GET .../LogServices/Audit` | 稽核／登入日誌 |
| `GET .../LogServices/{logId}/Entries` | 日誌條目集合 |
| `GET .../Entries/{entryId}` | 單筆詳情 |
| `GET .../LogServices/Oem/Pelx/MaxSeq` | 設備事件最大 `seq`（主機補同步用） |
| `GET .../LogServices/Oem/Pelx/LogSync?fromSeq=&toSeq=&lang=` | 依 seq 區間拉回事件（單次最多 100 筆） |

## OCP 範圍

✅ **OCP Service Baseline**（Manager `LogServices`）

## 建議流程

**OCP 日誌查詢**

```
GET Managers/1/LogServices
  → GET LogServices/Operational/Entries（或 Audit）
  → 依 Created 時間篩選；大量條目僅取最近 N 筆
```

**主機補同步缺失事件**（Pelx OEM，非 OCP 必填）

```
GET .../LogServices/Oem/Pelx/MaxSeq
  → 若主機 syncSeq < maxSeq
  → GET .../LogSync?fromSeq=syncSeq+1&toSeq=min(syncSeq+100, maxSeq)&lang=zh-hant
  → 重複直到追上 maxSeq
```

## curl 範例

```bash
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/Managers/1/LogServices/Operational/Entries
```

# 第 7 章：歷史趨勢

取得電力等量測的**時序資料**，繪製趨勢圖或做容量分析。Redfish 標準以 **`MetricReport` 的 `MetricValues` 陣列**提供批量讀值：一次 `GET .../MetricReports/{id}` 可取得多筆 `MetricId`／`MetricValue`／`Timestamp`，無須對每個感測器逐筆輪詢歷史點。**統一中控**補同步缺失分鐘統計時，另用 **addr ＋時間區間** API（見下表）。

> **非 OCP 必填** — DMTF 標準 `TelemetryService`；僅需 OCP 合規的整合方可略過本章。

## 主要 Redfish API

| API | 說明 |
|-----|------|
| `GET /redfish/v1/TelemetryService` | 服務入口 |
| `GET .../MetricReportDefinitions` | 報表定義（取樣間隔、指標） |
| `GET .../MetricReports/{reportId}` | 時序資料點（`MetricValues[]` 批量） |
| `GET .../MetricDefinitions` | 指標定義 |
| `GET .../Oem/Pelx/RollupRange/{addr}` | 各粒度保存區間（主機補同步用） |
| `GET .../Oem/Pelx/InterfaceRollup/{addr}?startTime=&endTime=&by=` | 依時間區間拉回統計（`by=1min` 單次最多 120 筆）；趨勢圖加 `&fill=null` |

## OCP 範圍

DMTF 標準（**非 OCP 必填**）

## 建議流程

```
GET TelemetryService
  → MetricReportDefinitions        # RecurrenceInterval PT1M、AppendLimit 120
  → MetricReports/{id}             # MetricValues[]；可選 ?$filter=Timestamp ge ...
```

```bash
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/TelemetryService/MetricReports/VoltageA

curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/MetricReports/VoltageA?$filter=Timestamp%20ge%202026-06-10T07:00:00Z'
```

**主機補同步缺失分鐘統計**（Pelx OEM，非 OCP 必填）

```
GET .../Mains/{mainId} 或 .../Outlets/{outletId}
  → Oem.Pelx.Interfaces.CurrentAmps（等）.@odata.id → 取出 addr
GET .../Oem/Pelx/RollupRange/{addr}
  → 比對設備 latest.1min 與主機 syncMinTime
  → GET .../InterfaceRollup/{addr}?startTime=syncMinTime+60&endTime=...&by=1min
  → 單次最多 120 筆；下一批 startTime = 本批最末 time + 60
  → 主機補件不要帶 fill
```

設備 Web 趨勢圖：同一支 `InterfaceRollup` 加 `&fill=null`，缺採樣的時間格值為 `null`，前端斷線。

> 不需在 `Mains`／`Outlets` 另設 Rollup API；詳見 「歷史趨勢」章節 — 從 Mains／Outlet 取得 addr。

# 第 8 章：韌體更新

上傳整機設備映像（`.swu`）並執行 OTA，查詢 `TaskService` 進度。需 **admin** 或具升級權限帳號。

## 主要 Redfish API

| API | 說明 |
|-----|------|
| `GET /redfish/v1/UpdateService` | 服務狀態、`upload` 路徑 |
| `GET .../FirmwareInventory/Image` | 目前映像版本 |
| `POST /redfish/v1/UpdateService/upload` | 上傳映像（`application/octet-stream`） |
| `POST .../Actions/UpdateService.SimpleUpdate` | 從遠端 URI 拉取映像（可選） |
| `GET /redfish/v1/TaskService/Tasks/{id}` | 升級任務進度 |

> 上傳格式：**僅** `application/octet-stream` 本體，**不支援** `multipart/form-data`。

## OCP 範圍

✅ **OCP Service Baseline**（`UpdateService`、`TaskService`）

## 建議流程

> **Recovery 模式**：韌體更新為**停機作業**，執行期間 Redfish 可能短暫不可用。設備僅有一組可更新映像，**非**雙映像熱切換。若更新過程意外斷電，電力恢復後設備會**自動續跑**更新流程。

**本地上傳**

```
GET UpdateService/FirmwareInventory/Image   # 記錄升級前版本
  → POST UpdateService/upload（octet-stream 寫入暫存）
  → 設備驗證並套用韌體映像（非同步 Task）
  → GET TaskService/Tasks 查進度
  → 設備重啟後再 GET FirmwareInventory
```

**遠端 URI**

```
POST .../Actions/UpdateService.SimpleUpdate
  Body: { "ImageURI": "https://..." }
```

## curl 範例

```bash
# 上傳映像
curl -sk -u admin:'<password>' -X POST \
  https://<host>/redfish/v1/UpdateService/upload \
  -H 'Content-Type: application/octet-stream' \
  --data-binary @rpm6_upgrade.swu
```

# 第 9 章：組態備份還原

匯出設備組態檔（cfg）備份，或上傳組態還原參數（插座名稱、閾值等）。**不替換韌體映像**。

> **Pelx 擴充** — 非 OCP Profile 必填；OCP 合規整合若只需監控／控制可略過。

## 主要 Redfish API

| API | 說明 |
|-----|------|
| `GET .../UpdateService/Oem/Pelx/Configuration` | 組態服務入口 |
| `POST .../Actions/PelxConfiguration.Download` | 下載備份檔 |
| `POST .../Actions/PelxConfiguration.Upload` | 上傳還原（`octet-stream`，回 **202**） |

與韌體流程**分開**：勿對 `UpdateService/upload` 上傳組態檔。

## 建議流程

**備份**

```
POST PelxConfiguration.Download
  → 回應為組態二進位或導向下載
```

**還原**

```
POST PelxConfiguration.Upload（octet-stream）
  → 202 已接受；背景 restore/apply
  → 設備可能重啟，預留 rebootWaitTime
```

個別參數亦可 `PATCH` 各資源（如 ATS `Parameters`），與整包 cfg 互補。

# 第 10 章：進階擴充

存取 **非 OCP 必填**能力：ATS（DMTF `TransferSwitches`）、Pelx OEM 介面列表（含 DI/DO、E-Port 等）、排程管理，以及工程組態（RS485、VNode、圖控、自動化流程）。

> 下列資源**不計入** OCP Rack PDU Profile 合規；整合方若只需 DCIM 標準監控／控制，可完全忽略本章。

> **同一套入口**：工程組態對外只走 `https://<host>/redfish/v1/Oem/Pelx/...`，沿用 Redfish Session／Basic 與 auth.md RBAC（工程寫入須 **Administrator**）。**不**另開對外 REST。

## 主要 Redfish API

| 資源 | 說明 | 條件 | 最低角色 |
|------|------|------|----------|
| `PowerEquipment/TransferSwitches` | ATS 狀態、Feeder A/B（DMTF 標準） | 設備支援 ATS | 讀：ReadOnly；寫參數：Operator |
| `.../TransferSwitches/{id}/Feeders/{A\|B}` | 各路進線詳情 | 同上 | 讀：ReadOnly |
| `Oem/Pelx/Interfaces` | 完整介面列表 | 永遠提供 | 讀：ReadOnly |
| `Oem/Pelx/Interfaces/{addr}` | 單一介面即時值 | `addr` 見 `Oem/Pelx/Interfaces` | 讀：ReadOnly |
| `Oem/Pelx/Schedules` | 排程 CRUD 與啟用/停用 | 有可排程輸出點 | 寫：Operator |
| `Oem/Pelx/SerialBuses` | RS485 通訊參數 | `devinfo.rs485` | **Administrator** |
| `Oem/Pelx/VNodes` | VNode 組態／讀取測試 | `devinfo.vnode` | **Administrator** |
| `Oem/Pelx/HmiScreens` | 圖控畫面 YAML、樣版匯出／載入 | `devinfo.hmi` | **Administrator** |
| `Oem/Pelx/HmiImageLibraries` | 圖控圖庫 zip／圖片上傳 | `devinfo.hmi` | **Administrator** |
| `Oem/Pelx/Automations` | Flow DSL 佈署／啟停 | `devinfo.autoBuilder` | **Administrator** |

> **電子鎖**為 iLock 獨立產品，非 PDU 功能；整合請見 「iLock 電子鎖」章節。

## OCP 範圍

**非 OCP 必填**（含 DMTF 標準選配與 Pelx OEM）

## 建議流程

**ATS**

```
GET PowerEquipment/TransferSwitches
  → GET TransferSwitches/1
  → GET Feeders/A、Feeders/B
  → PATCH Parameters（切換參數，需權限）
```

**非標準週邊／DI/DO**

```
GET Oem/Pelx/Interfaces
  → GET Oem/Pelx/Interfaces/{addr}
```

**排程**

控制目標以 `Links.Outlets`（OCP 插座）或 `Links.Interfaces`（`DO` 開頭位址，如 E-Port 等外接輸出週邊）的 `@odata.id` 指定。

```
GET Oem/Pelx/Interfaces（篩選 addr 以 DO 開頭）
GET Oem/Pelx/Schedules
  → POST Oem/Pelx/Schedules（新增；Links + Arg.Action）
  → PATCH Oem/Pelx/Schedules/{id}（修改）
  → POST .../Actions/PelxSchedule.SetEnabled（啟用/停用）
```

**工程組態（Administrator）**

建機／AI 佈署建議順序：

```
GET /redfish/v1（確認 Oem.Pelx 連結）
  → PATCH Oem/Pelx/SerialBuses/{id}（RS485）
  → PATCH Oem/Pelx/VNodes/{id}（對應暫存器 → 介面）
  → POST/PATCH Oem/Pelx/HmiScreens（圖控 YAML）
  → GET .../HmiScreens/{id}/Export 或 POST .../ImportTemplate（樣版 ZIP）
  → POST Oem/Pelx/HmiImageLibraries/Actions/PelxHmiImageLibrary.Import（圖庫 zip）
  → POST/PATCH Oem/Pelx/Automations（Flow YAML）
  → POST .../Automations/{id}/Actions/PelxAutomation.SetRun
```

即時點值仍用 `Oem/Pelx/Interfaces`；Flow **執行**在設備本地，Redfish 只負責組態。

# 第 11 章：MQTT / WebSocket（高效即時通道）

除 **OCP Redfish REST** 外，Pelx 設備另提供 **MQTT over WebSocket**，供高頻即時監控、狀態推送。本章說明與 Redfish 的**分工**、Topic 對照，以及多點網頁即時監控的建議架構。

> **非 OCP 標準協議**。DMTF Redfish（DSP0266）與 OCP Rack PDU Profile **未定義** MQTT 或 WebSocket；設備同時提供 Redfish 與 MQTT **不影響** OCP 合規（Redfish 資源樹須完整通過 Interop Validator）。MQTT 列為 Pelx **平行增值通道**（Sidecar Protocol）。

## 與 Redfish 的分工（雙軌架構）

業界慣例建議 **Redfish + MQTT 並用**，而非把 MQTT「包裝成 Redfish」：

| 通道 | 協議 | 用途 | OCP |
|------|------|------|-----|
| **Redfish REST** | HTTPS | Discovery、Inventory、配置（PATCH）、標準告警訂閱、第三方 DCIM | ✅ 主線 |
| **MQTT over WS** | WebSocket | 多點即時儀表板、變更推送、心跳 | Pelx OEM |
| **EventService** | HTTP POST 至 Destination | 低頻告警／狀態變更（OCP Baseline） | ✅ |
| **OutboundConnection** | 設備 → 外部 WebSocket | 防火牆後設備主動連雲端；Redfish over WS | 已實作（2023.2+） |
| **TelemetryService** | REST 輪詢 | 5～15 秒批量時序、歷史趨勢 | DMTF 標準（非 OCP 必填） |

**不建議**在閘道把 MQTT 逐筆轉成 Redfish Event——增加延遲與 Gateway 負擔。網頁或 BFF 可同時持有 **REST Client**（控制、探索）與 **MQTT Client**（即時顯示）。

### MQTT 能否取代 EventService？

**不能取代，應分工並用：**

| 機制 | 角色 | 說明 |
|------|------|------|
| **EventService**（DMTF/OCP） | **標準互通告警** | HTTP POST JSON 至 `Destination`；OCP Baseline；第三方 DCIM 通用 |
| **MQTT `/update`**（Pelx） | **高頻 telemetry + UI 狀態** | 含 `status` 但語意為介面狀態碼，非 Redfish Event 格式 |

* **Critical／Warning 告警** → `EventService/Subscriptions`（OCP 主線）
* **儀表板數值跳動、多點同步更新** → MQTT 訂閱
* MQTT `/update` 的 `status` 可驅動 UI 變色，**不可**當作 DCIM 標準告警通道

### 推送機制對照

| 機制 | 傳輸 | 標準地位 | 適用 |
|------|------|----------|------|
| `EventService/Subscriptions` | HTTP POST | OCP Baseline | 告警、插座跳脫、標準 DCIM 事件接收 |
| `AccountService/OutboundConnections` | WebSocket（`wss`） | DMTF 2023.2+ 選配 | 設備主動連雲端；已實作 |
| SSE（`EventService/SSE`） | HTTP 長連線 | DMTF 選配 | 瀏覽器單向串流；連線管理不如 MQTT |
| MQTT `/update` | WebSocket | Pelx 實務 | 介面 value/status **變更即推**；多點即時儀表板首選 |

## 連線方式

### 透過 Redfish Discovery（建議，DCIM）

整合方先讀 Redfish OEM 取得 MQTT URL，再以 **Redfish Session** 或 **Basic Auth** 連 WebSocket：

```
GET /redfish/v1/Oem/Pelx/Mqtt   → Endpoint、MqttAuth
POST .../SessionService/Sessions   → X-Auth-Token（或 Basic Auth）
WebSocket connect Endpoint         → 帶 X-Auth-Token 或 Authorization
subscribe /updates/local、/update/local/#
```

欄位定義見 「MQTT Discovery」章節。

| 欄位 | 說明 |
|------|------|
| **Endpoint** / **MqttEndpoint** | `wss://<host>/redfish/v1/Oem/Pelx/Mqtt` |
| **MqttAuth** | `RedfishSession`（`X-Auth-Token` 或 Basic Auth） |

**工具測試**：完整 MQTT 訂閱請用 **MQTTX CLI ≥ 1.11**（`-wh` 帶 HTTP Header、`--insecure` 略過自簽憑證）或 **mqtt.js**；MQTTX Desktop／Postman MQTT Request **無法**設定 WebSocket 握手 Header。curl 可驗 HTTP 401／WebSocket 101。範例見 「MQTT Discovery」章節。

**Postman**：HTTP GET 與 **WebSocket** Request 可在 Headers 手動加 `X-Auth-Token` 或 `Authorization: Basic ...`；**MQTT** Request 的 Authorization 分頁會變成 **MQTT CONNECT 帳密**，不可用於 Redfish 路徑。

## Topic ↔ Redfish 對照

| MQTT Topic | 方向 | 對應 Redfish | 說明 |
|------------|------|--------------|------|
| **`/updates/local`** | 設備 → 客戶端 | `Oem/Pelx/Interfaces` 批量 | 每秒 `value` 物件；`local` = **本機週邊** |
| **`/update/local/{addr}`** | 設備 → 客戶端 | `Oem/Pelx/Interfaces/{addr}` | 單點 `value`／`status` 變更 |
| **`/updates/ePort`** | 設備 → 客戶端 | E-Port 相關 | 若有 E-Port |

### 控制與寫入

**新整合的控制一律走 Redfish**：

| 需求 | Redfish |
|------|---------|
| 插座開／關／重啟 | `POST .../Outlets/{id}/Actions/Outlet.PowerControl` |
| DO／E-Port／DI 等 | `PATCH .../Oem/Pelx/Interfaces/{addr}` |
| 批量讀即時值 | `GET .../Oem/Pelx/Interfaces` |
| 告警門檻 | Sensor／Outlet 閾值 |

## 多點網頁即時監控

與 第 3 章 互補：

| 方案 | 請求／連線 | 刷新 | 適用 |
|------|------------|------|------|
| **MQTT 訂閱 `/updates/local`、`/update/local/#`** | 1 條 WS 長連線 | **變更即推**（≈1～2 秒級） | Pelx **專屬**監控頁、多點即時儀表板 |
| **`TelemetryService/MetricReports`** | HTTP 輪詢 | ≥ 5 秒 | OCP／第三方 DCIM、歷史趨勢 |
| **`EventService/Subscriptions`** | HTTP POST 推送 | 事件驅動 | **告警**，非連續數值 |

依 整合原則：**Pelx 多點即時看板只用 MQTT**；DCIM 只用 Redfish 常規輪詢，兩者不混用、不需額外 API。

### 建議前端流程

```
① Redfish GET /redfish/v1/Oem/Pelx/Mqtt  # Endpoint、MqttAuth
② POST SessionService/Sessions              # X-Auth-Token（DCIM）
③ MQTT connect Endpoint                     # 訂閱 /updates/local、/update/local/#
④ Redfish GET .../Metrics                   # 頂部摘要（5 秒）
⑤ Redfish POST .../EventService/Subscriptions  # 告警
⑥ 控制 → Outlet.PowerControl                # Redfish
```

## OCP 合規與文件位置

* MQTT **不寫入** OCP 必填 spec 章節；連線資訊見 「MQTT Discovery」章節
* Topic 定義見 「MQTT Discovery」章節

* 告警與事件
* 進階擴充
* 「MQTT Discovery」章節

# 第二部分 API 規格

本部分為各 Redfish 資源的完整欄位定義、JSON 範例與 Pelx OEM 擴充說明。

# API 規格索引

下列為 Redfish API 規格章節索引。

| 模組 | 說明 |
| ------ | ------ |
| 總覽與合規 | 協議範圍、OCP Profile 對照、服務資訊、通用欄位 |
| 驗證紀錄 | Redfish 版本、Profile、Service／Interop Validator、日期與範圍 |
| 設施 Redfish 落地契約 | LeakZone／CDU URI 定稿、必填欄位、分期驗收 |
| CDU 共通介面 | 角色鍵→Sensor；對上 Redfish；一個 CDU 畫面 |
| AI 機房資源樹（說明） | 圖解；衝突時以契約為準 |
| 認證 | SessionService、AccountService（帳號 CRUD、密碼政策、LDAP／RADIUS／TACACS+）、CertificateService（含 UACME）、Basic／Token、**RBAC 與文件撰寫慣例** |
| 探索與識別 | Service Root、Chassis、Managers、RackPDUs |
| 網路協定 | NetworkProtocol（NTP、SNMP、SSH、ICMP） |
| 電力與配電 | PowerEquipment、Mains、Metrics、Sensors |
| ATS 轉換開關 | TransferSwitches、Feeders（DSP2056；設備支援 ATS 時） |
| 插座 | Outlets、PowerControl |
| 插座群組 | OutletGroups（DSP2056） |
| 環境感測 | Chassis Thermal |
| 告警與事件 | EventService、Subscriptions |
| 出站連線 | AccountService/OutboundConnections（WebSocket） |
| 歷史訊息 | Managers LogServices |
| 歷史趨勢 | TelemetryService |
| 韌體與組態 | UpdateService、TaskService、PelxConfiguration |
| 讀取流程 | curl、redfishtool、OCP Interop Validator |
| 錯誤回應 | 通用 HTTP／Redfish 錯誤格式 |

## 其他產品（非 PDU）

| 模組 | 說明 |
| ------ | ------ |
| iLock 電子鎖主機 | 門禁控制、卡號、參數（iLock 電子鎖主機） |

## Pelx 擴充

| 模組 | 說明 |
| ------ | ------ |
| 擴充總覽 | OEM 路徑說明（含工程組態同一入口） |
| OEM 介面 | Oem/Pelx/Interfaces |
| 週邊樹 | Oem/Pelx/PeripheralTree |
| MQTT Discovery | Oem.Pelx.MqttEndpoint |
| 排程 | Oem/Pelx/Schedules |
| RS485 | Oem/Pelx/SerialBuses |
| VNode | Oem/Pelx/VNodes |
| 圖控 | Oem/Pelx/HmiScreens（含樣版 Export／ImportTemplate） |
| 圖庫 | Oem/Pelx/HmiImageLibraries |
| 自動化流程 | Oem/Pelx/Automations |
| E-Port 週邊 | 內部 `GET/PATCH /e-ports/{port}/peripherals` |

# Redfish API 總覽

以下 API 皆以對外入口 `https://<host>/redfish/v1/...` 撰寫。

## 協議範圍

本文件描述 **OCP Rack PDU Profile v1.0.0**（[OCPRackPDU.v1_0_0.json](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/RackAndPower/OCPRackPDU.v1_0_0.json)）及相依的 **OCP Service Baseline v1.0.0** 所要求的 Redfish REST API，並以 [DMTF DSP2056](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf) 為資源模型基礎。Pelx OEM 路徑（`Oem/Pelx/*`）列於 Pelx 擴充 章節，**不計入** OCP Profile 合規範圍。

| 項目 | 說明 |
|------|------|
| 介面風格 | HTTP RESTful，`GET` / `POST` / `PATCH` / `DELETE` |
| 資料格式 | JSON，含 `@odata.id`、`@odata.type` 等 Redfish 標準欄位 |
| 根路徑 | `/redfish/v1` |
| 認證 | HTTP Basic Auth，或 `SessionService` + `X-Auth-Token` |
| Profile | OCP Rack PDU 1.0.0 + OCP Service Baseline 1.0.0（RequiredProfiles） |

## 設計依據

| 來源 | 說明 |
|------|------|
| [OCP Rack PDU Profile v1.0.0](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/RackAndPower/OCPRackPDU.v1_0_0.json) | **主要合規依據**；PDU 量測、插座、Metrics、Circuit 等必填欄位 |
| [OCP Service Baseline v1.0.0](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/OCPServiceBaseline.v1_0_0.json) | ServiceRoot、Manager、Session、Account、UpdateService、TaskService |
| OCP Rack PDU Usage Guide | Profile 使用案例與 JSON 範例 |
| [DMTF DSP2056 — Redfish for Power Distribution Equipment](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf) | Rack PDU 資源樹、Circuit、Outlet、PowerEquipment 標準模型 |
| [Redfish Authentication](https://redfish.redoc.ly/docs/concepts/redfishauthentication/) | Session Token 與 `X-Auth-Token` 使用方式 |

## OCP Rack PDU Profile 對照

> **驗證故事總表**（版本、兩種 Validator、日期、範圍）：見 validation。

Profile 定義 **Mandatory** 資源與欄位；實作須通過 [Redfish Interop Validator](https://github.com/DMTF/Redfish-Interop-Validator) 搭配下列兩份 JSON 驗證：

| 路徑（HWMgmt-OCP-Profiles 倉庫） |
| ---------------------------------- |
| `RackAndPower/OCPRackPDU.v1_0_0.json` |
| `OCPServiceBaseline.v1_0_0.json` |

```bash
git clone https://github.com/opencomputeproject/HWMgmt-OCP-Profiles.git
pipx install redfish-interop-validator

rf_interop_validator \
  -r https://<host> \
  -u admin -p '<password>' \
  --authtype Basic \
  --required_profiles_dir ./HWMgmt-OCP-Profiles \
  ./HWMgmt-OCP-Profiles/RackAndPower/OCPRackPDU.v1_0_0.json
```

> Profile 目前為 **Draft**（`RackAndPower/` 子目錄）。本文件 JSON 範例以通過上述 Validator 為目標撰寫。

**實測進度參考**（Redfish Interop Validator，`--authtype Session`，2026-07-06）：

| Profile | Pass | Fail | Warning | Not Tested |
|---------|------|------|---------|------------|
| OCP Rack PDU v1.0.0 | 884 | 0 | 0 | 0 |
| OCP Baseline Hardware Management v1.1.1 | 271 | 0 | 0 | 0 |

兩項皆 **Validation SUCCEEDED**。

### Profile 必填資源（摘要）

| Schema | URI 範例 | Profile 重點 |
|--------|----------|----------------|
| ServiceRoot | `/redfish/v1` | `PowerEquipment`（PDU Profile）；Baseline 另須 `CertificateService`、`Product`、`Vendor`、`ProtocolFeaturesSupported`、`UpdateService` |
| PowerEquipment | `/redfish/v1/PowerEquipment` | 須含 `RackPDUs` |
| PowerDistribution | `.../RackPDUs/{rackId}` | `EquipmentType=RackPDU`、`UserLabel`、`Metrics`、`Mains`、`Branches`、`Outlets`、`Links`、`Location`、`UUID` |
| PowerDistributionMetrics | `.../RackPDUs/{rackId}/Metrics` | `PowerWatts`、`EnergykWh`、`PowerLoadPercent`；Action `ResetMetrics` |
| Circuit（Mains） | `.../Mains/{id}` | `CircuitType=Mains`、`UserLabel`、`ElectricalContext`、`PowerWatts`、`EnergykWh`、`Voltage` 或 `PolyPhaseVoltage` |
| Circuit（Branch） | `.../Branches/{id}` | 集合必須存在（可為空）；`Links.Outlets` 映射插座 |
| Outlet | `.../Outlets/{id}` | `ElectricalContext`（`Line1`／`Line2`／`Line3`）、`PowerRestorePolicy`、`Links.BranchCircuit`（Mandatory） |
| Sensor | **`/redfish/v1/Chassis/{id}/Sensors/{sensorId}`** | `Reading`、`ReadingType`、`ReadingTime`、`SensingInterval`；電氣量測須 `ElectricalContext` |
| Chassis | `/redfish/v1/Chassis/{id}` | `SerialNumber`、`PartNumber`、`Links.PowerDistribution`（**物件**，非陣列）、`Links.ManagedBy`、`Sensors`、`ThermalSubsystem`、`Location`、`PowerState`、`UUID` |
| EventService | `/redfish/v1/EventService` | `Subscriptions`（Baseline）；`RegistryPrefixes` 建議含 `Power`、`SensorEvent`、`Update` |
| Registries | `/redfish/v1/Registries` | 標準錯誤訊息註冊表（DMTF 建議） |
| Manager | `/redfish/v1/Managers/{id}` | `DateTime`、`UUID`、`FirmwareVersion`、`EthernetInterfaces`、`LogServices` |
| Session / Account / Certificate / Update / Task | 見各章節 | 依 OCP Service Baseline |

### 管理與安全 API OCP 合規對照

下列為近期補強的 **AccountService**、**CertificateService**、**NetworkProtocol** 等管理面 API。OCP **Mandatory** 表示 Interop Validator（搭配 Service Baseline）會檢查；**Recommended** 為建議實作；**Oem** 為 Pelx 擴充，**不計入** Profile 合規，但符合 DMTF「標準路徑 + Oem 延伸」慣例（參考 Vertiv 等 PDU Redfish 實務）。

| 功能 | Redfish 路徑 | OCP／DMTF | 規格 | 備註 |
| ------ | ------------- | ----------- | ------ | ------ |
| 帳號 CRUD | `AccountService/Accounts` | **Mandatory** | 認證 | `POST` 須 201 + `Location` |
| 角色三類 | `AccountService/Roles` | **Mandatory** | 認證 | Administrator／Operator／ReadOnly |
| 密碼長度 | `AccountService` `MinPasswordLength` 等 | **Mandatory** | 認證 | Vertiv 等皆有 |
| 密碼複雜度 | `Oem.Pelx.PasswordPolicy` | Oem | 認證 | 複雜度規則放 Oem |
| LDAP | `AccountService.LDAP` | **Recommended** | 認證 | `PATCH AccountService` |
| RADIUS | `Oem.Pelx.Radius` | Oem | 認證 | DMTF 無單一標準屬性 |
| TACACS+ | `Oem.Pelx.Tacacs` | Oem | 認證 | Pelx OEM |
| LDAP／RADIUS／TACACS+ 測試 | `Actions/PelxAccountService.Test*` | Oem | 認證 | 廠商加值 Action |
| OutboundConnection | `AccountService/OutboundConnections` | 選配（2023.2+） | outbound connection | 設備主動 WebSocket 連雲端 |
| 手動憑證 CSR | `CertificateService.GenerateCSR` | **Mandatory** | 認證 | 須 `CertificateMode=manual` |
| NTP | `NetworkProtocol.NTP` | **Mandatory** | 網路協定 | Vertiv：可 PATCH `NTPServers` |
| SNMP | `NetworkProtocol.SNMP` | **Mandatory** | 網路協定 | 基本開關；v3 細節放 Oem |
| SSH | `NetworkProtocol.SSH` | **Mandatory** | 網路協定 | 生產預設可 `false` |
| ICMP ping | `Oem.Pelx.ICMPEchoReply` | Oem | 網路協定 | DMTF 無標準屬性 |
| SNMP Agent 細節 | `Oem.Pelx.SNMPAgent` | Oem | 網路協定 | GET 不回傳 community 明文 |

**Validator 額外檢查點**

* 密碼不符政策：回傳標準 `error`（如 `PropertyValueIncorrect`）
* `NetworkProtocol`：`ProtocolEnabled`、`Port` 型別正確；非法 NTP 伺服器回 **400**
* `CertificateService`：建議提供 `GenerateCSRActionInfo`（`@Redfish.ActionInfo`）
* 所有資源須含 `@odata.type`；可寫資源建議含 `Allow` 與 `@Redfish.WriteableProperties`

### Sensor 雙路徑說明

OCP Profile 規定 Sensor 資源 URI 為 **`Chassis/{chassisId}/Sensors/{sensorId}`**。Pelx 另於 `PowerEquipment/RackPDUs/{rackId}/Sensors` 暴露相同量測（DSP2056 配電模型）；**Interop Validator 僅驗證 Chassis 路徑**。實作須：

* `Chassis/1/Sensors` 列出所有電氣與環境溫度感測器（與 RackPDU `Sensors` 成員一致；溫度 `{id}` 如 `Temp1`）
* `Mains`／`Outlets`／`Metrics` 的 `DataSourceUri` 指向 `Chassis/1/Sensors/...`
* `PowerEquipment/.../Sensors` 保留供配電整合快速查詢（非 OCP 驗證路徑）

### 一次回應多筆資料

Redfish／OCP **沒有**獨立的「bulk read」端點，但 DMTF 標準提供多種機制，讓 DCIM 客戶端**減少 HTTP 往返**、一次取得多筆讀值或多個子資源。整合方應依場景選擇：

| 機制 | 一次取得什麼 | OCP／Baseline | 典型 URL |
|------|-------------|---------------|----------|
| **資源內多欄位** | 單一資源含多個即時量測 | **Metrics Mandatory** | `GET .../RackPDUs/1/Metrics` → `PowerWatts`、`EnergykWh`、`PowerLoadPercent` |
| **Collection `Members`** | 多筆子資源**連結**（`@odata.id`） | 各集合 **Mandatory** | `GET .../Outlets` → 所有插座 URI 列表 |
| **`$expand` 查詢** | 集合＋各成員**完整 JSON** 內嵌 | `ExpandQuery` **Recommended** | `GET .../Outlets?$expand=.` |
| **`$expand` 多層** | PDU 與下層子資源一次展開 | 同上（須服務支援） | `GET .../RackPDUs/1?$expand=.($levels=2)` |
| **`TelemetryService` `MetricReports`** | 歷史量測**陣列**（多時間點、可多 Metric） | DMTF 標準；**非 OCP 必填** | `GET .../MetricReports/{id}` → `MetricValues[]` |
| **`OutletGroup.PowerControl`** | 一次 Action **控制**群組內多插座（寫入） | DSP2056；**非 OCP 必填** | `POST .../OutletGroups/{id}/Actions/OutletGroup.PowerControl` |
| **Event 推送** | 設備主動 POST 多筆 `Events[]` | `Subscriptions` Baseline | 告警狀態變更 → `Destination` |

**重點區分**

* **Collection 預設只回連結**，不含各成員的 `Reading`、`PowerState` 等即時值。要一次拿所有插座狀態，須用 **`$expand`**（若設備支援，見 Service Root `ProtocolFeaturesSupported.ExpandQuery`），或對 `Members` 逐筆 `GET`。
* **沒有**「單一 GET 回傳所有插座即時讀值」的 OCP 必填資源；`Metrics` 僅提供**整機彙總**，非逐路明細。
* **歷史／趨勢批量讀值**的標準路徑是 **`TelemetryService/MetricReports/{id}`**：回應內 `MetricValues` 陣列，每筆含 `MetricId`、`MetricValue`、`Timestamp`（見 歷史趨勢）。
* **即時監控** OCP 主線：`Metrics`（彙總）＋必要時 `$expand` 或輪詢 `Outlets`／`Chassis/Sensors`（見 第 3 章）。
* **同時多點網頁即時顯示**：多點即時看板用 **MQTT** `/update`；第三方 DCIM 用 Redfish 常規輪詢（`Metrics`、`Outlets`、`Sensors`，15～60 秒）；見 integration 整合原則。

`ProtocolFeaturesSupported` 宣告與 `$expand` 範例見 探索與識別；curl 範例見 讀取流程。

### 選配資源（DMTF 標準，非 OCP 必填）

下列為 DMTF Redfish 標準資源，Pelx 產品依機型或功能提供；OCP Rack PDU Profile 驗證**不要求**，整合若僅需 OCP 合規可忽略：

* `PowerEquipment/TransferSwitches`（ATS；見 ATS 轉換開關）
* `PowerEquipment/RackPDUs/{id}/OutletGroups`（插座群組；見 插座群組）
* `TelemetryService`（歷史趨勢；見 歷史趨勢）

### Pelx 擴充（OEM，非 OCP 必填）

下列為 Pelx OEM 路徑，**非** DMTF 標準資源模型：

* `Oem/Pelx/Interfaces`（完整介面；大量即時請用 MQTT，見 第 11 章）
* `Oem/Pelx/PeripheralTree`（週邊結構樹；設備週邊結構服務，見 週邊樹）
* `Oem.Pelx.MqttEndpoint`（MQTT 連線 URL；Redfish Discovery，見 MQTT Discovery）
* `Oem/Pelx/Configuration`（組態檔單獨上傳／下載）
* `Oem/Pelx/Schedules`（排程）
* `EventService/Events`（目前告警快照；OCP 標準事件訂閱見 `Subscriptions`）

* `GET /redfish/v1` 與 `GET /redfish/v1/` 皆應 **200**（勿對 `/redfish/v1/` 做 301 轉址）。

### 資源樹概覽（OCP Rack PDU Profile）

```
/redfish/v1                          ServiceRoot（OCP Baseline + PowerEquipment）
├── SessionService/Sessions          認證工作階段（Baseline）
├── AccountService/Accounts          帳號（Baseline）
├── AccountService/Roles             角色（Baseline）
├── AccountService/OutboundConnections  出站 WebSocket（2023.2+ 選配；已實作）
├── CertificateService               憑證服務（Baseline）
├── Managers/1                       管理控制器（Baseline）
│   ├── EthernetInterfaces/{id}      網路介面（Baseline Mandatory）
│   ├── NetworkProtocol              通訊協定設定（Baseline）
│   └── LogServices/{logId}/Entries  日誌（Baseline）
├── Chassis/1                        機箱（OCP PDU Profile）
│   ├── Sensors/{id}                 感測器（OCP Profile Mandatory URI）
│   ├── Thermal                      溫濕度（建議）
│   └── Power                        電源（可選）
├── PowerEquipment                   PDU 配電（OCP Profile 核心）
│   ├── TransferSwitches/{id}        ATS（DSP2056；設備支援 ATS 時）
│   └── RackPDUs/{id}                PowerDistribution
│       ├── Metrics                  PowerDistributionMetrics（Profile Mandatory）
│       ├── Mains/{id}               進線 Circuit
│       ├── Branches/{id}            分支 Circuit（集合必須存在；可為空）
│       ├── Outlets/{id}             插座 Outlet
│       ├── OutletGroups/{id}        插座群組（DSP2056）
│       └── Sensors/{id}             感測器 Sensor
├── TelemetryService                 歷史趨勢（DMTF 標準；非 OCP 必填）
├── EventService                     事件服務（Baseline + Profile）
│   ├── Subscriptions/{id}           事件訂閱（Usage Guide 建議）
│   └── Events                       目前告警快照（Pelx OEM）
├── UpdateService                    韌體更新（Baseline Mandatory）
│   ├── FirmwareInventory/Image      設備映像
│   ├── SimpleUpdateActionInfo       SimpleUpdate 參數定義
│   ├── upload                       上傳映像
│   └── Oem/Pelx/Configuration    組態備份／還原（Pelx OEM）
├── TaskService/Tasks/{taskId}       非同步任務（Baseline）
└── Oem/Pelx/*                    Interfaces、PeripheralTree、Schedules 等（Pelx OEM；PDU 選用）
```

iLock 電子鎖主機之 Service Root **不含** `PowerEquipment`；門禁 API 見 iLock 電子鎖。

---

## 通用 JSON 欄位

各 API 回應格式如下所示：先列 JSON 範例，再以「#### 欄位說明如下」**逐欄、逐層**說明（含巢狀子物件與陣列元素）。下列為常見欄位語意速查，各 API 章節仍會完整列出該回應的所有欄位。

### Redfish 標準欄位

* **@odata.id**: 資源 URI（如 `/redfish/v1/Chassis/1`），後續請求可直接使用
* **@odata.type**: 資源型別，對應 DMTF Schema 版本（**Mandatory**；缺此欄位 Interop Validator 報 `Missing Type Error`）
* **Id**: 資源識別碼，通常與 URI 最後一段相同
* **Name**: 顯示名稱
* **Members**: 集合成員連結陣列，元素為 `{ "@odata.id": "..." }`
* **Members@odata.count**: `Members` 筆數
* **Status**: 狀態物件
  * **State**: 運作狀態，如 `Enabled`（正常）、`Disabled`（停用）、`Absent`（不存在）
  * **Health**: 健康狀態，`OK` / `Warning` / `Critical`，由介面狀態碼轉換，見文末「狀態對照」
  * **HealthRollup**: 子資源健康彙整（Chassis 等上層資源使用）

### HTTP 回應標頭與可寫屬性標註

含可寫屬性（`UserLabel`、`Location` 等）的資源，`GET` 回應須同時提供：

1. **`Allow` 標頭** — 供 Validator 確認支援 `PATCH`
2. **`@Redfish.WriteableProperties`** — 標示可 `PATCH` 的屬性；`Location`：`Contacts`；`Location.Placement`：`Rack`、`Row`、`RackOffset`、`RackOffsetUnits` |
| RackPDU | `GET, PATCH` | 根層：`AssetTag`、`UserLabel`、`LocationIndicatorActive`；`Location`／`Placement` 同 Chassis |
| Mains | `GET, PATCH` | `UserLabel`、`ElectricalSourceManagerURI`、`ElectricalSourceName` |
| Outlet | `GET, PATCH` | `UserLabel`、`ElectricalConsumerNames`、`LocationIndicatorActive` |

> **PATCH 持久化**：部分可寫欄位重啟後還原；長期保存請用組態備份／還原。

範例（Chassis）：

```json
{
  "@odata.id": "/redfish/v1/Chassis/1",
  "@odata.type": "#Chassis.v1_22_0.Chassis",
  "@Redfish.WriteableProperties": [
    "AssetTag"
  ],
  "Id": "1",
  "Location": {
    "@Redfish.WriteableProperties": [
      "Contacts"
    ],
    "Placement": {
      "@Redfish.WriteableProperties": [
        "Rack",
        "Row",
        "RackOffset",
        "RackOffsetUnits"
      ],
      "Rack": "Rack-01"
    }
  }
}
```

對應回應標頭：`Allow: GET, PATCH`

缺 `@Redfish.WriteableProperties` 時，Validator 報 `WriteableProperties Warning`（即使已有 `Allow` 標頭）。

### 量測與閾值欄位

* **Reading**: 即時數值，對應 `GET /interfaces` 的 **value**
* **ReadingVolts** / **ReadingCelsius** / **ReadingAmps** 等: 具單位語意的讀值（部分資源直接放在物件頂層）
* **DataSourceUri**: 指向 `Sensors/{id}` 的連結，供進一步查詢感測器細項
* **Thresholds** / **UpperThresholdCritical** 等: 閾值，對應 `interfaces` 的 **params**
  * **hc** → `UpperThresholdCritical` / `UpperCritical`
  * **hw** → `UpperThresholdNonCritical` / `UpperCaution`
  * **lw** → `LowerThresholdNonCritical` / `LowerCaution`
  * **lc** → `LowerThresholdCritical` / `LowerCritical`

### Oem.Pelx 擴充欄位

、`interfaces`；**對外一律以 `@odata.id` 資源連結表示**，以 `@odata.id` 表示。自 hwctrl 2026 合規版起，**不再使用** `Oem.Pelx.Links` 包裝：

* **@odata.type**: 固定 `#Pelx.v1_0_0.Pelx`（DMTF Service Validator 必填）
* **Interface**: 單一 Pelx 介面資源連結（`Pelx.InterfaceLink`，僅 `@odata.id`）；用於 Sensor、Event、Thermal 等
* **Interfaces**: 多個量測／控制對應之介面連結物件（如 `Voltage`、`CurrentAmps`、`PowerState`）；用於 Mains、Outlet、Branch
* **InterfaceGroups**: 三相等巢狀量測對照（如 `PolyPhaseVoltage.Line1ToNeutral`）；用於 `INFEED3P` 進線

CSDL 定義內嵌於 `GET /redfish/v1/$metadata`，亦可 `GET /redfish/v1/schemas/Pelx_v1.xml`（部署路徑：`/root/rpm6/share/rpm6/redfish/schemas/Pelx_v1.xml`）。執行 DMTF Service Validator 時，本機 `csdl/Pelx_v1.xml` 須與設備同步。
* **MqttAuth**: MQTT 認證方式（Redfish：`RedfishSession`）
* **ElementId** / **elementId**: 週邊路數，對應週邊路數
* **Alias** / **alias**: 介面別名（如 `V`、`FREQ`）
* **peripheralAlias**: 週邊分類別名（如 `INFEED`、`OUTLET`、`TEMPRH`）
* **Unit** / **unit**: 資料單位（如 `V`、`°C`、`kWh`）
* **type**: 資料型別，如 `FLOAT`、`BOOL`、`STRING`
* **value**: 即時讀值，同即時讀值欄位
* **status**: 介面狀態碼（如 `ok`、`hw`、`hc`），見 mqtt-topic
* **params**: 閾值參數，欄位同 `GET /interfaces` 的 **params**
* **health**: 已由 `status` 轉換的 Redfish `Health` 值

---

# 認證

支援兩種方式，與多數 PDU 廠商（Vertiv、eConnect 等）一致：

1. **HTTP Basic Auth** — 適合單次查詢、腳本測試；每次請求帶 `Authorization: Basic ...`
2. **Session Token** — 適合長時間輪詢；先 `POST /redfish/v1/SessionService/Sessions` 取得 `X-Auth-Token`，後續請求帶此標頭

### 認證架構

| 項目 | 說明 |
|------|------|
| 帳號來源 | 與 Web 登入共用，**不需**另建 Redfish 專用帳號庫 |
| Redfish 協議 | Basic Auth、`SessionService`、`X-Auth-Token` |

`POST /redfish/v1/SessionService/Sessions` 建立 Redfish Session 並回傳 `X-Auth-Token`。

Redfish 服務依 auth **role** 映射權限如下：

| auth role | Web UI 名稱 | Redfish `RoleId` | 摘要 |
|-----------|------------|------------------|------|
| admin | 系統管理員 | Administrator | 讀寫全部資源；**工程模式**讀寫；帳號 CRUD（含同級系統管理員） |
| manager | 管理員 | Operator | 讀取全部；**控制**與一般選單寫入；帳號 CRUD 僅限 Operator／ReadOnly |
| viewer | 檢視者 | ReadOnly | OCP 基礎角色：可登入、可改自己密碼、可讀監測；**嚴禁**配置修改與控制 |
| app | — | — | **不開放** Redfish 登入 |

#### ReadOnly（OCP Baseline 基礎角色）

**ReadOnly** 為 OCP Service Baseline **Mandatory** 三角色之一（與 `Administrator`、`Operator` 並列），DMTF 預設 `AssignedPrivileges` 為 **`Login`**、**`ConfigureSelf`**（**不含** `ConfigureComponents`、`ConfigureManager`、`ConfigureUsers`）。

核心規範（Pelx 實作須符合）：

| 允許 | 禁止 |
|------|------|
| **登入** Redfish（Basic／Session） | 任何 **控制 Action**（`POST .../Actions/*`） |
| **修改自己的密碼**（`ConfigureSelf`；`PATCH .../Accounts/{id}` 僅 `Password` 且為本人） | 任何**配置修改**（`PATCH`／`POST`／`DELETE` 其他資源或欄位） |
| **讀取監測與 Inventory**（`GET`：Outlets、Metrics、Sensors、Events 等） | 管理他人帳號、LDAP／SNMP 等工程模式讀寫 |

> **Pelx 追加限制**（嚴於部分廠商慣例，不違反 OCP）：`GET .../AccountService/Accounts` 須 **Operator 以上**；工程模式資源之 `GET`／寫入須 **Administrator**。其餘監測類 `GET` 依預設，ReadOnly 可讀。

### 角色與權限模型（RBAC）

與 Web UI 選單對齊。

#### 權限層級

| 層級 | 適用角色 | 說明 |
|------|----------|------|
| **讀取** | ReadOnly 以上 | `GET` 監測、Inventory、事件列表等 |
| **控制** | **Operator 以上** | `POST .../Actions/*`：插座開關／重啟、群組控制、電子鎖、能耗重設、排程 Run 等 |
| **一般寫入** | **Operator 以上** | `PATCH`／`POST`／`DELETE`（非工程模式）：排程 CRUD、ATS 參數、NTP／SSH 等 |
| **工程模式** | **Administrator 專屬** | 週邊診斷、RS485／VNode／圖控／Flow、帳號服務、憑證、SNMP Agent、韌體／組態、告警通道設定等 |

**ReadOnly** 僅能 **登入**、**改自己密碼**、**GET 監測數據**；**嚴禁**任何配置修改與控制 Action。**Administrator** 涵蓋 Operator 全部權限（含控制）。

#### Web「工程模式」↔ Redfish API

工程模式選單（週邊資訊、密碼政策、LDAP、RADIUS／TACACS+、SNMP Agent、告警服務、韌體更新）對外整合時對應下列 Redfish；**讀寫皆須 Administrator**（`403` 若為 Operator／ReadOnly）：

| Web 工程模式 | Redfish API（摘要） | 備註 |
|--------------|---------------------|------|
| 週邊資訊 | `GET/PATCH .../Oem/Pelx/Interfaces/{addr}` | 診斷用介面 |
| RS485／UART | `GET/PATCH .../Oem/Pelx/SerialBuses/{id}` | 見 oem serial buses；`devinfo.rs485` |
| VNode | `GET/PATCH .../Oem/Pelx/VNodes/{id}`、`PelxVNode.Test` | 見 oem vnodes；`devinfo.vnode` |
| 圖控 HMI | `GET/POST/PATCH/DELETE .../Oem/Pelx/HmiScreens`、`.../Export`、`PelxHmiScreen.ExportTemplate`／`ImportTemplate` | 見 oem hmi screens；含樣版匯出／載入；`devinfo.hmi` |
| 圖控圖庫 | `.../Oem/Pelx/HmiImageLibraries`、`PelxHmiImageLibrary.Import` | 見 oem hmi image libraries；`devinfo.hmi` |
| 自動化流程 | `GET/POST/PATCH/DELETE .../Oem/Pelx/Automations` | 見 oem automations；`devinfo.autoBuilder`；聯鎖執行仍在本地 |
| 密碼政策 | `PATCH .../AccountService`（密碼政策欄位） | 見本文 AccountService |
| LDAP | `PATCH .../AccountService`（`LDAP`） | |
| RADIUS | `PATCH .../AccountService`（`Oem.Pelx.Radius`） | |
| TACACS+ | `PATCH .../AccountService`（`Oem.Pelx.Tacacs`） | |
| SNMP Agent | `PATCH .../Managers/1/NetworkProtocol`（`SNMP`、`Oem.Pelx.SNMPAgent`） | 見 網路協定 |
| 告警服務 | notify／`EventService` 設定 | 訂閱建立見 告警與事件 |
| 韌體更新 | `UpdateService/upload`、`SimpleUpdate`、`PelxConfiguration` | 見 韌體與組態 |
| HTTPS／UACME | `CertificateService` | 見本文 CertificateService |

同一資源內若混有工程與一般欄位（如 `NetworkProtocol`），依欄位路徑分別檢查：SNMP 區塊須 Administrator；NTP／SSH／ICMP 區塊須 Operator 以上（見 網路協定）。

#### 一般選單（非工程模式）控制與寫入

**控制 Action** 與一般寫入皆須 **Operator 以上**；**ReadOnly** 回 `403`。

**控制**（`POST .../Actions/*`）：

* 插座／插座群組：`Outlet.PowerControl`、`OutletGroup.PowerControl`、`Outlet.ResetMetrics`
* 電子鎖：`PelxElectronicLock.Control`
* 電力：`ResetMetrics`（Rack PDU／Mains）
* 排程：`Schedules/{id}/Actions/...Run` 等

**一般寫入**（`PATCH`／`POST`／`DELETE`）：

* 排程 CRUD、ATS 參數、電子鎖白名單／卡號
* `Managers/1/NetworkProtocol` 之 NTP、SSH、ICMP（非 SNMP Agent）
* `EventService/Subscriptions` 建立／修改（若產品政策允許 Operator 管理訂閱）
* `AccountService/OutboundConnections` 建立／修改／刪除（**Administrator**；見 outbound connection）

#### 帳號 CRUD 授權矩陣

`POST`／`PATCH`／`DELETE` `AccountService/Accounts` 依**呼叫者角色**與**目標帳號 RoleId** 決定：

| 操作 | 目標 `RoleId` | 允許的呼叫者 |
|------|---------------|--------------|
| `POST` 建立 | `Administrator` | **僅** Administrator（系統管理員） |
| `POST` 建立 | `Operator`、`ReadOnly` | Administrator **或** Operator（管理員） |
| `PATCH` 修改 | `Administrator` | **僅** Administrator |
| `PATCH` 修改 | `Operator`、`ReadOnly` | Administrator **或** Operator |
| `DELETE` 刪除 | `Administrator` | **僅** Administrator |
| `DELETE` 刪除 | `Operator`、`ReadOnly` | Administrator **或** Operator |

附加規則：

* Operator **不可**將既有帳號之 `RoleId` 改為 `Administrator`，**不可**修改或刪除 `RoleId` 為 `Administrator` 的帳號
* 不可刪除**最後一個** `Administrator` 帳號
* `GET .../Accounts`／`{id}`：**Operator 以上**；ReadOnly 回 `403`（帳號清單屬敏感資訊）
* Operator 建立／管理之帳號，`RoleId` 僅能為 `Operator` 或 `ReadOnly`

`403` 回應時 `Message` 宜註明「權限不足」或「不可管理系統管理員帳號」。

#### Role 資源與 OemPrivileges

`GET .../AccountService/Roles/{RoleId}` 之 **OemPrivileges** 反映 Pelx 工程模式（非 DMTF 標準必填）：

| `RoleId` | `OemPrivileges`（Pelx） |
|----------|---------------------------|
| Administrator | `["ConfigureEngineering"]` |
| Operator | `[]` |
| ReadOnly | `[]` |

整合方可先 `GET .../Roles/{RoleId}` 判斷是否具工程模式寫入資格。

### 文件撰寫慣例（各 spec 章節）

各 API 章節**不必**逐條重複最低角色；以本文「角色與權限模型」為**唯一權威來源**。

#### 預設規則

| HTTP 方法 | 最低 `RoleId` | 說明 |
|-----------|---------------|------|
| `GET` | **ReadOnly** | 監測、Inventory、韌體版本等 |
| `POST .../Actions/*`（**控制**） | **Operator** | 插座開關、群組控制、電子鎖、能耗重設等 |
| `POST`／`PATCH`／`DELETE`（設定） | **Operator** | 排程 CRUD、NTP／SSH 等一般寫入 |
| 工程模式 API | **Administrator** | 見上方工程模式對照表 |
| 帳號 CRUD | 依矩陣 | 見「帳號 CRUD 授權矩陣」 |

#### 僅在下列情況於 API 段落**額外**標註

| 情況 | 寫法 |
|------|------|
| 須 **Administrator**（Operator 不可） | 段落開頭或 `403` 註明「須 Administrator（工程模式）」 |
| **混合資源**（同 `PATCH` 欄位分級） | 該章節寫欄位級對照表（如 網路協定） |
| **帳號 CRUD** | 寫「依帳號 CRUD 授權矩陣」；不重複整張表 |
| **`GET` 比 ReadOnly 更嚴** | 標註例外（如 `GET .../Accounts` 須 Operator） |

符合預設的控制 Action 與 `POST`／`PATCH`（如 `Outlet.PowerControl`、排程 CRUD）**不必**再寫「須 Operator 以上」。各章可在標題下加一行：「權限預設見 認證（**控制 Action 至少 Operator**）。」

#### `403` 撰寫

| 情境 | 狀態表寫法 |
|------|------------|
| ReadOnly 嘗試控制或寫入 | `403 \| 權限不足` |
| 工程模式 | `403 \| 須 Administrator` |
| 帳號矩陣 | 具體說明（如不可管理系統管理員帳號） |

整合方應以 **Redfish `AccountService/Accounts`** 建立專用帳號（OCP Baseline **Mandatory**），例如 `dcim-read` 設 `RoleId: ReadOnly`、`dcim-ctrl` 設 `Operator`，與管理員 `admin` 分離。與 Web UI 共用帳號庫。。

### OCP AccountService 要求（摘要）

| 操作 | HTTP | OCP Baseline |
|------|------|--------------|
| 列出／查詢帳號 | `GET .../Accounts`、`GET .../Accounts/{id}` | **Mandatory** |
| 新增帳號 | `POST .../AccountService/Accounts` | **Mandatory** |
| 修改帳號 | `PATCH .../Accounts/{id}` | **Mandatory** |
| 刪除帳號 | `DELETE .../Accounts/{id}` | **Mandatory** |
| 角色定義 | `GET .../AccountService/Roles` | **Mandatory** |

標準角色 **Administrator**、**Operator**、**ReadOnly** 為 OCP 必填；`app` 角色**不**經 Redfish 暴露。

### 外部帳號提供者（LDAP／RADIUS／TACACS+）

OCP PDU 對 LDAP、RADIUS 為 **Recommended**（非 Baseline Mandatory）。TACACS+ 為 Pelx OEM 擴充：

| 協定 | Redfish 路徑 |
| ------ | ------------- |
| LDAP | `PATCH /AccountService` 之 `LDAP` 物件 |
| RADIUS | `PATCH /AccountService` 之 `Oem.Pelx.Radius` |
| TACACS+ | `PATCH /AccountService` 之 `Oem.Pelx.Tacacs` |
| LDAP 連線測試 | `POST .../Actions/PelxAccountService.TestLDAPConnection` |
| RADIUS 連線測試 | `POST .../Actions/PelxAccountService.TestRADIUSConnection` |
| TACACS+ 連線測試 | `POST .../Actions/PelxAccountService.TestTACACSConnection` |

### 密碼強度政策

本地帳號密碼須符合 `AccountService` 內嵌政策（OCP **Recommended**）。透過 AccountService 設定。

建立或修改帳號（`POST`／`PATCH Accounts`）時，依此政策驗證 `Password`。

### Interop Validator 與認證

| 模式 | 說明 |
|------|------|
| **Basic**（建議） | Validator 對 `GET /redfish/v1` **不帶**認證；子資源請求帶 Basic。Service Root 須允許匿名讀取。 |
| **Session** | Validator 自 Service Root 讀取 `Links.Sessions.@odata.id` 後 `POST` 建立 Token。若 Service Root 無 `Links.Sessions`，Session 無法建立。 |

對外須轉送 `Authorization`、`X-Auth-Token`（見「服務資訊」）。

### GET https://<host>/redfish/v1/SessionService

取得 Session 服務能力與逾時設定。

```json
{
  "@odata.id": "/redfish/v1/SessionService",
  "@odata.type": "#SessionService.v1_1_1.SessionService",
  "Id": "SessionService",
  "Name": "Session Service",
  "ServiceEnabled": true,
  "SessionTimeout": 1800,
  "Sessions": {
    "@odata.id": "/redfish/v1/SessionService/Sessions"
  },
  "Actions": {
      }
}
```

#### 欄位說明如下:

* **@odata.id**: Session 服務 URI
* **@odata.type**: 資源型別，固定 `#SessionService.v1_1_1.SessionService`
* **Id**: 固定為 `SessionService`
* **Name**: 顯示名稱
* **ServiceEnabled**: Session 服務是否啟用，`true` 表示可建立工作階段
* **SessionTimeout**: 工作階段逾時（秒），預設 `1800`（30 分鐘），可 `PATCH` 調整（範圍 30–86400）
* **Sessions**: Session 集合連結物件
  * **@odata.id**: Session 列表 URI，固定 `/redfish/v1/SessionService/Sessions`；`GET` 可列出有效 Session，`POST` 可建立新 Session
* **Actions**: Pelx 擴充 Action
  
#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### PATCH https://<host>/redfish/v1/SessionService

修改 Session 逾時。

```json
{
  "SessionTimeout": 3600
}
```

#### 欄位說明如下:

* **SessionTimeout**: 工作階段逾時（秒），範圍 30–86400

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 參數錯誤
403   | 權限不足

### GET https://<host>/redfish/v1/SessionService/Sessions

列出目前有效 Session。

```json
{
  "@odata.id": "/redfish/v1/SessionService/Sessions",
  "@odata.type": "#SessionCollection.SessionCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/SessionService/Sessions/a1b2c3d4"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: Session 集合資源 URI，固定 `/redfish/v1/SessionService/Sessions`
* **@odata.type**: 資源型別，固定 `#SessionCollection.SessionCollection`
* **Members**: 目前有效 Session 連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一 Session 資源 URI，如 `/redfish/v1/SessionService/Sessions/a1b2c3d4`；`GET` 可查詳情，`DELETE` 可登出終止
* **Members@odata.count**: `Members` 陣列筆數，即目前有效 Session 數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足

### POST https://<host>/redfish/v1/SessionService/Sessions

建立認證工作階段。請求需帶 Basic Auth 或 JSON 帳密（二擇一，建議 Basic Auth）。

**方式 A — Basic Auth 標頭 + 空 body**

```http
POST /redfish/v1/SessionService/Sessions HTTP/1.1
Authorization: Basic YWRtaW46cGFzc3dvcmQ=
Content-Type: application/json
```

**方式 B — JSON body**

```json
{
  "UserName": "admin",
  "Password": "password"
}
```

#### 欄位說明如下:

* **UserName**: 登入帳號，對應 auth 使用者名稱
* **Password**: 登入密碼

#### 回傳資料格式如下:

回應標頭：

```http
HTTP/1.1 201 Created
Location: /redfish/v1/SessionService/Sessions/a1b2c3d4
X-Auth-Token: 7c3f8a2b9e1d4f6a8c0b2d4e6f8a0c2
```

回應 body：

```json
{
  "@odata.id": "/redfish/v1/SessionService/Sessions/a1b2c3d4",
  "@odata.type": "#Session.v1_7_2.Session",
  "Id": "a1b2c3d4",
  "Name": "admin",
  "UserName": "admin",
  "Description": "User Session"
}
```

#### 欄位說明如下:

* **X-Auth-Token**（回應標頭）: 後續 API 請求須帶此標頭，取代 Basic Auth
* **Location**（回應標頭）: Session 資源 URI，登出時對此 URI 執行 `DELETE`
* **@odata.id**: 新建 Session 的資源 URI
* **@odata.type**: 資源型別，固定 `#Session.v1_7_2.Session`
* **Id**: Session 識別碼，與 URI 最後一段相同
* **Name**: 通常為登入帳號名稱
* **UserName**: 登入帳號
* **Description**: 工作階段說明

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功
400   | 請求格式錯誤
401   | 帳密錯誤
403   | 帳號鎖定或權限不足

### GET https://<host>/redfish/v1/SessionService/Sessions/{id}

查詢指定 Session 資訊。請求須帶 `X-Auth-Token` 或 Basic Auth。

* **id**（路徑參數）: Session 識別碼，與 `POST /SessionService/Sessions` 回應的 **Id** 相同

#### 回傳資料格式如下:

回應標頭：

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

回應 body：

```json
{
  "@odata.id": "/redfish/v1/SessionService/Sessions/a1b2c3d4",
  "@odata.type": "#Session.v1_7_2.Session",
  "Id": "a1b2c3d4",
  "Name": "admin",
  "UserName": "admin",
  "Description": "User Session"
}
```

#### 欄位說明如下:

* **@odata.id**: Session 資源 URI
* **@odata.type**: 資源型別，固定 `#Session.v1_7_2.Session`
* **Id**: Session 識別碼，與 URI 最後一段相同
* **Name**: 通常為登入帳號名稱
* **UserName**: 登入帳號
* **Description**: 工作階段說明

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常，回傳上述 Session 資源 body
401   | 未認證（未帶 `X-Auth-Token` 或 Basic Auth）
403   | 權限不足
404   | Session 不存在或已過期

### DELETE https://<host>/redfish/v1/SessionService/Sessions/{id}

登出並終止 Session。請求須帶對應的 `X-Auth-Token`。無請求 body。

#### 欄位說明如下:

* **id**（路徑參數）: 要終止的 Session 識別碼

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 已終止
404   | Session 不存在

curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","TokenLifetimeSeconds":300,"Language":"zh-TW"}'

curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","ClientIp":"203.0.113.50","TokenLifetimeSeconds":300}'

curl -sk -u admin:'<password>' -X POST \
  -H 'Content-Type: application/json' \
  -d '{"UserName":"viewer1","ReturnPath":"/eng/Peripheral","ClientIp":"203.0.113.50","TokenLifetimeSeconds":300}'
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 成功
400   | JSON 錯誤、參數超出範圍，或 `ReturnPath` 格式／白名單不符
401   | 未認證
403   | 權限不足、帳號停用，或 Operator 試圖為他人簽發
404   | 指定 UserName 不存在

### GET https://<host>/redfish/v1/AccountService

查詢帳號服務資訊。本地帳號集合為唯讀探索連結；LDAP／RADIUS／TACACS+ 設定內嵌於本資源。

```json
{
  "@odata.id": "/redfish/v1/AccountService",
  "@odata.type": "#AccountService.v1_15_0.AccountService",
  "Id": "AccountService",
  "Name": "Account Service",
  "ServiceEnabled": true,
  "MinPasswordLength": 8,
  "MaxPasswordLength": 16,
  "Accounts": {
    "@odata.id": "/redfish/v1/AccountService/Accounts"
  },
  "Roles": {
    "@odata.id": "/redfish/v1/AccountService/Roles"
  },
  "OutboundConnections": {
    "@odata.id": "/redfish/v1/AccountService/OutboundConnections"
  },
  "LDAP": {
    "ServiceEnabled": false,
    "ServiceAddresses": [],
    "Authentication": {
      "AuthenticationType": "UsernameAndPassword",
      "Username": null,
      "Password": null
    },
    "LDAPService": {
      "SearchSettings": {
        "BaseDistinguishedNames": [],
        "UsernameAttribute": "uid"
      }
    },
    "Oem": {
      "Pelx": {
        "FallbackLocal": true
      }
    }
  },
  "Oem": {
    "Pelx": {
      "PasswordPolicy": {
        "RequireUppercase": true,
        "RequireLowercase": true,
        "RequireNumbers": true,
        "RequireSpecialChars": true
      },
      "Radius": {
        "ServiceEnabled": false,
        "ServiceAddress": "",
        "ServicePort": 1812,
        "TimeoutSec": 5,
        "MaxRetries": 3,
        "FallbackLocal": true,
        "Secret": null
      },
      "Tacacs": {
        "ServiceEnabled": false,
        "ServiceAddress": "",
        "ServicePort": 49,
        "TimeoutSec": 5,
        "FallbackLocal": true,
        "Secret": null
      }
    }
  },
  "Actions": {
    "#PelxAccountService.TestLDAPConnection": {
      "target": "/redfish/v1/AccountService/Actions/PelxAccountService.TestLDAPConnection"
    },
    "#PelxAccountService.TestRADIUSConnection": {
      "target": "/redfish/v1/AccountService/Actions/PelxAccountService.TestRADIUSConnection"
    },
    "#PelxAccountService.TestTACACSConnection": {
      "target": "/redfish/v1/AccountService/Actions/PelxAccountService.TestTACACSConnection"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: AccountService 資源 URI，固定 `/redfish/v1/AccountService`
* **@odata.type**: 資源型別，固定 `#AccountService.v1_15_0.AccountService`
* **Id**: 資源識別碼，固定 `AccountService`
* **Name**: 顯示名稱，固定 `Account Service`
* **ServiceEnabled**: 帳號服務是否啟用，`true` 表示可透過 Redfish 查詢帳號資訊
* **MinPasswordLength**／**MaxPasswordLength**: 密碼長度上下限（DMTF 標準欄位）
* **Oem.Pelx.PasswordPolicy**: 複雜度要求（大寫、小寫、數字、特殊字元）
* **Accounts**: 帳號集合連結物件
  * **@odata.id**: 帳號列表 URI（`/redfish/v1/AccountService/Accounts`）；支援 `GET`／`POST`；單筆支援 `GET`／`PATCH`／`DELETE`
* **Roles**: 角色定義集合連結物件
  * **@odata.id**: 角色列表 URI（`/redfish/v1/AccountService/Roles`）
* **OutboundConnections**: 出站 WebSocket 連線集合（DMTF 2023.2+；見 outbound connection）
  * **@odata.id**: 出站連線列表 URI（`/redfish/v1/AccountService/OutboundConnections`）；`GET`／`POST`；單筆支援 `GET`／`PATCH`／`DELETE`
* **LDAP**: 標準 LDAP 外部帳號提供者（DMTF `LDAPService`）；`PATCH` 本資源之 `LDAP` 區塊更新
* **Oem.Pelx.Radius**: RADIUS 伺服器設定（DMTF 無單一標準屬性，以 OEM 表示）
* **Oem.Pelx.Tacacs**: TACACS+ 伺服器設定（Pelx OEM）
* **Actions**: LDAP／RADIUS／TACACS+ 連線測試 Action

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/AccountService/Accounts

列出帳號（不回傳密碼）。

```json
{
  "@odata.id": "/redfish/v1/AccountService/Accounts",
  "@odata.type": "#ManagerAccountCollection.ManagerAccountCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/AccountService/Accounts/1"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 帳號集合資源 URI，固定 `/redfish/v1/AccountService/Accounts`
* **@odata.type**: 資源型別，固定 `#ManagerAccountCollection.ManagerAccountCollection`（**Mandatory**）
* **Members**: 帳號資源連結陣列，元素為 `{ "@odata.id": "..." }`，不含密碼
  * **@odata.id**: 單一帳號資源 URI，如 `/redfish/v1/AccountService/Accounts/1`
* **Members@odata.count**: `Members` 陣列筆數，即帳號數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足

### GET https://<host>/redfish/v1/AccountService/Accounts/{id}

查詢單一帳號詳細資訊（不回傳密碼）。

`{id}` 為帳號資源識別碼，對應上一節 `Members` 中 `@odata.id` 的最後一段路徑，例如 `/redfish/v1/AccountService/Accounts/1` 的 `{id}` 為 `1`。`{id}` 與 `UserName` 不一定相同；登入名稱請讀回應中的 `UserName` 欄位。

#### 回傳資料格式如下:

```json
{
  "@odata.id": "/redfish/v1/AccountService/Accounts/1",
  "@odata.type": "#ManagerAccount.v1_12_0.ManagerAccount",
  "Id": "1",
  "UserName": "admin",
  "RoleId": "Administrator",
  "Enabled": true,
  "Locked": false,
  "@Redfish.WriteableProperties": ["RoleId", "Password", "Enabled", "Locked"]
}
```

#### 欄位說明如下:

* **@odata.id**: 帳號資源 URI，如 `/redfish/v1/AccountService/Accounts/1`
* **@odata.type**: 資源型別，固定 `#ManagerAccount.v1_12_0.ManagerAccount`
* **Id**: 帳號資源識別碼，與 URI 路徑參數 `{id}` 相同
* **UserName**: 登入帳號名稱，對應 auth 使用者名稱
* **RoleId**: Redfish 角色識別碼，如 `Administrator`、`Operator`、`ReadOnly`；由 auth **role** 映射，見本文「認證」章節
* **Enabled**: 帳號是否啟用，`false` 時無法登入
* **Locked**: 帳號是否鎖定（如多次登入失敗），`true` 時無法登入直至解鎖
* **@Redfish.WriteableProperties**: 可 `PATCH` 欄位陣列（須 **Administrator**）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 查詢成功
401   | 未登入或 Token 無效
403   | 權限不足
404   | `{id}` 不存在或帳號已刪除

`{id}` 不存在時不會回傳其他帳號內容，請重新 `GET /AccountService/Accounts` 從 `Members` 取得有效 id。

404 回應範例：

```json
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "Message": "The resource at the URI /redfish/v1/AccountService/Accounts/999 was not found.",
        "MessageId": "Base.1.18.ResourceNotFound",
        "Severity": "Critical",
        "Resolution": "Place a valid resource URI in the request."
      }
    ]
  }
}
```

#### 欄位說明如下:

* **error**: 錯誤物件
  * **@Message.ExtendedInfo**: 延伸錯誤資訊陣列
    * **Message**: 詳細說明
    * **MessageId**: 訊息識別碼，如 `Base.1.18.ResourceNotFound`
    * **Severity**: 嚴重程度，如 `Critical`
    * **Resolution**: 建議處理方式

### POST https://<host>/redfish/v1/AccountService/Accounts

建立本地帳號（OCP Baseline **Mandatory**）。須 **Operator 以上**；依 [帳號 CRUD 授權矩陣](#帳號-crud-授權矩陣) 檢查 `RoleId`。閘道轉呼叫 auth `POST /users`。

請求 body 範例：

```json
{
  "UserName": "dcim-read",
  "Password": "ChangeMe-Strong1",
  "RoleId": "ReadOnly",
  "Enabled": true
}
```

#### 欄位說明如下:

* **UserName**: 登入帳號名稱（必填）
* **Password**: 登入密碼（必填）
* **RoleId**: Redfish 角色，須為 `Administrator`、`Operator` 或 `ReadOnly`（**不可** `app`）
* **Enabled**: 是否啟用，預設 `true`；`false` 

#### 欄位對照（Redfish → auth）

| Redfish | auth `POST /users` |
|---------|-------------------|
| `UserName` | `username` |
| `Password` | `password` |
| `RoleId` | `role`（見下表） |
| `Enabled: false` | `deactivate: true` |

| Redfish `RoleId` | auth `role` |
|------------------|-------------|
| `Administrator` | `admin` |
| `Operator` | `manager` |
| `ReadOnly` | `viewer` |

> Redfish 建立帳號**不**接受 `outlets`、`notifications` 等 Web 專用欄位；插座權限請用 Web 或 auth API 另行設定。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功；`Location` 指向 `/redfish/v1/AccountService/Accounts/{id}`
400   | 請求格式錯誤（缺欄位、RoleId 無效）
401   | 未認證
403   | 權限不足（ReadOnly 不可建立；Operator 不可建立 `Administrator`；Operator 僅能建立 `Operator`／`ReadOnly`）
409   | `UserName` 已存在

### PATCH https://<host>/redfish/v1/AccountService/Accounts/{id}

修改帳號（OCP Baseline **Mandatory**）。須 **Operator 以上**；依 [帳號 CRUD 授權矩陣](#帳號-crud-授權矩陣) 檢查目標帳號之 `RoleId` 與變更後 `RoleId`。閘道轉呼叫 auth `PATCH /users/{username}`（`username` 由資源 `{id}` 查得）。

請求 body 範例（僅送要變更的欄位）：

```json
{
  "RoleId": "Operator",
  "Password": "NewPassword-Strong1",
  "Enabled": true
}
```

#### 可寫欄位

| 欄位 | 說明 |
|------|------|
| **Password** | 新密碼 |
| **RoleId** | 變更角色 |
| **Enabled** | `false` 停用帳號 |
| **Locked** | 解鎖／鎖定（若 auth 支援） |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 修改成功
400   | 請求格式錯誤
401   | 未認證
403   | 權限不足（ReadOnly 不可修改；Operator 不可修改 `Administrator` 或將 `RoleId` 改為 `Administrator`）
404   | `{id}` 不存在

### DELETE https://<host>/redfish/v1/AccountService/Accounts/{id}

刪除帳號（OCP Baseline **Mandatory**）。須 **Operator 以上**；依 [帳號 CRUD 授權矩陣](#帳號-crud-授權矩陣) 檢查目標帳號。閘道轉呼叫 auth `DELETE /users/{username}`。

無請求 body。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 刪除成功
401   | 未認證
403   | 權限不足（ReadOnly 不可刪除；Operator 不可刪除 `Administrator`），或不可刪除最後一個 `Administrator`
404   | `{id}` 不存在

### GET https://<host>/redfish/v1/AccountService/Roles

角色集合（OCP Service Baseline）。

```json
{
  "@odata.id": "/redfish/v1/AccountService/Roles",
  "@odata.type": "#RoleCollection.RoleCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/AccountService/Roles/Administrator" },
    { "@odata.id": "/redfish/v1/AccountService/Roles/Operator" },
    { "@odata.id": "/redfish/v1/AccountService/Roles/ReadOnly" }
  ],
  "Members@odata.count": 3
}
```

#### 欄位說明如下:

* **@odata.id**: 角色集合 URI，固定 `/redfish/v1/AccountService/Roles`
* **@odata.type**: 資源型別，固定 `#RoleCollection.RoleCollection`（**Mandatory**）
* **Members**: 角色資源連結陣列
* **Members@odata.count**: 角色數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足

### GET https://<host>/redfish/v1/AccountService/Roles/{RoleId}

查詢單一角色定義（OCP Baseline **Mandatory**）。**RoleId** 為 `Administrator`、`Operator` 或 `ReadOnly`。預設角色 `IsPredefined: true`，`AssignedPrivileges` 不可 `PATCH` 修改。

**Administrator** 範例：

```json
{
  "@odata.id": "/redfish/v1/AccountService/Roles/Administrator",
  "@odata.type": "#Role.v1_3_0.Role",
  "Id": "Administrator",
  "Name": "Administrator",
  "IsPredefined": true,
  "AssignedPrivileges": ["Login", "ConfigureManager", "ConfigureUsers", "ConfigureSelf", "ConfigureComponents"],
  "OemPrivileges": ["ConfigureEngineering"]
}
```

**ReadOnly** 範例（OCP 基礎角色）：

```json
{
  "@odata.id": "/redfish/v1/AccountService/Roles/ReadOnly",
  "@odata.type": "#Role.v1_3_0.Role",
  "Id": "ReadOnly",
  "Name": "Read Only",
  "IsPredefined": true,
  "AssignedPrivileges": ["Login", "ConfigureSelf"],
  "OemPrivileges": []
}
```

| RoleId | 典型權限 |
|--------|----------|
| **Administrator** | 讀寫全部資源、工程模式、帳號 CRUD（含系統管理員）、Session 管理 |
| **Operator** | 讀取全部、**控制 Action** 與一般選單寫入；帳號 CRUD 僅限 Operator／ReadOnly |
| **ReadOnly** | **可登入**、**可改自己密碼**、**可讀監測**；**嚴禁**配置修改與控制 |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | RoleId 不存在

### PATCH https://<host>/redfish/v1/AccountService

修改帳號服務設定（密碼政策、LDAP、RADIUS、TACACS+）。須 **Administrator**（工程模式）。僅送要變更的區塊。

#### 密碼強度政策範例

```json
{
  "MinPasswordLength": 10,
  "MaxPasswordLength": 32,
  "Oem": {
    "Pelx": {
      "PasswordPolicy": {
        "RequireUppercase": true,
        "RequireLowercase": true,
        "RequireNumbers": true,
        "RequireSpecialChars": true
      }
    }
  }
}
```

#### LDAP 範例

```json
{
  "LDAP": {
    "ServiceEnabled": true,
    "ServiceAddresses": ["ldap://ldap.example.com:389"],
    "Authentication": {
      "AuthenticationType": "UsernameAndPassword",
      "Username": "cn=admin,dc=example,dc=com",
      "Password": "bind-secret"
    },
    "LDAPService": {
      "SearchSettings": {
        "BaseDistinguishedNames": ["dc=example,dc=com"],
        "UsernameAttribute": "uid"
      }
    },
    "Oem": {
      "Pelx": {
        "FallbackLocal": true
      }
    }
  }
}
```

#### RADIUS 範例

```json
{
  "Oem": {
    "Pelx": {
      "Radius": {
        "ServiceEnabled": true,
        "ServiceAddress": "radius.example.com",
        "ServicePort": 1812,
        "Secret": "radius_secret",
        "TimeoutSec": 5,
        "MaxRetries": 3,
        "FallbackLocal": true
      }
    }
  }
}
```

#### TACACS+ 範例

```json
{
  "Oem": {
    "Pelx": {
      "Tacacs": {
        "ServiceEnabled": true,
        "ServiceAddress": "tacacs.example.com",
        "ServicePort": 49,
        "Secret": "tacacs_secret",
        "TimeoutSec": 5,
        "FallbackLocal": true
      }
    }
  }
}
```

#### 欄位對照（Redfish → auth）

**LDAP** → `PATCH /config/ldap`：

| Redfish `LDAP` | auth |
|----------------|------|
| `ServiceEnabled` | `enabled` |
| `ServiceAddresses[0]` | `host`、`port`、`sslEnabled`（`ldaps://` → `sslEnabled: true`） |
| `Authentication.Username` | `bindDN` |
| `Authentication.Password` | `password` |
| `LDAPService.SearchSettings.BaseDistinguishedNames[0]` | `base` |
| `LDAPService.SearchSettings.UsernameAttribute` | `uid` |
| `Oem.Pelx.FallbackLocal` | `fallbackLocal` |

**RADIUS** → `PATCH /config/radius`：

| Redfish `Oem.Pelx.Radius` | auth |
|------------------------------|------|
| `ServiceEnabled` | `enabled` |
| `ServiceAddress` | `host` |
| `ServicePort` | `port` |
| `Secret` | `secret` |
| `TimeoutSec` | `timeout` |
| `MaxRetries` | `maxRetries` |
| `FallbackLocal` | `fallbackLocal` |

**TACACS+** → `PATCH /config/tacacs`：

| Redfish `Oem.Pelx.Tacacs` | auth |
|------------------------------|------|
| `ServiceEnabled` | `enabled` |
| `ServiceAddress` | `host` |
| `ServicePort` | `port` |
| `Secret` | `secret` |
| `TimeoutSec` | `timeout` |
| `FallbackLocal` | `fallbackLocal` |

**密碼強度** → `PATCH /config/password-policy`：

| Redfish | auth |
|---------|------|
| `MinPasswordLength` | `minLength` |
| `MaxPasswordLength` | `maxLength` |
| `Oem.Pelx.PasswordPolicy.RequireUppercase` | `requireUppercase` |
| `Oem.Pelx.PasswordPolicy.RequireLowercase` | `requireLowercase` |
| `Oem.Pelx.PasswordPolicy.RequireNumbers` | `requireNumbers` |
| `Oem.Pelx.PasswordPolicy.RequireSpecialChars` | `requireSpecialChars` |

GET 回應**不回傳** `Authentication.Password`、`Radius.Secret`、`Tacacs.Secret`（`null` 或省略）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 修改成功
400   | 請求格式錯誤
401   | 未認證
403   | 須 Administrator（工程模式）
503   | 無法連線 auth

### POST https://<host>/redfish/v1/AccountService/Actions/PelxAccountService.TestLDAPConnection

測試 LDAP 連線。須 **Administrator**。。

請求 body 範例（可省略已儲存於 `LDAP` 的欄位，改送測試帳密）：

```json
{
  "ServiceAddresses": ["ldap://ldap.example.com:389"],
  "Authentication": {
    "Username": "cn=admin,dc=example,dc=com",
    "Password": "bind-secret"
  },
  "LDAPService": {
    "SearchSettings": {
      "BaseDistinguishedNames": ["dc=example,dc=com"],
      "UsernameAttribute": "uid"
    }
  },
  "TestUserName": "testuser",
  "TestPassword": "testpassword"
}
```

| Redfish | auth `/test/ldap` |
|---------|---------------------|
| `ServiceAddresses` → host/port/ssl | `host`、`port`、`sslEnabled` |
| `Authentication.Username` | `bindDN` |
| `Authentication.Password` | `password` |
| `LDAPService.SearchSettings.BaseDistinguishedNames[0]` | `base` |
| `LDAPService.SearchSettings.UsernameAttribute` | `uid` |
| `TestUserName` | `testUsername` |
| `TestPassword` | `testPassword` |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 測試成功
400   | 請求格式錯誤
401   | LDAP 認證失敗
403   | 須 Administrator（工程模式）

### POST https://<host>/redfish/v1/AccountService/Actions/PelxAccountService.TestRADIUSConnection

測試 RADIUS 連線。須 **Administrator**。。

請求 body 範例：

```json
{
  "ServiceAddress": "radius.example.com",
  "ServicePort": 1812,
  "Secret": "radius_secret",
  "TimeoutSec": 5,
  "MaxRetries": 3,
  "TestUserName": "testuser",
  "TestPassword": "testpassword"
}
```

| Redfish | auth `/test/radius` |
|---------|---------------------|
| `ServiceAddress` | `host` |
| `ServicePort` | `port` |
| `Secret` | `secret` |
| `TimeoutSec` | `timeout` |
| `MaxRetries` | `maxRetries` |
| `TestUserName` | `testUsername` |
| `TestPassword` | `testPassword` |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 測試成功
400   | 請求格式錯誤
401   | RADIUS 認證失敗
403   | 須 Administrator（工程模式）

### POST https://<host>/redfish/v1/AccountService/Actions/PelxAccountService.TestTACACSConnection

測試 TACACS+ 連線。須 **Administrator**。。

請求 body 範例：

```json
{
  "ServiceAddress": "tacacs.example.com",
  "ServicePort": 49,
  "Secret": "tacacs_secret",
  "TimeoutSec": 5,
  "TestUserName": "testuser",
  "TestPassword": "testpassword"
}
```

| Redfish | auth `/test/tacacs` |
|---------|---------------------|
| `ServiceAddress` | `host` |
| `ServicePort` | `port` |
| `Secret` | `secret` |
| `TimeoutSec` | `timeout` |
| `TestUserName` | `testUsername` |
| `TestPassword` | `testPassword` |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 測試成功
400   | 請求格式錯誤
401   | TACACS+ 認證失敗
403   | 須 Administrator（工程模式）

**實作狀態**：LDAP／RADIUS／TACACS+ 為規格定義。

### HTTPS 憑證（實際作業方式）

設備對外 HTTPS（Web 管理介面、Redfish over HTTPS）支援兩種模式：

|------|--------------------------------------|-------------|
| **uacme**（預設） | `uacme` | `CertificateService` 與 `PelxCertificateService.TestUacme` |
| **manual** | `manual` | `GET/PATCH /tls`、`POST /tls/csr`、`POST /tls/certificates/replace` |

### GET https://<host>/redfish/v1/CertificateService

憑證服務（OCP Service Baseline **Mandatory**）。

```json
{
  "@odata.id": "/redfish/v1/CertificateService",
  "@odata.type": "#CertificateService.v1_0_1.CertificateService",
  "Id": "CertificateService",
  "Name": "Certificate Service",
  "ServiceEnabled": true,
  "CertificateLocations": {
    "@odata.id": "/redfish/v1/CertificateService/CertificateLocations"
  },
  "Oem": {
    "Pelx": {
      "CertificateMode": "uacme",
      "Uacme": {
        "ServiceEnabled": true,
        "Domain": "pdu.example.com",
        "ContactEmail": "admin@example.com"
      }
    }
  },
  "Actions": {
    "#CertificateService.GenerateCSR": {
      "target": "/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR"
    },
    "#CertificateService.ReplaceCertificate": {
      "target": "/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate"
    },
    "#PelxCertificateService.TestUacme": {
      "target": "/redfish/v1/CertificateService/Actions/PelxCertificateService.TestUacme"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: CertificateService 資源 URI，固定 `/redfish/v1/CertificateService`
* **ServiceEnabled**: 服務是否啟用（Baseline **Mandatory**）
* **CertificateLocations**: 憑證存放位置集合（Baseline **Mandatory**）
* **Oem.Pelx.CertificateMode**: `manual` 或 `uacme`（。須 **Administrator**。 與／或 `PATCH /uacme`。

切換為 uacme（預設生產模式）：

```json
{
  "Oem": {
    "Pelx": {
      "CertificateMode": "uacme",
      "Uacme": {
        "ServiceEnabled": true,
        "Domain": "pdu.example.com",
        "ContactEmail": "admin@example.com"
      }
    }
  }
}
```

切換為手動憑證（企業 CA／CSR）：

```json
{
  "Oem": {
    "Pelx": {
      "CertificateMode": "manual",
      "Uacme": {
        "ServiceEnabled": false
      }
    }
  }
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 修改成功
400   | 請求格式錯誤
401   | 未認證
403   | 須 Administrator（工程模式）
409   | 切換條件不符（例如憑證更新中）
502   | uacme／CA 連線失敗
503   | 服務暫不可用

### POST https://<host>/redfish/v1/CertificateService/Actions/PelxCertificateService.TestUacme

測試 uacme 申請條件（不實際簽發）。須 **Administrator**。。

請求 body 範例：

```json
{
  "Domain": "pdu.example.com",
  "ContactEmail": "admin@example.com"
}
```

|---------|----------------------|
| `Domain` | `domain` |
| `ContactEmail` | `mail` |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 測試成功
400   | 請求格式錯誤
401   | 未認證
403   | 須 Administrator（工程模式）
502   | CA 連線或驗證失敗
503   | 服務暫不可用

### GET https://<host>/redfish/v1/CertificateService/CertificateLocations

列出可管理的憑證位置（OCP Service Baseline **Mandatory**）。

```json
{
  "@odata.id": "/redfish/v1/CertificateService/CertificateLocations",
  "@odata.type": "#CertificateLocations.v1_0_2.CertificateLocations",
  "Id": "CertificateLocations",
  "Links": {
    "Certificates": [
      { "@odata.id": "/redfish/v1/CertificateService/Certificates/https-server" }
    ]
  }
}
```

#### 欄位說明如下:

* **@odata.id**: CertificateLocations 資源 URI，固定 `/redfish/v1/CertificateService/CertificateLocations`
* **@odata.type**: 資源型別，固定 `#CertificateLocations.v1_0_2.CertificateLocations`
* **Id**: 資源識別碼，固定 `CertificateLocations`
* **Links.Certificates**: 憑證資源連結陣列；有 HTTPS 憑證時指向 `.../CertificateService/Certificates/https-server`（含 `certMode=uacme` 時使用自動憑證）；無憑證時為空陣列 `[]`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
503   | 服務暫不可用

### GET https://<host>/redfish/v1/CertificateService/Certificates

憑證集合。。

```json
{
  "@odata.id": "/redfish/v1/CertificateService/Certificates",
  "@odata.type": "#CertificateCollection.CertificateCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/CertificateService/Certificates/https-server" }
  ],
  "Members@odata.count": 1
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
503   | 服務暫不可用

### GET https://<host>/redfish/v1/CertificateService/Certificates/{id}

查詢指定憑證 slot 的 PEM 公開資訊（不含私鑰）。**id** 固定為 `https-server`（別名 `1`）。

```json
{
  "@odata.id": "/redfish/v1/CertificateService/Certificates/https-server",
  "@odata.type": "#Certificate.v1_8_0.Certificate",
  "Id": "https-server",
  "Name": "HTTPS Server Certificate",
  "CertificateType": "PEM",
  "CertificateString": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
  "Issuer": { "CommonName": "Example CA" },
  "Subject": { "CommonName": "CN=pdu.example.com" },
  "ValidNotBefore": "2026-06-01T00:00:00Z",
  "ValidNotAfter": "2027-06-01T00:00:00Z"
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | slot 不存在
503   | 服務暫不可用

### POST https://<host>/redfish/v1/CertificateService/Actions/CertificateService.GenerateCSR

產生 CSR（DMTF Redfish 標準 Action）。（須 `certMode=manual`）。

請求 body 範例：

```json
{
  "Country": "TW",
  "State": "Taipei",
  "City": "Taipei",
  "Organization": "Example Corp",
  "OrganizationalUnit": "IT",
  "CommonName": "pdu.example.com",
  "Email": "admin@example.com",
  "AlternativeNames": ["pdu.example.com", "192.168.1.100"],
  "KeyBitLength": 2048
}
```

成功回應：

```json
{
  "CSRString": "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----"
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 成功
401   | 未認證
403   | 權限不足
409   | `certMode=uacme`，須先切換為 `manual`
503   | 服務暫不可用

### POST https://<host>/redfish/v1/CertificateService/Actions/CertificateService.ReplaceCertificate

更換憑證。。

請求 body 範例：

```json
{
  "CertificateUri": "/redfish/v1/CertificateService/Certificates/https-server",
  "CertificateType": "PEM",
  "CertificateString": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}
```

亦可附 `CertificateChain` 陣列（中繼憑證 PEM）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 成功
401   | 未認證
403   | 權限不足
409   | `certMode=uacme`，或憑證與私鑰不匹配
503   | 服務暫不可用

---

# 探索與識別

Redfish Service Root，作為所有資源的入口。

```json
{
  "@odata.id": "/redfish/v1",
  "@odata.type": "#ServiceRoot.v1_16_0.ServiceRoot",
  "Id": "RootService",
  "Name": "Root Service",
  "RedfishVersion": "1.16.0",
  "UUID": "00000000-0000-0000-0000-000000000001",
  "Vendor": "Pelx",
  "SessionService": {
    "@odata.id": "/redfish/v1/SessionService"
  },
  "AccountService": {
    "@odata.id": "/redfish/v1/AccountService"
  },
  "CertificateService": {
    "@odata.id": "/redfish/v1/CertificateService"
  },
  "Chassis": {
    "@odata.id": "/redfish/v1/Chassis"
  },
  "Managers": {
    "@odata.id": "/redfish/v1/Managers"
  },
  "PowerEquipment": {
    "@odata.id": "/redfish/v1/PowerEquipment"
  },
  "EventService": {
    "@odata.id": "/redfish/v1/EventService"
  },
  "UpdateService": {
    "@odata.id": "/redfish/v1/UpdateService"
  },
  "TaskService": {
    "@odata.id": "/redfish/v1/TaskService"
  },
  "Product": {
    "Vendor": "Pelx",
    "Name": "Rack PDU"
  },
  "ProtocolFeaturesSupported": {
    "ExpandQuery": {
      "ExpandAll": true,
      "Levels": true
    },
    "FilterQuery": true,
    "OnlyMemberQuery": true
  },
  "Links": {
    "Sessions": {
      "@odata.id": "/redfish/v1/SessionService/Sessions"
    }
  },
  "Oem": {
    "Pelx": {
      "Interfaces": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces"
      },
      "PeripheralTree": {
        "@odata.id": "/redfish/v1/Oem/Pelx/PeripheralTree"
      },
      "TelemetryService": {
        "@odata.id": "/redfish/v1/TelemetryService"
      },
      "Mqtt": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Mqtt"
      },
      "MqttEndpoint": "wss://<host>/redfish/v1/Oem/Pelx/Mqtt",
      "MqttAuth": "RedfishSession",
      "SerialBuses": {
        "@odata.id": "/redfish/v1/Oem/Pelx/SerialBuses"
      },
      "VNodes": {
        "@odata.id": "/redfish/v1/Oem/Pelx/VNodes"
      },
      "HmiScreens": {
        "@odata.id": "/redfish/v1/Oem/Pelx/HmiScreens"
      },
      "HmiImageLibraries": {
        "@odata.id": "/redfish/v1/Oem/Pelx/HmiImageLibraries"
      },
      "Automations": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Automations"
      }
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: Service Root 資源 URI，固定 `/redfish/v1`
* **@odata.type**: 資源型別，固定 `#ServiceRoot.v1_16_0.ServiceRoot`
* **Id**: 資源識別碼，固定 `RootService`
* **Name**: 顯示名稱，固定 `Root Service`
* **RedfishVersion**: Redfish 協議版本（OCP Baseline **Mandatory**）
* **UUID**: 設備唯一識別碼（OCP Baseline **Mandatory**）
* **Vendor**: 廠商名稱（OCP Baseline **Mandatory**），固定 `Pelx`
* **SessionService**: Session 服務連結（Baseline **Mandatory**）
* **AccountService**: 帳號服務連結（Baseline **Mandatory**）
* **CertificateService**: 憑證服務連結（Baseline **Mandatory**）
* **Chassis**: 機箱集合連結（Baseline）
* **Managers**: 管理控制器集合連結（Baseline **Mandatory**）
* **PowerEquipment**: 配電設備連結（**OCP Rack PDU Profile Mandatory**）
* **EventService**: 事件服務連結（Baseline **Mandatory**）
* **UpdateService**: 韌體更新服務連結（Baseline **Mandatory**）
* **TaskService**: 任務服務連結（Baseline **Mandatory**）
* **Product**: 產品識別物件（Baseline **Mandatory**）
  * **Vendor**: 廠商名稱
  * **Name**: 產品名稱
* **ProtocolFeaturesSupported**: 協定能力（Baseline **Mandatory**）
  * **ExpandQuery**: 支援 `$expand`（Baseline **Recommended**）；`ExpandAll`、`Levels` 為 true 時可用 `$expand=.`、`$expand=.($levels=N)` 一次展開子資源
  * **FilterQuery**: 支援 `$filter`（Baseline **Recommended**）
  * **OnlyMemberQuery**: 支援 `$only`（Baseline **Mandatory**）；如 `GET .../Outlets?$only` 僅回 `Members` 陣列
* **Links**: 服務層連結（Session 建立所需）
  * **Sessions**: Session 集合 URI（**Interop Validator Session 模式 Mandatory**）
* **Oem.Pelx**: Pelx 擴充連結（非 OCP 必填）
  * **Interfaces**: 介面列表
  * **PeripheralTree**: 週邊結構樹
  * **TelemetryService**: 歷史趨勢服務
  * **MqttEndpoint**: MQTT over WebSocket URL（Redfish 整合：`/redfish/v1/Oem/Pelx/Mqtt`；見 MQTT Discovery）
  * **MqttAuth**: MQTT 認證方式；Redfish 整合為 `RedfishSession`（X-Auth-Token 或 Basic Auth）
  * **SerialBuses**: RS485 參數（僅 `devinfo.rs485`；見 oem serial buses）
  * **VNodes**: VNode 組態（僅 `devinfo.vnode`；見 oem vnodes）
  * **HmiScreens**: 圖控畫面與樣版匯出／載入（僅 `devinfo.hmi`；見 oem hmi screens）
  * **HmiImageLibraries**: 圖控圖庫（僅 `devinfo.hmi`；見 oem hmi image libraries）
  * **Automations**: 自動化流程（僅 `devinfo.autoBuilder`；見 oem automations）

> `SerialBuses`／`VNodes`／`HmiScreens`／`HmiImageLibraries`／`Automations` 依能力旗標**條件出現**；未支援時省略該連結（客戶端勿假設永遠存在）。讀寫皆須 **Administrator**（工程模式）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常（**允許匿名**；Interop Validator 掃描 Service Root 時需要）
401   | 未認證（子資源；根路徑 `GET /redfish/v1` 匿名仍回 200）

#### `$expand` 與 `$only` 範例

Service Root 宣告 `ProtocolFeaturesSupported.ExpandQuery` 時，可用 OData 查詢**減少往返**（不支援時回 **501**）：

| 需求 | 範例 URL |
|------|----------|
| 所有插座完整 body | `GET .../RackPDUs/1/Outlets?$expand=.` |
| PDU 與下兩層子資源 | `GET .../RackPDUs/1?$expand=.($levels=2)` |
| 僅要集合成員連結 | `GET .../Outlets?$only` |

> Collection **未加** `$expand` 時，`Members` 僅含 `@odata.id` 連結，不含各插座 `Reading`／`PowerState`。詳見 「總覽與合規」章節 — 一次回應多筆資料。

### GET https://<host>/redfish/v1/Managers

```json
{
  "@odata.id": "/redfish/v1/Managers",
  "@odata.type": "#ManagerCollection.ManagerCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/Managers/1" }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: Manager 集合資源 URI，固定 `/redfish/v1/Managers`
* **@odata.type**: 資源型別，固定 `#ManagerCollection.ManagerCollection`（Baseline **Mandatory**）
* **Members**: Manager 資源連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一 Manager 資源 URI，如 `/redfish/v1/Managers/1`
* **Members@odata.count**: `Members` 陣列筆數；本機單台產品通常為 `1`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/Managers/1

管理控制器識別，韌體版本見 `FirmwareVersion`。路徑參數 `{id}` 為 Manager 資源識別碼；**本機單台 PDU 產品通常僅一筆，id 為 `1`**。整合方應先 `GET /Managers`，從 `Members` 的 `@odata.id` 取得有效 id，勿寫死。

```json
{
  "@odata.id": "/redfish/v1/Managers/1",
  "@odata.type": "#Manager.v1_19_0.Manager",
  "Id": "1",
  "Name": "Manager",
  "ManagerType": "BMC",
  "FirmwareVersion": "1.60.3",
  "UUID": "00000000-0000-0000-0000-000000000001",
  "DateTime": "2026-06-15T10:00:00+08:00",
  "DateTimeLocalOffset": "+08:00",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "EthernetInterfaces": {
    "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces"
  },
  "NetworkProtocol": {
    "@odata.id": "/redfish/v1/Managers/1/NetworkProtocol"
  },
  "Links": {
    "ManagerForChassis": [
      { "@odata.id": "/redfish/v1/Chassis/1" }
    ],
    "ManagerForPowerEquipment": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1" }
    ]
  },
  "LogServices": {
    "@odata.id": "/redfish/v1/Managers/1/LogServices"
  },
  "Oem": {
    "Pelx": {
      "Build": "202301161315",
      "CompanyOid": "26104",
      "Mqtt": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Mqtt"
      },
      "MqttEndpoint": "wss://<host>/redfish/v1/Oem/Pelx/Mqtt",
      "MqttAuth": "RedfishSession"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: Manager 資源 URI，固定 `/redfish/v1/Managers/1`
* **@odata.type**: 資源型別，固定 `#Manager.v1_19_0.Manager`
* **Id**: 資源識別碼，固定 `1`
* **Name**: 顯示名稱，固定 `Manager`
* **ManagerType**: 管理器類型（Baseline **Mandatory**），固定 `BMC`
* **FirmwareVersion**: 設備映像版本（Baseline **Mandatory**），對應 `Managers/1.FirmwareVersion`
* **UUID**: 管理器 UUID（Baseline **Mandatory**）
* **DateTime**: 管理器目前時間 ISO 8601（Baseline **Mandatory**）
* **DateTimeLocalOffset**: 時區偏移（Baseline **Mandatory**），如 `+08:00`
* **Status**: 狀態物件（Baseline **Mandatory**）
* **EthernetInterfaces**: 網路介面集合（Baseline **Mandatory**）
* **NetworkProtocol**: 通訊協定設定（Baseline **Supported**）
* **Links**: 關聯資源（Baseline **Mandatory**）
  * **ManagerForChassis**: 所管理機箱
  * **ManagerForPowerEquipment**: 所管理配電資源
* **LogServices**: 日誌服務（Baseline **Mandatory**）
* **Oem.Pelx**: Pelx 擴充（非 OCP 必填）
  * **Build**: 版號（建置時間），建置版號
  * **CompanyOid**: 公司 OID，公司 OID
  * **MqttEndpoint**: MQTT over WebSocket URL（見 MQTT Discovery）
  * **MqttAuth**: `RedfishSession`（X-Auth-Token 或 Basic Auth）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/Managers/1/EthernetInterfaces

```json
{
  "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces",
  "@odata.type": "#EthernetInterfaceCollection.EthernetInterfaceCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/1" }
  ],
  "Members@odata.count": 1
}
```

### GET https://<host>/redfish/v1/Managers/1/EthernetInterfaces/1

```json
{
  "@odata.id": "/redfish/v1/Managers/1/EthernetInterfaces/1",
  "@odata.type": "#EthernetInterface.v1_12_0.EthernetInterface",
  "Id": "1",
  "Name": "eth0",
  "MACAddress": "00:11:22:33:44:55",
  "InterfaceEnabled": true,
  "LinkStatus": "LinkUp",
  "SpeedMbps": 1000,
  "IPv4Addresses": [
    {
      "Address": "192.168.1.100",
      "SubnetMask": "255.255.255.0",
      "AddressOrigin": "Static",
      "Gateway": "192.168.1.1"
    }
  ],
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  }
}
```

### GET https://<host>/redfish/v1/Managers/1/NetworkProtocol

NTP、SNMP 設定見 網路協定。

```json
{
  "@odata.id": "/redfish/v1/Managers/1/NetworkProtocol",
  "@odata.type": "#ManagerNetworkProtocol.v1_9_1.ManagerNetworkProtocol",
  "Id": "NetworkProtocol",
  "HostName": "pdu-1",
  "HTTPS": {
    "ProtocolEnabled": true,
    "Port": 443
  },
  "HTTP": {
    "ProtocolEnabled": false,
    "Port": 80
  },
  "NTP": {
    "ProtocolEnabled": true,
    "NTPServers": ["time.stdtime.gov.tw"]
  },
  "SNMP": {
    "ProtocolEnabled": true,
    "Port": 161
  },
  "SSH": {
    "ProtocolEnabled": false,
    "Port": 22
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  }
}
```

### GET https://<host>/redfish/v1/Chassis

```json
{
  "@odata.id": "/redfish/v1/Chassis",
  "@odata.type": "#ChassisCollection.ChassisCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/Chassis/1" }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: Chassis 集合資源 URI，固定 `/redfish/v1/Chassis`
* **@odata.type**: 資源型別，固定 `#ChassisCollection.ChassisCollection`（Baseline）
* **Members**: Chassis 資源連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一 Chassis 資源 URI，如 `/redfish/v1/Chassis/1`
* **Members@odata.count**: `Members` 陣列筆數；本機單台產品通常為 `1`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/Chassis/1

機箱識別與健康彙整。路徑參數 `{chassisId}` 為 Chassis 資源識別碼；**本機單台 PDU 產品通常僅一筆，id 為 `1`**。整合方應先 `GET /Chassis`，從 `Members` 的 `@odata.id` 取得有效 id，勿寫死。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1",
  "@odata.type": "#Chassis.v1_22_0.Chassis",
  "@Redfish.WriteableProperties": [
    "AssetTag"
  ],
  "Id": "1",
  "Name": "Chassis",
  "ChassisType": "RackMount",
  "Manufacturer": "Pelx",
  "Model": "ZDL-2A-12Z",
  "PartNumber": "ZDL-2A-12Z",
  "SerialNumber": "001122AABBCC",
  "AssetTag": "",
  "UUID": "00000000-0000-0000-0000-000000000002",
  "PowerState": "On",
  "Location": {
    "@Redfish.WriteableProperties": [
      "Contacts"
    ],
    "Contacts": "",
    "Placement": {
      "@Redfish.WriteableProperties": [
        "Rack",
        "Row",
        "RackOffset",
        "RackOffsetUnits"
      ],
      "Rack": "Rack-01",
      "Row": "Row-A",
      "RackOffset": 42,
      "RackOffsetUnits": "EIA_310"
    }
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK",
    "HealthRollup": "OK"
  },
  "Links": {
    "ManagedBy": [
      { "@odata.id": "/redfish/v1/Managers/1" }
    ],
    "PowerDistribution": {
      "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1"
    }
  },
  "Sensors": {
    "@odata.id": "/redfish/v1/Chassis/1/Sensors"
  },
  "ThermalSubsystem": {
    "@odata.id": "/redfish/v1/Chassis/1/ThermalSubsystem"
  },
  "EnvironmentMetrics": {
    "@odata.id": "/redfish/v1/Chassis/1/EnvironmentMetrics"
  },
  "PowerSubsystem": {
    "@odata.id": "/redfish/v1/Chassis/1/PowerSubsystem"
  },
  "Power": {
    "@odata.id": "/redfish/v1/Chassis/1/Power"
  }
}
```

> **注意**：`Links.PowerDistribution` 為**單一物件** `{ "@odata.id": "..." }`，非陣列（DMTF Chassis schema 要求）。Chassis 不再連結已棄用之 `Thermal`；環境量測請用 `ThermalSubsystem`／`ThermalMetrics`（見 環境感測）。

#### 欄位說明如下:

* **@odata.id**: Chassis 資源 URI，固定 `/redfish/v1/Chassis/1`
* **@odata.type**: 資源型別，固定 `#Chassis.v1_22_0.Chassis`
* **Id**: 資源識別碼，固定 `1`
* **Name**: 顯示名稱，固定 `Chassis`
* **ChassisType**: 機箱類型（OCP **Mandatory**），如 `RackMount`
* **Manufacturer**: 製造商，製造商識別
* **Model**: 型號，設備型號
* **PartNumber**: 料號（OCP **Mandatory**）；`devinfo.partNumber` 為空時以 `Model` 填入
* **SerialNumber**: 序號；`devinfo.serialNumber` 為空時以 MAC（`ethaddr`，去冒號）填入
* **UUID**: 機箱 UUID（OCP **Mandatory**）
* **PowerState**: 整機電源狀態（OCP **Mandatory**），`On` 或 `Off`
* **Location**: 機架位置（OCP **Mandatory**）
  * **Placement.Rack**: 機架名稱（**Mandatory**，可寫入）
  * **Placement.Row**: 列／區域（Recommended）
  * **Placement.RackOffset**: U 位偏移（Recommended）
  * **Placement.RackOffsetUnits**: 偏移單位，如 `EIA_310`
* **Status**: 運作與健康狀態
  * **HealthRollup**: 整機健康彙整，依告警彙整
* **Links**: 關聯資源（OCP **Mandatory**）
  * **ManagedBy**: 管理此機箱的 Manager
  * **PowerDistribution**: 對應 Rack PDU 資源（**單一物件**，非陣列）
* **Sensors**: 機箱感測器集合（OCP **Mandatory**）；含電氣量測與 `TEMPRH` 溫度（`Temp1` 等）
* **ThermalSubsystem**: 環境熱管理子系統（OCP Baseline）；內含 `ThermalMetrics`
* **EnvironmentMetrics**: 機箱環境彙總（如 `PowerWatts`）；**不含** `TemperatureSummaryCelsius`
* **PowerSubsystem** / **Power**: 電源子系統與傳統 Power 資源（`Power` 為 deprecated，Validator 可能 WARN）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/Chassis/{chassisId}/Sensors

**OCP Profile Mandatory** 感測器集合 URI。成員與 `PowerEquipment/RackPDUs/{rackId}/Sensors` 相同，但 `@odata.id` 須在 `Chassis` 路徑下（Interop Validator 掃描此集合）。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/Sensors",
  "@odata.type": "#SensorCollection.SensorCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/CurrentA" },
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/PowerA" },
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/EnergyA" },
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/VoltageA" },
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/Outlet1Current" },
    { "@odata.id": "/redfish/v1/Chassis/1/Sensors/Temp1" }
  ],
  "Members@odata.count": 6
}
```

#### 欄位說明如下:

* **@odata.id**: 感測器集合 URI，固定 `/redfish/v1/Chassis/{chassisId}/Sensors`
* **Members**: 感測器連結；`{sensorId}` 命名規則見「電力與配電」章節 Sensor 定義
* **Members@odata.count**: 感測器數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/Chassis/{chassisId}/Sensors/{sensorId}

單一感測器（**OCP Profile 規定 URI**）。內容與 `PowerEquipment/.../Sensors/{sensorId}` 相同；`DataSourceUri` 須指向本 URI。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/Sensors/PowerA",
  "@odata.type": "#Sensor.v1_9_0.Sensor",
  "Id": "PowerA",
  "Name": "Infeed1 Power",
  "Reading": 2750.0,
  "ReadingUnits": "W",
  "ReadingType": "Power",
  "ElectricalContext": "Total",
  "ReadingTime": "2026-06-15T10:00:05+08:00",
  "SensingInterval": "PT5S",
  "PeakReading": 3100.0,
  "PeakReadingTime": "2026-06-14T18:22:00+08:00",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Thresholds": {
    "UpperCritical": { "Reading": 3500 },
    "UpperCaution": { "Reading": 3000 }
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "Interface": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CAI2105"
      },
      "RackPduSensorUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/PowerA"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 感測器 URI，固定 `/redfish/v1/Chassis/{chassisId}/Sensors/{sensorId}`
* **Reading**: 即時讀值（OCP **Mandatory**）
* **ReadingType**: 量測類型（OCP **Mandatory**）
* **ElectricalContext**: 電氣上下文（電氣量測 OCP **Mandatory**）
* **ReadingTime**: 讀值時間 ISO 8601（OCP **Mandatory**）
* **SensingInterval**: 取樣間隔，如 `PT5S`（OCP **Mandatory**）
* **PeakReading** / **PeakReadingTime**: 功率感測器至少一筆須提供峰值（OCP Supported）
* **Oem.Pelx.Interface**: 對應之 Pelx 介面資源連結（`Pelx.InterfaceLink`）
* **Oem.Pelx.RackPduSensorUri**: 對應之 DSP2056 配電路徑（選用，方便整合）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 感測器不存在

---

# 網路協定

`Managers/1/NetworkProtocol` 彙整管理介面通訊協定。OCP Service Baseline 要求 **NetworkProtocol** 資源存在；**NTP、SNMP、SSH** 為 **Mandatory**（須支援 `GET`／`PATCH` 之 `ProtocolEnabled`、`Port`；Vertiv PDU 文件亦有 PATCH NTP／SSH 範例）。SNMP v3、ICMP 等細節以 **Oem** 延伸。

> **權限**：`PATCH` 依欄位分級（例外）；詳見下方表格與 認證。

### GET https://<host>/redfish/v1/Managers/1/NetworkProtocol

```json
{
  "@odata.id": "/redfish/v1/Managers/1/NetworkProtocol",
    "@odata.type": "#ManagerNetworkProtocol.v1_10_1.ManagerNetworkProtocol",
  "Id": "NetworkProtocol",
  "HostName": "pdu-1",
  "HTTPS": {
    "ProtocolEnabled": true,
    "Port": 443
  },
  "HTTP": {
    "ProtocolEnabled": false,
    "Port": 80
  },
  "NTP": {
    "ProtocolEnabled": true,
    "NTPServers": ["time.stdtime.gov.tw"]
  },
  "SNMP": {
    "ProtocolEnabled": true,
    "Port": 161
  },
  "SSH": {
    "ProtocolEnabled": false,
    "Port": 22
  },
  "Proxy": {
    "Enabled": false,
    "ProxyServerURI": "http://proxy.corp.com:8080",
    "Username": "proxyuser",
    "Password": null,
    "PasswordSet": true,
    "ExcludeAddresses": ["dc.local"],
    "ProxyAutoConfigURI": null
  },
  "Oem": {
    "Pelx": {
      "ICMPEchoReply": {
        "ProtocolEnabled": true
      },
      "DateTime": {
        "TimeZone": "Asia/Taipei",
        "CustomNTPServer": false
      },
      "SNMPAgent": {
        "SNMPv1v2c": {
          "ProtocolEnabled": true,
          "ReadCommunity": "public",
          "WriteEnabled": true,
          "WriteCommunity": "private"
        },
        "SNMPv3": {
          "ProtocolEnabled": false,
          "UserName": "snmpuser",
          "AccessMode": "ReadWrite",
          "AuthProtocol": "MD5",
          "PrivProtocol": "DES"
        },
        "SystemName": "ZDL-2A-12Z",
        "Contact": "Administrator",
        "Location": "Office"
      }
    }
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  }
}
```

#### 欄位說明如下:

* **HostName**: 設備主機名稱
* **HTTPS**／**HTTP**: Web 與 Redfish 對外埠（Baseline）
  * **ProtocolEnabled**: 是否啟用
  * **Port**: 監聽埠
* **NTP**: 時間同步（OCP **Mandatory**）
  * **ProtocolEnabled**: 
  * **NTPServers**: NTP 伺服器位址陣列；`customTimeServer=true` 時為 `timeServer`，否則為預設池或空陣列
* **SNMP**: Agent 是否對外提供（OCP **Mandatory**）
  * **ProtocolEnabled**: `SNMPAgent.SNMPv1v2c` 或 `SNMPv3` 任一啟用即為 `true`
  * **Port**: UDP 161（固定）
* **SSH**: 遠端 Shell（OCP **Mandatory**；生產環境預設 **停用**）
  * **ProtocolEnabled**: ；`true` 表示允許 SSH 登入（搭配 sshcli）
  * **Port**: TCP 22（固定；Cascade 轉發見 串接.md）
* **Proxy**: 設備**出站** HTTP/HTTPS 代理（DMTF `ManagerNetworkProtocol` v1.8+；供 OutboundConnection 等連外使用）
  * **Enabled**: 是否啟用
  * **ProxyServerURI**: 代理伺服器 URI（如 `http://proxy.corp.com:8080`）
  * **Username**／**Password**: 代理認證；`Password` 僅寫入，GET 固定 `null`，以 **PasswordSet** 表示是否已設定
  * **ExcludeAddresses**: 不走代理的主機名或 IP 清單（`localhost`、`127.0.0.1` 永遠排除）
  * **ProxyAutoConfigURI**: PAC 檔 URI（**已儲存**；連線邏輯**尚未**依 PAC 自動選路）
* **Oem.Pelx.ICMPEchoReply**: ICMP Echo（ping）回應
  * **ProtocolEnabled**: `true` 允許 ping；`false` 
* **Oem.Pelx.DateTime**: 時區等延伸欄位
* **Oem.Pelx.SNMPAgent**: 完整 SNMP Agent 設定（；GET **不回傳** community／密碼字串，僅顯示是否已設定）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### PATCH https://<host>/redfish/v1/Managers/1/NetworkProtocol

修改通訊協定設定。依欄位分級（見 認證 RBAC）：

| 區塊 | 最低角色 |
|------|----------|
| `SNMP`、`Oem.Pelx.SNMPAgent`、`Proxy` | **Administrator**（工程模式／SNMP Agent／出站代理） |
| `NTP`、`SSH`、`Oem.Pelx.DateTime`、`Oem.Pelx.ICMPEchoReply` | **Operator** 以上 |
| `HTTPS`、`HTTP` | **Administrator** |

僅送要變更的區塊。若單次 `PATCH` 同時含 SNMP 與 NTP，須 **Administrator**。

NTP 範例：

```json
{
  "NTP": {
    "ProtocolEnabled": true,
    "NTPServers": ["ntp.example.com"]
  },
  "Oem": {
    "Pelx": {
      "DateTime": {
        "TimeZone": "Asia/Taipei",
        "CustomNTPServer": true
      }
    }
  }
}
```

SNMP v1/v2c 範例：

```json
{
  "SNMP": {
    "ProtocolEnabled": true
  },
  "Oem": {
    "Pelx": {
      "SNMPAgent": {
        "SNMPv1v2c": {
          "ProtocolEnabled": true,
          "ReadCommunity": "public",
          "WriteEnabled": false
        }
      }
    }
  }
}
```

SSH 與 ICMP 範例：

```json
{
  "SSH": {
    "ProtocolEnabled": true
  },
  "Oem": {
    "Pelx": {
      "ICMPEchoReply": {
        "ProtocolEnabled": false
      }
    }
  }
}
```

HTTP Proxy 範例（OutboundConnection 連外時經企業代理）：

```json
{
  "Proxy": {
    "Enabled": true,
    "ProxyServerURI": "http://proxy.corp.com:8080",
    "Username": "proxyuser",
    "Password": "secret",
    "ExcludeAddresses": ["nms.local"]
  }
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 修改成功
400   | 請求格式錯誤
401   | 未認證
403   | 權限不足（SNMP 區塊須 Administrator；其餘區塊須 Operator 以上）
503   | 服務暫不可用

---

# 電力與配電（PowerEquipment）

依 [OCP Rack PDU Profile](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/RackAndPower/OCPRackPDU.v1_0_0.json) 與 [DMTF DSP2056](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf)，Rack PDU 資源置於 `PowerEquipment/RackPDUs`；須含 `Metrics`、`Mains`、`Branches`（可為空集合）、`Outlets` 與 `Links`。具 ATS 功能之機型見 ATS 轉換開關（`TransferSwitches`）。

> **權限**：預設見 認證（控制 Action 與寫入至少 **Operator**）。

### GET https://<host>/redfish/v1/PowerEquipment

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment",
  "@odata.type": "#PowerEquipment.v1_2_3.PowerEquipment",
  "Id": "PowerEquipment",
  "RackPDUs": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs"
  },
  "TransferSwitches": {
    "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches"
  }
}
```

`TransferSwitches` 僅在 設備支援 ATS 時出現；無 ATS 機型省略此欄位。

#### 欄位說明如下:

* **@odata.id**: PowerEquipment 資源 URI，固定 `/redfish/v1/PowerEquipment`
* **@odata.type**: 資源型別，固定 `#PowerEquipment.v1_2_3.PowerEquipment`
* **Id**: 資源識別碼，固定 `PowerEquipment`
* **RackPDUs**: Rack PDU 集合連結物件
  * **@odata.id**: Rack PDU 列表 URI（`/redfish/v1/PowerEquipment/RackPDUs`）；`GET` 進一步取得 `RackPDUs/{id}`
* **TransferSwitches**: ATS 轉換開關集合連結物件（僅 設備支援 ATS 時）
  * **@odata.id**: ATS 列表 URI（`/redfish/v1/PowerEquipment/TransferSwitches`）；`GET` 進一步取得 `TransferSwitches/{id}`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs",
  "@odata.type": "#PowerDistributionCollection.PowerDistributionCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1" }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: Rack PDU 集合資源 URI，固定 `/redfish/v1/PowerEquipment/RackPDUs`
* **@odata.type**: 資源型別，固定 `#PowerDistributionCollection.PowerDistributionCollection`
* **Members**: Rack PDU 資源連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一 Rack PDU 資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1`
* **Members@odata.count**: `Members` 陣列筆數，Rack PDU 數量；本機單台產品通常為 `1`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}

Rack PDU 主資源，彙整進線、分支、插座連結。路徑參數 `{id}` 為 Rack PDU 資源識別碼；**本機單台 PDU 產品通常僅一筆，id 為 `1`**。整合方應先 `GET /PowerEquipment/RackPDUs`，從 `Members` 的 `@odata.id` 取得有效 id，勿寫死。

以下範例以 `{id}` = `1` 表示常見單機情境。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1",
  "@odata.type": "#PowerDistribution.v1_4_0.PowerDistribution",
  "@Redfish.WriteableProperties": [
    "AssetTag",
    "UserLabel",
    "LocationIndicatorActive"
  ],
  "Id": "1",
  "Name": "RackPDU",
  "EquipmentType": "RackPDU",
  "UserLabel": "PDU-1",
  "Manufacturer": "Pelx",
  "Model": "ZDL-2A-12Z",
  "PartNumber": "ZDL-2A-12Z",
  "SerialNumber": "001122AABBCC",
  "AssetTag": "",
  "LocationIndicatorActive": false,
  "FirmwareVersion": "1.60.3",
  "UUID": "00000000-0000-0000-0000-000000000003",
  "Location": {
    "@Redfish.WriteableProperties": [
      "Contacts"
    ],
    "Contacts": "",
    "Placement": {
      "@Redfish.WriteableProperties": [
        "Rack",
        "Row",
        "RackOffset",
        "RackOffsetUnits"
      ],
      "Rack": "Rack-01",
      "Row": "Row-A",
      "RackOffset": 42,
      "RackOffsetUnits": "EIA_310"
    }
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Metrics": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Metrics"
  },
  "Mains": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains"
  },
  "Branches": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches"
  },
  "Outlets": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets"
  },
  "Sensors": {
    "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors"
  },
  "Links": {
    "Chassis": [
      { "@odata.id": "/redfish/v1/Chassis/1" }
    ],
    "ManagedBy": [
      { "@odata.id": "/redfish/v1/Managers/1" }
    ]
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: Rack PDU 資源識別碼；單機產品通常為 `1`
* **@odata.id**: Rack PDU 資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1`
* **@odata.type**: 資源型別，固定 `#PowerDistribution.v1_4_0.PowerDistribution`
* **Id**: 資源識別碼，與路徑參數 `{id}` 相同
* **Name**: 顯示名稱，固定 `RackPDU`
* **EquipmentType**: 設備類型（OCP **Mandatory**），固定 `RackPDU`
* **UserLabel**: 使用者自訂標籤（OCP **Mandatory**，可寫入）
* **Manufacturer**: 製造商
* **Model**: 型號，設備型號
* **PartNumber**: 料號；`devinfo.partNumber` 為空時以 `Model` 填入
* **SerialNumber**: 序號；`devinfo.serialNumber` 為空時以 MAC（`ethaddr`，去冒號）填入
* **FirmwareVersion**: 韌體版本
* **UUID**: Rack PDU UUID（OCP **Mandatory**）
* **Location**: 機架位置（OCP **Mandatory**）；`Placement.Rack` 必填
* **Status**: 運作與健康狀態
* **Metrics**: 彙總量測資源（OCP **Mandatory**）
* **Mains**: 電源進線集合
* **Branches**: 分支電路集合（OCP **Mandatory**）；**一律提供**連結，無分支時 `Members` 為空
* **Outlets**: 插座集合
* **Sensors**: 感測器集合
* **Links**: 關聯資源（OCP **Mandatory**）
  * **Chassis**: 對應實體機箱
  * **ManagedBy**: 管理此 PDU 的 Manager

> **路徑說明**：`GET/PATCH .../RackPDUs/{id}` 與 `GET .../RackPDUs/{id}/Metrics`、`POST .../Metrics/Actions/...` 支援變數 `{id}`（無效 id 回 404）。其餘子資源（`Mains`、`Branches`、`Outlets`、`Sensors`、`OutletGroups`）的 **GET／PATCH／Action** 路由目前實作為 `.../RackPDUs/1/...`（單機產品 id 固定為 `1`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常（`{id}` 須存在於 `GET .../RackPDUs` 的 `Members` 中）
401   | 未認證
404   | `{id}` 不存在（如單機產品請求 `RackPDUs/2`、`RackPDUs/999`）；**不會** fallback 回 `1`，也不回傳部分資料

`{id}` 無效時回傳 Redfish 標準 `error` 物件（格式見文末「通用錯誤回應」），例如請求 `/redfish/v1/PowerEquipment/RackPDUs/999`：

```json
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "Message": "The resource at the URI /redfish/v1/PowerEquipment/RackPDUs/999 was not found.",
        "MessageId": "Base.1.18.ResourceNotFound",
        "Severity": "Critical",
        "Resolution": "Place a valid resource URI in the request."
      }
    ],
    "code": "Base.1.18.ResourceNotFound",
    "message": "The resource at the URI /redfish/v1/PowerEquipment/RackPDUs/999 was not found."
  }
}
```

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Metrics

Rack PDU 彙總量測（OCP **PowerDistributionMetrics Mandatory**）。`{rackId}` 為 Rack PDU 路徑參數。**一次回應**含整機 `PowerWatts`、`EnergykWh`、`PowerLoadPercent` 三項讀值（OCP 批量即時量測的標準做法；逐路插座仍須查 `Outlets` 或 `$expand`）。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Metrics",
  "@odata.type": "#PowerDistributionMetrics.v1_3_0.PowerDistributionMetrics",
  "Id": "Metrics",
  "Name": "Rack PDU Metrics",
  "PowerWatts": {
    "Reading": 2750.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerA"
  },
  "EnergykWh": {
    "Reading": 1523.6,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/EnergyA"
  },
  "PowerLoadPercent": {
    "Reading": 45.2
  },
  "Actions": {
    "#PowerDistributionMetrics.ResetMetrics": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/Metrics/Actions/PowerDistributionMetrics.ResetMetrics"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: Metrics 資源 URI，固定 `.../RackPDUs/{rackId}/Metrics`
* **@odata.type**: 資源型別，固定 `#PowerDistributionMetrics.v1_3_0.PowerDistributionMetrics`
* **PowerWatts**: 總有功功率（OCP **Mandatory**）
* **EnergykWh**: 總累計能耗（OCP **Mandatory**）
* **PowerLoadPercent**: 負載百分比（OCP **Mandatory**）
* **Actions.#PowerDistributionMetrics.ResetMetrics**: 重設能耗計數（OCP **Mandatory** Action）；見下方 `POST` 章節

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | Rack PDU 不存在

### POST https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Metrics/Actions/PowerDistributionMetrics.ResetMetrics

重設 Rack PDU 累計能耗。（整機能耗歸零，非逐路插座）。

請求 body 可為空物件 `{}`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 重設成功
401   | 未認證
403   | 權限不足
404   | Rack PDU 不存在
500   | 裝置不支援或內部錯誤

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Mains

進線電路集合（OCP **Mandatory**）。依 [OCP Rack PDU Profile](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/RackAndPower/OCPRackPDU.v1_0_0.json) **AC Mains** use case，每筆成員須能表達整機（或該路進線）之功率／能耗與接線型態；單相與三相機型皆透過此集合暴露。

| 進線類型 | 週邊 | `Members` 成員數 | 說明 |
|----------------------|----------|------------------|------|
| `1` Current、`2` WattHour | `INFEED` | 進線路數（通常 1） | 每路單相進線一筆 `Mains/{id}` |
| `3` ThreePhase | `INFEED3P` | 1 | 三相整體進線一筆 `Mains/1`，量測以 `PolyPhase*` 呈現 |
| 無進線（如 DPB） | — | 1（合成） | 滿足 OCP 必填；見 `usesSyntheticMainCircuit` |

**單相**（一進線）與**三相**（整體進線）集合結構相同；多路單相進線時 `Members` 可含多筆（如 `Mains/1`、`Mains/2`）。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains",
  "@odata.type": "#CircuitCollection.CircuitCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1" }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 進線集合 URI，固定 `.../RackPDUs/{rackId}/Mains`
* **@odata.type**: 資源型別，固定 `#CircuitCollection.CircuitCollection`（**Mandatory**）
* **Members**: 進線電路連結陣列；單相多進線時每路一筆，三相整體進線通常僅一筆
* **Members@odata.count**: 進線路數（與 `Members` 長度相同）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Mains/{mainId}

電源進線電路（`CircuitType: Mains`）。`{mainId}` 為進線路數。依 [DMTF DSP2056](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf) Circuit schema 與 OCP **AC Mains** use case：

* **單相**（單相進線）：對應單相進線週邊；使用 `Voltage`、`CurrentAmps`，`PhaseWiringType` 為 `OnePhase3Wire`。
* **三相**（三相進線）：對應三相進線週邊（L1／L2／L3，`elements.id` 1–3）；使用 `PolyPhaseVoltage`、`PolyPhaseCurrentAmps` 等，**不得**同時出現單相 `Voltage`／`CurrentAmps`（OCP Conditional：二擇一）。
* **無進線機型**：合成 `Mains/1`（`Oem.Pelx.Synthetic: true`）。

OCP 量測互斥（Mains）：

| 接線 | `PhaseWiringType` | 電壓 | 電流 |
|------|-------------------|------|------|
| 單相 | `OnePhase3Wire` | `Voltage`（**Mandatory**） | `CurrentAmps`（**Mandatory**） |
| 三相 | `ThreePhase4Wire` 或 `ThreePhase5Wire` | `PolyPhaseVoltage`（**Mandatory**） | `PolyPhaseCurrentAmps`（**Mandatory**） |

`PolyPhaseVoltage`／`PolyPhaseCurrentAmps` 之子鍵為 [ElectricalContext](https://redfish.dmtf.org/schemas/v1_8_1/Circuit.json) 列舉（如 `Line1ToNeutral`、`Line1`）；各子鍵內含 `Reading` 與建議之 `DataSourceUri`（指向 `Chassis/1/Sensors/...`）。

#### OCP AC Mains 欄位名稱合規對照

以下對照 [OCPRackPDU.v1_0_0.json](https://github.com/opencomputeproject/HWMgmt-OCP-Profiles/blob/master/RackAndPower/OCPRackPDU.v1_0_0.json) **Circuit → AC Mains** use case。

| 欄位 | OCP 要求 | 單相 | 三相 |
|------|----------|------|------|
| `CircuitType` | Mandatory（`Mains`） | ✓ | ✓ |
| `UserLabel` | Mandatory，可寫 | ✓ | ✓ |
| `ElectricalContext` | Mandatory | `Total` | `Total` |
| `PhaseWiringType` | Mandatory | `OnePhase3Wire` | `ThreePhase4Wire`／`ThreePhase5Wire` |
| `Voltage` | Conditional（無 `PolyPhaseVoltage`） | **Mandatory** | 省略 |
| `CurrentAmps` | Conditional（無 `PolyPhaseCurrentAmps`） | **Mandatory** | 省略 |
| `PolyPhaseVoltage` | Conditional（無 `Voltage`） | 省略 | **Mandatory** |
| `PolyPhaseCurrentAmps` | Conditional（無 `CurrentAmps`） | 省略 | **Mandatory** |
| `PowerWatts` | Mandatory（`Reading`） | ✓ | ✓（總量） |
| `EnergykWh` | Mandatory（`Reading`） | ✓ | ✓（總量） |
| `FrequencyHz` | Recommended | ✓ | ✓ |
| `PolyPhasePowerWatts` | Recommended | — | `Line1ToNeutral` 等 |
| `PolyPhaseEnergykWh` | Recommended | — | 各相能耗 |
| `NominalVoltage` | 支援 | 列舉字串 | 列舉字串 |
| `NominalFrequencyHz` | Recommended | 可選 | 可選 |
| `VoltageType` | 支援 | `AC` | `AC` |
| `RatedCurrentAmps` | 支援 | ✓ | ✓ |
| `PowerState` | 支援 | ✓ | ✓ |
| `Status` | Mandatory | ✓ | ✓ |
| `Links.PowerOutlet` | Recommended（Mains） | 插座連結 | 插座連結 |
| `Links.DistributionCircuits` | Recommended | 分支連結 | 分支連結 |
| `ElectricalSourceName` | Recommended，可寫 | 可選 | 可選 |
| `ElectricalSourceManagerURI` | Recommended，可寫 | 可選 | 可選 |
| `UnbalancedCurrentPercent` | Recommended | — | 可選 |
| `UnbalancedVoltagePercent` | Recommended | — | 可選 |
| `Actions.#Circuit.ResetMetrics` | Recommended | ✓ | ✓ |

**命名與型別注意**

* **`NominalVoltage`**：DMTF 為 `NominalVoltageType` **列舉字串**（如 `AC230V`、`AC100To240V`），**不是** `{ "Reading": … }` 物件；即時電壓請用 `Voltage` 或 `PolyPhaseVoltage`。
* **`Links`**：OCP Mains 建議 `Links.PowerOutlet`；DMTF Circuit 亦支援 `Links.Outlets`（與 Branches 相同結構），實作可擇一或並列。
* **Sensor `{id}`**（如 `VoltageA`）：Pelx 命名，非 OCP 標準；OCP 僅要求 `DataSourceUri` 指向 `Chassis/…/Sensors/{sensorId}`。
* **`Oem.Pelx`**：廠商擴充，不計入 OCP 合規。

**`PolyPhaseVoltage` 子鍵**（OCP IfImplemented，依機型擇一或多個）：

| 子鍵 | 說明 |
|------|------|
| `Line1ToNeutral`、`Line2ToNeutral`、`Line3ToNeutral` | 相對中性線電壓（Pelx 三相常用） |
| `Line1ToLine2`、`Line2ToLine3`、`Line3ToLine1` | 線間電壓 |

**`PolyPhaseCurrentAmps` 子鍵**：`Line1`、`Line2`、`Line3`、`Neutral`（IfImplemented）。

#### 單相進線範例（`INFEED`）

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Mains/{mainId}",
  "@odata.type": "#Circuit.v1_8_1.Circuit",
  "Id": "{mainId}",
  "Name": "Infeed1",
  "UserLabel": "Main Input",
  "CircuitType": "Mains",
  "ElectricalContext": "Total",
  "NominalVoltage": "AC230V",
  "VoltageType": "AC",
  "PhaseWiringType": "OnePhase3Wire",
  "RatedCurrentAmps": 32,
  "PowerState": "On",
  "Voltage": {
    "Reading": 220.4,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/VoltageA"
  },
  "CurrentAmps": {
    "Reading": 12.5,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/CurrentA"
  },
  "PowerWatts": {
    "Reading": 2750.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerA"
  },
  "EnergykWh": {
    "Reading": 1523.6,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/EnergyA"
  },
  "FrequencyHz": {
    "Reading": 60.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/FrequencyA"
  },
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
    ]
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Actions": {
    "#Circuit.ResetMetrics": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1/Actions/Circuit.ResetMetrics"
    }
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "ElementId": 1,
      "Alias": "INFEED",
      "Interfaces": {
        "Voltage": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101" },
        "CurrentAmps": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2103" },
        "PowerWatts": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CAI2105" },
        "FrequencyHz": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2102" }
      }
    }
  }
}
```

#### 三相進線範例（`INFEED3P`，`infeedKind=ThreePhase`）

三相機型以**單一** `Mains/1` 表示整體 AC 進線；各相量測彙整至 `PolyPhase*`。`INFEED3P` 的 `elements.id` 1／2／3 分別對應 L1（X）／L2（Y）／L3（Z）。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1",
  "@odata.type": "#Circuit.v1_8_1.Circuit",
  "Id": "1",
  "Name": "Main Input",
  "UserLabel": "Main Input",
  "CircuitType": "Mains",
  "ElectricalContext": "Total",
  "NominalVoltage": "AC230V",
  "VoltageType": "AC",
  "PhaseWiringType": "ThreePhase4Wire",
  "RatedCurrentAmps": 32,
  "PowerState": "On",
  "PolyPhaseVoltage": {
    "Line1ToNeutral": {
      "Reading": 220.1,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/VoltageA"
    },
    "Line2ToNeutral": {
      "Reading": 219.8,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/VoltageB"
    },
    "Line3ToNeutral": {
      "Reading": 220.4,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/VoltageC"
    }
  },
  "PolyPhaseCurrentAmps": {
    "Line1": {
      "Reading": 12.5,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/CurrentA"
    },
    "Line2": {
      "Reading": 11.8,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/CurrentB"
    },
    "Line3": {
      "Reading": 12.1,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/CurrentC"
    }
  },
  "PolyPhasePowerWatts": {
    "Line1ToNeutral": {
      "Reading": 2750.0,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerA"
    },
    "Line2ToNeutral": {
      "Reading": 2594.0,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerB"
    },
    "Line3ToNeutral": {
      "Reading": 2666.0,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerC"
    }
  },
  "PowerWatts": {
    "Reading": 8010.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/PowerTotal"
  },
  "EnergykWh": {
    "Reading": 4521.3,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/EnergyTotal"
  },
  "FrequencyHz": {
    "Reading": 60.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/FrequencyA"
  },
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
    ]
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Actions": {
    "#Circuit.ResetMetrics": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1/Actions/Circuit.ResetMetrics"
    }
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "Alias": "INFEED3P",
      "InterfaceGroups": {
        "PolyPhaseVoltage": {
          "Line1ToNeutral": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B201" },
          "Line2ToNeutral": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B202" },
          "Line3ToNeutral": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B203" }
        },
        "PolyPhaseCurrentAmps": {
          "Line1": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B401" },
          "Line2": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B402" },
          "Line3": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI1B403" }
        },
        "PolyPhasePowerWatts": {
          "Line1ToNeutral": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CAI1B501" }
        }
      }
    }
  }
}
```

介面 alias 對照（`INFEED3P` 每相元素）：

| Redfish 欄位 | `INFEED3P` 介面 alias | Sensor `{id}`（相別 A/B/C） |
|--------------|----------------------|----------------------------|
| `PolyPhaseVoltage.Line1ToNeutral` | `V`（id=1） | `VoltageA` |
| `PolyPhaseVoltage.Line2ToNeutral` | `V`（id=2） | `VoltageB` |
| `PolyPhaseVoltage.Line3ToNeutral` | `V`（id=3） | `VoltageC` |
| `PolyPhaseCurrentAmps.Line1` | `CUR`（id=1） | `CurrentA` |
| `PolyPhaseCurrentAmps.Line2` | `CUR`（id=2） | `CurrentB` |
| `PolyPhaseCurrentAmps.Line3` | `CUR`（id=3） | `CurrentC` |
| `PolyPhasePowerWatts.Line1ToNeutral` | `AP`（id=1） | `PowerA` |
| `FrequencyHz` | `FREQ`（id=1） | `FrequencyA` |
| `EnergykWh` | 各相 `UWH` 彙總 | `EnergyTotal` 或各相 `EnergyA`…`C` |

#### 欄位說明如下:

* **id**（路徑參數）: 進線路數；單相對應 `INFEED.elements.id`，三相整體進線固定 `1`
* **@odata.id**: 進線電路資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1`
* **@odata.type**: 資源型別，固定 `#Circuit.v1_8_1.Circuit`
* **Id**: 資源識別碼，與路徑參數 `{mainId}` 相同
* **Name**: 顯示名稱；單相如 `Infeed1`，三相如 `Main Input`
* **CircuitType**: 電路類型，進線固定 `Mains`（OCP AC Mains use case）
* **UserLabel**: 使用者標籤（OCP **Mandatory**，可寫入）
* **ElectricalContext**: 電氣上下文（OCP **Mandatory**），進線總量為 `Total`
* **VoltageType**: 電壓類型，如 `AC`
* **PhaseWiringType**: 相線接線類型（OCP **Mandatory**）；單相 `OnePhase3Wire`，三相 `ThreePhase4Wire` 或 `ThreePhase5Wire`（依機型中性線配置）
* **RatedCurrentAmps**: 額定電流（A），額定電流設定
* **PowerState**: 進線供電狀態，`On` 或 `Off`
* **NominalVoltage**: 額定電壓類型（DMTF `NominalVoltageType` **字串列舉**，如 `AC230V`、`AC100To240V`）；由即時讀值或機型預設推斷，**非**量測 excerpt 物件
* **Voltage**: 單相即時電壓（OCP Conditional：無 `PolyPhaseVoltage` 時 **Mandatory**）；三相機型**省略**
  * **DataSourceUri**: 須指向 `Chassis/{chassisId}/Sensors/{sensorId}`
* **CurrentAmps**: 單相電流量測（OCP Conditional：無 `PolyPhaseCurrentAmps` 時 **Mandatory**）；三相機型**省略**
* **PolyPhaseVoltage**: 三相線對中性點／線間電壓（OCP Conditional：無 `Voltage` 時 **Mandatory**）；子鍵為 `Line1ToNeutral`、`Line2ToNeutral`、`Line3ToNeutral` 等
* **PolyPhaseCurrentAmps**: 三相各相電流（OCP Conditional：無 `CurrentAmps` 時 **Mandatory**）；子鍵為 `Line1`、`Line2`、`Line3`
* **PolyPhasePowerWatts**: 各相有功功率（OCP **Recommended**）；子鍵為 `Line1ToNeutral` 等
* **PolyPhaseEnergykWh**: 各相累計能耗（OCP **Recommended**）；若僅回報總量可省略，改以 `EnergykWh` 表示
* **PowerWatts**: 有功功率總量（OCP **Mandatory**）；三相為各相 `AP` 彙總或晶片總功率
* **EnergykWh**: 累計能耗總量（OCP **Mandatory**）
* **FrequencyHz**: 頻率（OCP **Recommended**）；三相通常取 L1 之 `FREQ`
* **Links**: 電路關聯（OCP **Recommended**）
  * **PowerOutlet** / **Outlets**: 此進線供電之插座列表（OCP Mains 建議 `PowerOutlet`；DMTF 亦支援 `Outlets`）
  * **DistributionCircuits**: 下層分支／配電電路（OCP Recommended）
* **Actions.#Circuit.ResetMetrics**: 重設進線能耗計數（OCP **Recommended**）；見下方 `POST` 章節
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，固定 `Enabled`
  * **Health**: 健康狀態，由相關介面 **status** 彙整
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **ElementId**: 週邊路數（單相 `INFEED`）；三相整體進線可省略或標示主相
    * **Alias**: 週邊別名；單相 `INFEED`，三相 `INFEED3P`
    * **Synthetic**: `true` 表示無實體進線之合成資源（如 DPB）
    * **Interfaces**: 各量測對應之 Pelx 介面資源連結（單相 `INFEED`）
    * **InterfaceGroups**: 三相巢狀量測對照（`INFEED3P`）；結構與 `PolyPhaseVoltage` 等欄位對應
* 若機型無某量測（如瓦時），該欄位省略

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 進線不存在

### POST https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Mains/{mainId}/Actions/Circuit.ResetMetrics

重設進線能耗計數。重設該插座能耗計數。

請求 body 可為空物件 `{}`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 重設成功
401   | 未認證
403   | 權限不足
404   | 進線不存在
500   | 裝置不支援或內部錯誤

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Branches

分支電路集合（OCP **Mandatory**；無實體分支時 `Members` 為空陣列）。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches",
  "@odata.type": "#CircuitCollection.CircuitCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches/1" }
  ],
  "Members@odata.count": 1
}
```

無分支時 `Members` 為 `[]`，`Members@odata.count` 為 `0`。

#### 欄位說明如下:

* **@odata.id**: 分支集合 URI，固定 `.../RackPDUs/{rackId}/Branches`
* **Members**: 分支電路連結陣列；無分支時為 `[]`
* **Members@odata.count**: 分支數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Branches/{branchId}

分支電路（`CircuitType: Branch`）。若無分支進線 且無分支，集合為空。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches/1",
  "@odata.type": "#Circuit.v1_8_1.Circuit",
  "Id": "1",
  "Name": "Branch1",
  "UserLabel": "Branch 1",
  "CircuitType": "Branch",
  "ElectricalContext": "Line1",
  "NominalVoltage": "AC230V",
  "VoltageType": "AC",
  "PhaseWiringType": "OnePhase3Wire",
  "CurrentAmps": {
    "Reading": 8.2,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Branch1Current"
  },
  "PowerWatts": {
    "Reading": 1804.0,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Branch1Power"
  },
  "Links": {
    "SourceCircuit": {
      "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Mains/1"
    },
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
    ]
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "ElementId": 1,
      "Alias": "BRANCH",
      "Interfaces": {
        "CurrentAmps": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2203" },
        "PowerWatts": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CAI2205" }
      }
    }
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: 分支路數
* **@odata.id**: 分支電路資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1/Branches/1`
* **@odata.type**: 資源型別，固定 `#Circuit.v1_8_1.Circuit`
* **Id**: 資源識別碼，與路徑參數 `{id}` 相同
* **Name**: 顯示名稱，如 `Branch1`
* **CircuitType**: 電路類型，固定 `Branch` 或 `Bus`（OCP Branches use case）
* **UserLabel**: 使用者標籤（OCP **Mandatory**，可寫入）
* **ElectricalContext**: 電氣上下文；分支 1／2／3 分別為 `Line1`／`Line2`／`Line3`
* **Links**: 電路關聯（OCP Branches use case）
  * **SourceCircuit**: 上層進線電路
  * **Outlets**: 此分支下屬插座列表
* **CurrentAmps**: 電流量測物件
  * **Reading**: 分支電流（A）
  * **DataSourceUri**: 電流感測器資源 URI
* **PowerWatts**: 功率量測物件
  * **Reading**: 分支功率（W）
  * **DataSourceUri**: 功率感測器資源 URI
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，固定 `Enabled`
  * **Health**: 健康狀態，由相關介面 **status** 彙整
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **ElementId**: 週邊路數
    * **Alias**: 週邊別名，通常為 `BRANCH`
    * **Interfaces**: 各量測對應之 Pelx 介面資源連結

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 分支不存在

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Sensors

列出本 Rack PDU 下所有感測器資源（**DSP2056 配電路徑**）。成員與 `Chassis/1/Sensors` 相同；**OCP Interop Validator 驗證 `Chassis/.../Sensors`**，`DataSourceUri` 須使用 Chassis URI。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors",
  "@odata.type": "#SensorCollection.SensorCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/CurrentA" },
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/PowerA" },
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/EnergyA" },
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/Outlet1Current" }
  ],
  "Members@odata.count": 4
}
```

#### 欄位說明如下:

* **@odata.id**: 感測器集合 URI，固定 `.../RackPDUs/{rackId}/Sensors`
* **@odata.type**: 資源型別，固定 `#SensorCollection.SensorCollection`
* **Members**: 感測器資源連結陣列
  * **@odata.id**: 單一感測器 URI；`{id}` 見下節命名規則
* **Members@odata.count**: 感測器數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### Sensor `{id}` 定義

**一筆 Sensor = 一個可讀取的 AI／CAI 量測介面**（可讀取之量測介面），來源週邊限於 Rack PDU 配電範圍：

| 來源週邊（`peripheralAlias`） | 說明 |
|------------------------------|------|
| `INFEED` | 單相進線電壓、電流、功率、能耗、頻率等（`infeedKind` = Current / WattHour） |
| `INFEED3P` | 三相進線各相電壓、電流、功率、能耗、頻率等（`infeedKind` = ThreePhase）；Sensor `{id}` 以 A/B/C 表相別 |
| `OUTLET` | 插座電壓、電流、功率、能耗等 |
| `BRANCH` / `INFEED3PB` | 分支電流、功率等（若有分支進線） |

不納入 Sensor 集合者：`DI`／`DO` 狀態位、其餘週邊（改走 `Oem/Pelx/Interfaces`）。`TEMPRH` 溫度同時出現在 `Chassis/1/Sensors/Temp{n}` 與 `ThermalSubsystem/ThermalMetrics`；濕度等若無標準欄位請查 `Oem/Pelx/Interfaces`。

**`{id}` 命名規則**（字串，URI 區分大小寫）：

```
{週邊縮寫}{路數}{量測別名}
```

| 片段 | 來源 | 範例 |
|------|------|------|
| 週邊縮寫 | 週邊類型 | 進線用 `Infeed` 或單進線簡寫 `A`/`B`；插座 `Outlet`；分支 `Branch` |
| 路數 | `elements.id` | `1`、`2`… |
| 量測別名 | 介面 `alias` 轉 Redfish | `V`→`Voltage`、`A`/`CUR`→`Current`、`W`→`Power`、`WH`→`Energy`、`FREQ`→`Frequency` |

**常見 `{id}` 範例**（依 `Mains`／`Outlets` 內 `DataSourceUri` 與 `Oem.Pelx.Interfaces` 互相對照）：

| 位置 | 介面 alias | Sensor `{id}` 範例 |
|----------|-----------|-------------------|
| INFEED 1 電流 | TC / A | `CurrentA` |
| INFEED 1 功率 | AP / W | `PowerA` |
| INFEED 1 能耗 | UWH / WH | `EnergyA` |
| INFEED 1 電壓 | V | `VoltageA` |
| INFEED3P L1 電壓 | V（id=1） | `VoltageA` |
| INFEED3P L2 電流 | CUR（id=2） | `CurrentB` |
| INFEED3P L3 功率 | AP（id=3） | `PowerC` |
| OUTLET 1 電流 | C / CUR | `Outlet1Current` |
| BRANCH 1 電流 | TC / CUR | `Branch1Current` |

整合方應以 **`GET .../Chassis/1/Sensors` 的 `Members`**（OCP）或 `GET .../RackPDUs/.../Sensors`（DSP2056）取得有效 `{id}`，並以 `Mains`／`Outlets` 的 **`DataSourceUri`** 交叉對照。

與 [DSP2056](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf) 一致：`Mains`／`Outlets` 上可內嵌 **Reading** 做快速瀏覽；`Sensors/{id}` 提供完整 **Reading**、**Thresholds** 與 **Status**，供監控系統深入輪詢。

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Sensors/{sensorId}

單一感測器讀值與閾值。`{sensorId}` 見上節。`{rackId}` 為 Rack PDU 路徑參數。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Sensors/{sensorId}",
  "@odata.type": "#Sensor.v1_9_0.Sensor",
  "Id": "{sensorId}",
  "Name": "Infeed1 Voltage",
  "Reading": 220.4,
  "ReadingUnits": "V",
  "ReadingType": "Voltage",
  "ElectricalContext": "Line1ToNeutral",
  "ReadingTime": "2026-06-15T10:00:05+08:00",
  "SensingInterval": "PT5S",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Thresholds": {
    "UpperCritical": { "Reading": 250 },
    "UpperCaution": { "Reading": 240 },
    "LowerCaution": { "Reading": 200 },
    "LowerCritical": { "Reading": 190 }
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "Interface": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
      }
    }
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: 感測器識別碼（如 `VoltageA`）
* **@odata.id**: 感測器資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageA`
* **@odata.type**: 資源型別，固定 `#Sensor.v1_9_0.Sensor`
* **Id**: 資源識別碼，與路徑參數 `{id}` 相同
* **Name**: 顯示名稱，如 `Infeed1 Voltage`
* **Reading**: 即時讀值，對應 `interfaces` 的 **value**
* **ReadingUnits**: 單位（如 `V`、`A`、`W`、`kWh`）
* **ReadingType**: 量測類型（如 `Voltage`、`Current`、`Power`、`Energy`）
* **ElectricalContext**: 電氣上下文（OCP 電氣感測器 **Mandatory**）
* **ReadingTime**: 讀值時間 ISO 8601（OCP **Mandatory**）
* **SensingInterval**: 取樣間隔 ISO 8601 duration（OCP **Mandatory**），如 `PT5S`
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，固定 `Enabled`
  * **Health**: 健康狀態，由對應介面 **status** 轉換
* **Thresholds**: 閾值物件，對應 `interfaces` 的 **params**
  * **UpperCritical**: 過高異常閾值物件
    * **Reading**: 閾值數值（過高異常閾值）
  * **UpperCaution**: 過高警告閾值物件
    * **Reading**: 閾值數值（過高警告閾值）
  * **LowerCaution**: 過低警告閾值物件
    * **Reading**: 閾值數值（過低警告閾值）
  * **LowerCritical**: 過低異常閾值物件
    * **Reading**: 閾值數值（過低異常閾值）
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **Interface**: 對應之 Pelx 介面資源連結（`/redfish/v1/Oem/Pelx/Interfaces/{addr}`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 感測器不存在

---

# ATS 轉換開關（TransferSwitches）

Redfish 標準以 **Transfer Switch** 表示 ATS（非字串 `ATS`）。僅當設備支援 ATS 時提供下列資源；否則 `GET .../TransferSwitches` 回傳空集合 `Members: []`。

> **權限**：預設見 認證（控制 Action 與寫入至少 **Operator**）。

### GET https://<host>/redfish/v1/PowerEquipment/TransferSwitches

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches",
  "@odata.type": "#PowerDistributionCollection.PowerDistributionCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1" }
  ],
  "Members@odata.count": 1
}
```

無 ATS 時 `Members` 為空陣列，`Members@odata.count` 為 `0`。

#### 欄位說明如下:

* **@odata.id**: ATS 集合資源 URI，固定 `/redfish/v1/PowerEquipment/TransferSwitches`
* **@odata.type**: 資源型別，固定 `#PowerDistributionCollection.PowerDistributionCollection`
* **Members**: ATS 資源連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一 ATS 資源 URI，如 `/redfish/v1/PowerEquipment/TransferSwitches/1`
* **Members@odata.count**: `Members` 陣列筆數；有 ATS 時通常為 `1`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常（無 ATS 時為空集合）
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/TransferSwitches/{atsId}

ATS 主資源。路徑參數 `{atsId}` 通常為 `1`；應自 `Members` 探索，無效 id 回 `404`。

**本回應是否要有 A、B 廻路資料？** 依 [DSP2056](https://www.dmtf.org/sites/default/files/standards/documents/DSP2056_1.1.0.pdf) 與一般 PDU 實作：

| 內容 | 是否在 `{atsId}` 主資源 body 內 | 取得方式 |
|------|--------------------------------|----------|
| 目前供電廻路（A 或 B） | **要**，在 `TransferConfiguration.ActiveMainsId` | 本 API |
| A／B 連結 | **要**，`Feeders.@odata.id` 指向集合 | 本 API（連結） |
| A／B 電壓、頻率、有電等量測 | **不要**內嵌 | `GET .../Feeders/A`、`GET .../Feeders/B` |
| 切換參數（基準電壓等） | **不要**內嵌 | `GET .../Oem/Pelx/Parameters` |

亦即：主資源只回答「現在走 A 還是 B、切換設定為何」；兩路詳細讀值需再請求 `Feeders` 子資源。你實機 Postman 看到的結構（`ActiveMainsId: "A"` + `Feeders` 連結、無內嵌 V/Hz）**符合設計**。

**使用者怎麼知道要打 `.../Feeders/B`？** Redfish 不應猜 URL，依 **`@odata.id` 連結逐層探索**：

```
① GET /redfish/v1/PowerEquipment
      → 若有 TransferSwitches，取 TransferSwitches.@odata.id

② GET .../TransferSwitches          （或 ① 已含 Members）
      → Members[].@odata.id → .../TransferSwitches/1

③ GET .../TransferSwitches/1
      → Feeders.@odata.id → .../TransferSwitches/1/Feeders
      → TransferConfiguration.ActiveMainsId → 目前 "A" 或 "B"（僅狀態，非完整 URI）

④ GET .../TransferSwitches/1/Feeders
      → Members[] 列出每一廻路完整 URI，例如：
         .../Feeders/A
         .../Feeders/B

⑤ GET Members 中的 @odata.id        （整合程式對 Members 逐筆 GET 即可）
```

整合程式**只需跟著 JSON 裡的 `@odata.id` 走**，不必事先知道廻路叫 `A`/`B` 還是數字。若略過 ④ 直接猜 `Feeders/1`，會得到 404。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1",
  "@odata.type": "#PowerDistribution.v1_4_0.PowerDistribution",
  "Id": "1",
  "Name": "ATS",
  "EquipmentType": "AutomaticTransferSwitch",
  "Manufacturer": "Pelx",
  "Model": "ZDL-2A-12Z",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Feeders": {
    "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Feeders"
  },
  "Mains": {
    "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Mains"
  },
  "TransferConfiguration": {
    "ActiveMainsId": "A",
    "AutoTransferEnabled": true,
    "TransferSensitivity": "Medium"
  },
  "Oem": {
    "Pelx": {
      "AtsKind": 1,
      "Parameters": {
        "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Oem/Pelx/Parameters"
      }
    }
  }
}
```

#### 欄位說明如下:

* **atsId**（路徑參數）: ATS 資源識別碼；有 ATS 時通常為 `1`
* **@odata.id**: ATS 資源 URI，如 `/redfish/v1/PowerEquipment/TransferSwitches/1`
* **@odata.type**: 資源型別，固定 `#PowerDistribution.v1_4_0.PowerDistribution`
* **Id**: 資源識別碼，與路徑參數 `{atsId}` 相同
* **Name**: 顯示名稱，固定 `ATS`
* **EquipmentType**: 設備類型，固定 `AutomaticTransferSwitch`（自動轉換開關）
* **Manufacturer**: 製造商，製造商識別
* **Model**: 型號，設備型號
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，固定 `Enabled`
  * **Health**: 健康狀態，由 ATS 廻路與告警彙整
* **Feeders**: 輸入廻路集合連結物件（A／B 源）
  * **@odata.id**: 廻路列表 URI（`.../Feeders`）；`GET .../Feeders/A`、`.../Feeders/B`
* **Mains**: 輸出側電路集合連結物件（ATS 切換後輸出）
  * **@odata.id**: 輸出列表 URI（`.../Mains`）；`GET .../Mains/1`
* **TransferConfiguration**: ATS 切換組態（對應 DSP2056）；**本資源內表示 A/B 的唯一即時欄位為 ActiveMainsId**
  * **ActiveMainsId**: 目前供電廻路，`A` 或 `B`
  * **AutoTransferEnabled**: 是否啟用自動切換
  * **TransferSensitivity**: 切換靈敏度，`High` / `Medium` / `Low`
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **AtsKind**: ATS 種類，ATS 種類（`1`=110V、`2`=220V）
    * **Parameters**: ATS 參數資源連結物件
      * **@odata.id**: 完整參數 URI

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | `{atsId}` 不存在，或本機無 ATS（設備不支援 ATS 時）

### GET https://<host>/redfish/v1/PowerEquipment/TransferSwitches/{atsId}/Feeders

列出 ATS 兩路輸入源。廻路識別碼為 **`A`、`B`（字串）**，不是數字 `1`、`2`。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Feeders",
  "@odata.type": "#CircuitCollection.CircuitCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Feeders/A" },
    { "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Feeders/B" }
  ],
  "Members@odata.count": 2
}
```

#### 欄位說明如下:

* **atsId**（路徑參數）: ATS 資源識別碼，通常為 `1`
* **@odata.id**: 廻路集合 URI，如 `.../TransferSwitches/1/Feeders`
* **@odata.type**: 資源型別，固定 `#CircuitCollection.CircuitCollection`
* **Members**: 輸入廻路連結陣列，固定兩筆 `A`、`B`
  * **@odata.id**: 單一廻路 URI；`.../Feeders/A` 或 `.../Feeders/B`
* **Members@odata.count**: 固定 `2`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | ATS 不存在

### GET https://<host>/redfish/v1/PowerEquipment/TransferSwitches/{atsId}/Feeders/{feederId}

輸入廻路量測。`feederId` **僅允許** `A` 或 `B`。

**常見誤用**：`GET .../Feeders/1` 或 `.../Feeders/2` 會回 **404**——廻路不是用數字路數編號，請改請求 `.../Feeders/A`、`.../Feeders/B`，或先 `GET .../Feeders` 從 `Members` 取得 URI。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Feeders/A",
  "@odata.type": "#Circuit.v1_8_1.Circuit",
  "Id": "A",
  "Name": "Source A",
  "CircuitType": "Mains",
  "NominalVoltage": {
    "Reading": 110.2
  },
  "FrequencyHz": {
    "Reading": 60.0
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Oem": {
    "Pelx": {
      "Alias": "ATS",
      "Links": {
        "Interfaces": {
          "Voltage": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI0E201" },
          "FrequencyHz": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI0E301" },
          "Present": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DI0E401" }
        }
      }
    }
  }
}
```

#### 欄位說明如下:

* **atsId**（路徑參數）: ATS 資源識別碼
* **feederId**（路徑參數）: 廻路識別碼，**僅** `A` 或 `B`（非 `1`／`2`）
* **@odata.id**: 廻路電路資源 URI，如 `.../Feeders/A`
* **@odata.type**: 資源型別，固定 `#Circuit.v1_8_1.Circuit`
* **Id**: 資源識別碼，與 `feederId` 相同
* **Name**: 顯示名稱，如 `Source A`
* **CircuitType**: 電路類型，輸入廻路固定 `Mains`（DSP2056 對 Transfer Switch 之輸入源）
* **NominalVoltage**: 電壓量測物件
  * **Reading**: 廻路電壓（V），對應 **ATAV**（A）或 **ATBV**（B）
* **FrequencyHz**: 頻率量測物件
  * **Reading**: 廻路頻率（Hz），對應 **ATAF**（A）或 **ATBF**（B）
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態
  * **Health**: 健康狀態；廻路有電／電壓頻率告警由 **ATAI**、**ATAVH** 等 DI 彙整
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **Alias**: 週邊別名，固定 `ATS`
    * **Interfaces**: 各量測對應之 Pelx 介面資源連結（`/redfish/v1/Oem/Pelx/Interfaces/{addr}`）
      * **Voltage**: 電壓介面
      * **FrequencyHz**: 頻率介面
      * **Present**: 有電狀態介面（**ATAI** / **ATBI**）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | ATS 不存在，或 `feederId` 非 `A`／`B`（如誤用 `Feeders/1`）

ATS 切換參數。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/TransferSwitches/1/Oem/Pelx/Parameters",
  "@odata.type": "#Pelx.AtsParameters",
  "Id": "Parameters",
  "brownOutHighA": 120,
  "brownOutHighB": 120,
  "brownOutLowA": 100,
  "brownOutLowB": 80,
  "frequencyHighA": 65,
  "frequencyHighB": 65,
  "frequencyLowA": 55,
  "frequencyLowB": 55,
  "frequencyNominal": 60,
  "frequencyTolerance": 5,
  "voltageNominal": 110,
  "voltageTolerance": 10
}
```

#### 欄位說明如下:

* **id**（路徑參數）: ATS 資源識別碼
* **@odata.id**: 參數資源 URI
* **brownOutHighA** / **brownOutHighB**: A／B 廻路過高電壓閾值（V）
* **brownOutLowA** / **brownOutLowB**: A／B 廻路過低電壓閾值（V）
* **frequencyHighA** / **frequencyHighB**: A／B 廻路過高頻率閾值（Hz）
* **frequencyLowA** / **frequencyLowB**: A／B 廻路過低頻率閾值（Hz）
* **frequencyNominal**: 基準頻率（Hz）
* **frequencyTolerance**: 頻率容許範圍（Hz）
* **voltageNominal**: 基準電壓（V）；110V 系統可為 100／110／120，220V 系統可為 200／210／220／230
* **voltageTolerance**: 電壓容許範圍；110V：10–23，220V：15–25

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 本機無 ATS

### PATCH https://<host>/redfish/v1/PowerEquipment/TransferSwitches/{atsId}/Oem/Pelx/Parameters

設定 ATS 參數。；可部分更新。

```json
{
  "voltageNominal": 110,
  "voltageTolerance": 10,
  "frequencyTolerance": 5
}
```

#### 欄位說明如下:

* **id**（路徑參數）: ATS 資源識別碼
* **voltageNominal**: 基準電壓，合法值依 ATS 機型 見上節
* **voltageTolerance**: 電壓容許範圍
* **frequencyTolerance**: 頻率容許範圍（3–10）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 設定成功
400   | 參數錯誤
401   | 未認證
403   | 權限不足
404   | 本機無 ATS

---

# 插座（Outlets）

依 DSP2056，所有插座集中於單一 `Outlets` 集合，無需先查分支電路即可定位。

> **權限**：預設見 認證（`GET` ReadOnly 以上；**控制 Action** 與寫入至少 **Operator**）。

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Outlets

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets",
  "@odata.type": "#OutletCollection.OutletCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
  ],
  "Members@odata.count": 2
}
```

#### 欄位說明如下:

* **@odata.id**: 插座集合資源 URI，固定 `/redfish/v1/PowerEquipment/RackPDUs/1/Outlets`
* **@odata.type**: 資源型別，固定 `#OutletCollection.OutletCollection`
* **Members**: 插座資源連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一插座資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1`
* **Members@odata.count**: `Members` 陣列筆數，插座數量，插座總數

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Outlets/{outletId}

單路插座詳細資料。`id` 對應插座路數。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1",
  "@odata.type": "#Outlet.v1_4_4.Outlet",
  "Id": "1",
  "Name": "Outlet1",
  "UserLabel": "Server-1",
  "OutletType": "NEMA_5_20R",
  "ElectricalContext": "Line1",
  "NominalVoltage": {
    "Reading": 220
  },
  "VoltageType": "AC",
  "PhaseWiringType": "OnePhase3Wire",
  "RatedCurrentAmps": 20,
  "PowerState": "On",
  "PowerEnabled": true,
  "PowerRestorePolicy": "AlwaysOn",
  "Voltage": {
    "Reading": 220.1,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Outlet1Voltage"
  },
  "CurrentAmps": {
    "Reading": 4.2,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Outlet1Current"
  },
  "PowerWatts": {
    "Reading": 924.4,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Outlet1Power"
  },
  "EnergykWh": {
    "Reading": 128.5,
    "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Outlet1Energy"
  },
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Links": {
    "BranchCircuit": {
      "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Branches/1"
    }
  },
  "Actions": {
    "#Outlet.PowerControl": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1/Actions/Outlet.PowerControl",
      "@Redfish.ActionInfo": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1/Outlet.PowerControlActionInfo"
    },
    "#Outlet.ResetMetrics": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1/Actions/Outlet.ResetMetrics"
    }
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "ElementId": 1,
      "Alias": "OUTLET",
      "Interfaces": {
        "PowerState": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO00101" },
        "Voltage": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI00101" },
        "CurrentAmps": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI00102" },
        "PowerWatts": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI00103" },
        "EnergykWh": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CAI00104" }
      }
    }
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: 插座路數，對應插座路數
* **@odata.id**: 插座資源 URI，如 `/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1`
* **@odata.type**: 資源型別，固定 `#Outlet.v1_4_4.Outlet`
* **Id**: 資源識別碼，與路徑參數 `{id}` 相同
* **Name**: 顯示名稱，如 `Outlet1`
* **UserLabel**: 使用者標籤（OCP Recommended，可寫入）
* **OutletType**: 插座實體規格（如 `NEMA_5_20R`），依產品規格填入
* **ElectricalContext**: 電氣上下文（OCP **Mandatory**）；依插座所屬相別為 `Line1`、`Line2` 或 `Line3`（由 `relayBoardMap` 推斷；預設 `Line1`）
* **NominalVoltage**: 額定電壓
* **VoltageType**: 電壓類型，如 `AC`
* **PhaseWiringType**: 相線接線類型
* **RatedCurrentAmps**: 額定電流（A）
* **PowerRestorePolicy**: 斷電恢復策略（OCP **Mandatory**），`AlwaysOn` / `AlwaysOff` / `LastState`
* **PowerState**: 目前電源狀態（**讀取**）；僅 `On` 或 `Off`，由 DO 介面 **value** 轉換（`true` → `On`）。**不含** `PowerCycle`——重啟為控制指令，見 `POST .../Outlet.PowerControl`
* **PowerEnabled**: 插座輸出是否啟用，`true` 表示允許供電
* **Voltage** / **CurrentAmps** / **PowerWatts** / **EnergykWh**: 量測物件（OCP Recommended）
  * **Reading**: 即時讀值
  * **DataSourceUri**: 須指向 `Chassis/{chassisId}/Sensors/{sensorId}`（OCP Profile）
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，固定 `Enabled`
  * **Health**: 健康狀態，由相關介面 **status** 彙整
* **Links**: 關聯資源連結物件
  * **BranchCircuit**: 所屬分支電路（OCP **Mandatory**）
    * **@odata.id**: 分支 URI；**無實體分支時**指向對應 `Mains/{mainId}`（OCP Usage Guide）
* **Actions**: 可執行操作物件
  * **#Outlet.PowerControl**: 電源控制；須含 `@Redfish.ActionInfo` 指向 ActionInfo 資源
  * **#Outlet.ResetMetrics**: 重設插座能耗計數（OCP Recommended）
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **ElementId**: 週邊路數
    * **Alias**: 週邊別名，通常為 `OUTLET`
    * **Interfaces**: 各量測／控制對應之 Pelx 介面資源連結（`/redfish/v1/Oem/Pelx/Interfaces/{addr}`）
      * **PowerState**: DO 輸出控制介面（`DO…`）；`Outlet.PowerControl`
      * **Voltage** / **CurrentAmps** / **PowerWatts** / **EnergykWh**: 量測介面連結
* 若機型無某量測，該欄位省略

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 插座不存在

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Outlets/{outletId}/Outlet.PowerControlActionInfo

`Outlet.PowerControl` 的參數定義（Interop Validator **Mandatory** 驗證 `PowerState` 允許值）。**每個插座**各有一筆 ActionInfo，URI 在對應 Outlet 路徑下（非 RackPDU 根層）。

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1/Outlet.PowerControlActionInfo",
  "@odata.type": "#ActionInfo.v1_4_2.ActionInfo",
  "Id": "OutletPowerControlActionInfo",
  "Name": "Outlet Power Control Action Info",
  "Parameters": [
    {
      "Name": "PowerState",
      "Required": true,
      "DataType": "String",
      "AllowableValues": ["On", "Off", "PowerCycle"]
    }
  ]
}
```

### POST https://<host>/redfish/v1/PowerEquipment/RackPDUs/{rackId}/Outlets/{outletId}/Actions/Outlet.PowerControl

控制插座電源。。

```json
{
  "PowerState": "On"
}
```

`PowerState` 可選值：

| 值 | 說明 |
| ---- | ------ |
| On | 開啟 |
| Off | 關閉 |
| PowerCycle | 重啟 |

可選延遲參數（對應 `onDelay` / `offDelay`）：

```json
{
  "PowerState": "On",
  "Oem": {
    "Pelx": {
      "OnDelaySec": 10,
      "OffDelaySec": 10
    }
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: 插座路數，對應 `Outlets/{id}`
* **PowerState**: 目標電源狀態，`On` / `Off` / `PowerCycle`（重啟），見上表
* **Oem**: 廠商擴充欄位容器（可選）
  * **Pelx**: Pelx OEM 命名空間
    * **OnDelaySec**: 開啟延遲（秒），即 **OnDelaySec**
    * **OffDelaySec**: 關閉延遲（秒），即 **OffDelaySec**

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 控制成功
202   | 已接受，延遲執行中
400   | 參數錯誤
403   | 權限不足
404   | 插座不存在
409   | 插座操作中

### POST https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/{outletId}/Actions/Outlet.ResetMetrics

重設插座能耗計數。重設該插座能耗計數。

請求 body 可為空物件 `{}`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 重設成功
401   | 未認證
403   | 權限不足
404   | 插座不存在
500   | 裝置不支援或內部錯誤

---

# 插座群組（OutletGroups）

DMTF DSP2056 標準資源。依資料庫群組定義，一次控制多個插座。路徑固定於 `RackPDUs/1/OutletGroups`（非 OCP Rack PDU Profile 必填）。

> **權限**：預設見 認證（控制 Action 與寫入至少 **Operator**）。

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups",
  "Members": [
    { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups/1" }
  ],
  "Members@odata.count": 1
}
```

> 集合回應目前**未含** `@odata.type`。

### GET https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups/{id}

```json
{
  "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups/1",
  "@odata.type": "#OutletGroup.v1_2_0.OutletGroup",
  "Id": "1",
  "Name": "Group A",
  "PowerState": "On",
  "Status": { "State": "Enabled", "Health": "OK" },
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
    ]
  },
  "Actions": {
    "#OutletGroup.PowerControl": {
      "target": "/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups/1/Actions/OutletGroup.PowerControl"
    }
  },
  "Oem": { "Pelx": { "uId": 1 } }
}
```

* **PowerState**：群組內任一插座為 `Off` 時為 `Off`，否則為 `On`
* **Links.Outlets**：群組成員插座連結
* **Actions.#OutletGroup.PowerControl**：批次電源控制（參數同 `Outlet.PowerControl`）

### POST https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/OutletGroups/{id}/Actions/OutletGroup.PowerControl

對群組內所有插座執行電源控制。請求 body 同 `Outlet.PowerControl`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 控制成功
400   | 參數錯誤
403   | 權限不足
404   | 群組不存在

---

# 環境感測（Thermal）

環境溫度資料來源為溫濕度感測週邊。OCP Baseline 與 DMTF Service Validator 以 **`ThermalSubsystem`／`ThermalMetrics`** 為主路徑；`Chassis/1/Thermal` 仍保留相容舊整合，但 Chassis 資源已不再連結 `Thermal`。

### GET https://<host>/redfish/v1/Chassis/{chassisId}/ThermalSubsystem

熱管理子系統（OCP Baseline **Mandatory**）。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/ThermalSubsystem",
  "@odata.type": "#ThermalSubsystem.v1_3_0.ThermalSubsystem",
  "Id": "ThermalSubsystem",
  "Name": "Thermal Subsystem",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Fans": {
    "@odata.id": "/redfish/v1/Chassis/1/ThermalSubsystem/Fans"
  },
  "ThermalMetrics": {
    "@odata.id": "/redfish/v1/Chassis/1/ThermalSubsystem/ThermalMetrics"
  }
}
```

#### 欄位說明

* **Fans**: 風扇集合（本設備通常為空集合）
* **ThermalMetrics**: 溫度彙總與讀值連結

### GET https://<host>/redfish/v1/Chassis/{chassisId}/ThermalSubsystem/ThermalMetrics

溫度讀值與摘要（DMTF `ThermalMetrics` excerpt 格式）。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/ThermalSubsystem/ThermalMetrics",
  "@odata.type": "#ThermalMetrics.v1_3_0.ThermalMetrics",
  "Id": "ThermalMetrics",
  "Name": "Thermal Metrics",
  "TemperatureReadingsCelsius": [
    {
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Temp1",
      "Reading": 26.5,
      "PhysicalContext": "Room"
    }
  ],
  "TemperatureSummaryCelsius": {
    "Ambient": {
      "Reading": 26.5,
      "DataSourceUri": "/redfish/v1/Chassis/1/Sensors/Temp1"
    }
  }
}
```

#### 欄位說明

* **TemperatureReadingsCelsius**: 溫度讀值陣列（**excerpt** 格式）
  * **DataSourceUri**: 指向 `Chassis/1/Sensors/Temp{n}`（OCP Sensor 路徑）
  * **Reading**: 溫度（°C）
  * **PhysicalContext**: 物理情境，如 `Room`
* **TemperatureSummaryCelsius**: 摘要物件（**非** `AverageReading`／`MaxReading`／`MinReading`）
  * **Ambient**: 第一個感測點讀值
  * **Internal**: 多感測點時為平均值（僅一點時省略）

> `EnvironmentMetrics` **不含** `TemperatureSummaryCelsius`；溫度摘要僅在 `ThermalMetrics` 提供。

### GET https://<host>/redfish/v1/Chassis/{chassisId}/Sensors/Temp{n}

溫度感測器與電氣 Sensor 共用 `Chassis/1/Sensors` 集合；`{id}` 為 `Temp` + `TEMPRH.elements.id`（如 `Temp1`）。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/Sensors/Temp1",
  "@odata.type": "#Sensor.v1_9_0.Sensor",
  "Id": "Temp1",
  "Name": "Temp1 Temperature",
  "Reading": 26.5,
  "ReadingUnits": "C",
  "ReadingType": "Temperature",
  "ReadingTime": "2026-06-15T10:00:05+08:00",
  "SensingInterval": "PT5S",
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "Interface": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI00301"
      },
      "RackPduSensorUri": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/Temp1"
    }
  }
}
```

### GET https://<host>/redfish/v1/Chassis/{chassisId}/EnvironmentMetrics

機箱環境彙總（可含進線功率 `PowerWatts`）；**不含**溫度摘要欄位。

### GET https://<host>/redfish/v1/Chassis/{chassisId}/Thermal（相容）

舊版 `Thermal.v1_7_3` 資源，仍可直接 `GET` 取得 `Temperatures[]` 與 `ReadingCelsius`。**不含** `Oem.Pelx` 連結；新整合請改用 `ThermalSubsystem`／`Sensors/Temp{n}`。

```json
{
  "@odata.id": "/redfish/v1/Chassis/1/Thermal",
  "@odata.type": "#Thermal.v1_7_3.Thermal",
  "Id": "Thermal",
  "Temperatures": [
    {
      "MemberId": "1",
      "Name": "Temp1",
      "ReadingCelsius": 26.5,
      "Status": {
        "State": "Enabled",
        "Health": "OK"
      }
    }
  ],
  "Fans": []
}
```

* 濕度等量測若無標準 `Thermal`／`ThermalMetrics` 欄位，請改查 `Oem/Pelx/Interfaces`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

---

# 告警與事件（EventService）

OCP Rack PDU Profile 要求提供 `EventService`；標準事件訂閱見 `Subscriptions`。Pelx 另提供 `Events` 作為目前告警快照（非 OCP 必填，見「Pelx 擴充」）。

> 若整合環境中設備無法被外部主動連線（防火牆／NAT），可採 DMTF **OutboundConnection**（設備主動 WebSocket 連至雲端）；見 outbound connection。告警推送仍建議用本章 `Subscriptions`。

### GET https://<host>/redfish/v1/EventService

```json
{
  "@odata.id": "/redfish/v1/EventService",
  "@odata.type": "#EventService.v1_11_0.EventService",
  "Id": "EventService",
  "ServiceEnabled": true,
  "DeliveryRetryAttempts": 3,
  "DeliveryRetryIntervalSeconds": 60,
  "RegistryPrefixes": [
    "Power",
    "SensorEvent",
    "Update"
  ],
  "Subscriptions": {
    "@odata.id": "/redfish/v1/EventService/Subscriptions"
  },
  "Events": {
    "@odata.id": "/redfish/v1/EventService/Events"
  }
}
```

#### 欄位說明如下:

* **@odata.id**: EventService 資源 URI，固定 `/redfish/v1/EventService`
* **@odata.type**: 資源型別，固定 `#EventService.v1_11_0.EventService`
* **Id**: 資源識別碼，固定 `EventService`
* **ServiceEnabled**: 事件服務是否啟用（Baseline **Mandatory**）
* **DeliveryRetryAttempts**: 訂閱投遞重試次數（Baseline **Mandatory**）
* **DeliveryRetryIntervalSeconds**: 重試間隔秒數（Baseline **Mandatory**）
* **RegistryPrefixes**: 支援的 Registry 前綴（OCP **Recommended**）；PDU 建議含 `Power`、`SensorEvent`、`Update`
* **Subscriptions**: 事件訂閱集合（Baseline **Mandatory**）
* **Events**: 目前告警快照（Pelx 擴充；對應 `interfaces/alarms`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/EventService/Subscriptions

```json
{
  "@odata.id": "/redfish/v1/EventService/Subscriptions",
  "@odata.type": "#EventDestinationCollection.EventDestinationCollection",
  "Members": [],
  "Members@odata.count": 0
}
```

#### 欄位說明如下:

* **@odata.id**: 訂閱集合 URI，固定 `/redfish/v1/EventService/Subscriptions`
* **Members**: 訂閱資源連結陣列；`POST` 此集合建立新訂閱
* **Members@odata.count**: 訂閱數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### POST https://<host>/redfish/v1/EventService/Subscriptions

建立事件訂閱。訂閱持久化於設備本機，重啟後自動載入。告警狀態變更時，設備會以 Redfish Event 格式 **POST** 至各訂閱的 `Destination`（依 `DeliveryRetryAttempts`／`DeliveryRetryIntervalSeconds` 重試）。若 `Managers/1/NetworkProtocol.Proxy.Enabled` 為 `true` 且 `Destination` 主機不在 `ExcludeAddresses`，投遞會經 HTTP/HTTPS 代理（與 OutboundConnection 共用設定）。

```json
{
  "Destination": "https://example.com/redfish/events",
  "Protocol": "Redfish",
  "Context": "Pelx monitoring"
}
```

#### 欄位說明如下:

* **Destination**: 事件接收 URL（**Mandatory**）；須為有效 `http://` 或 `https://` URL
* **Protocol**: 協定，預設 `Redfish`
* **Context**: 訂閱識別字串，預設 `Pelx`；會附在推送 payload 的 `Context` 欄位
* **EventTypes**: 可選；如 `["Alert"]` 僅推送告警，`["StatusChange"]` 僅推送恢復／狀態變更；未指定則推送所有支援類型
* **HttpHeaders**: 可選；POST 至 `Destination` 時附加的 HTTP 標頭（如 `Authorization`）

成功時回 `201 Created`，`Location` 指向 `/redfish/v1/EventService/Subscriptions/{id}`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功
400   | 參數錯誤（缺 `Destination`）
401   | 未認證

### OEM 擴充（Pelx）— 訂閱與推送 payload

為兼容既有整合欄位，可在**不改變標準 `Subscriptions` 路徑**的前提下，於請求與事件內容加上 `Oem.Pelx`。此作法不影響 OCP Baseline 必填欄位。

建立訂閱（含 OEM 參數）範例：

```json
{
  "Destination": "https://example.com/redfish/events",
  "Protocol": "Redfish",
  "Context": "Pelx monitoring",
  "Oem": {
    "Pelx": {
      "DeliveryMode": "EventOnly",
      "IncludeAlarmSeries": false,
      "IncludeInterfaceSnapshot": false
    }
  }
}
```

#### OEM 欄位建議如下:

* **Oem**: 廠商擴充欄位容器（可選）
  * **Pelx**: Pelx OEM 命名空間（可選）
    * **DeliveryMode**: 推送模式，建議值 `EventOnly`
    * **IncludeAlarmSeries**: 是否附帶趨勢摘要（布林）
    * **IncludeInterfaceSnapshot**: 是否附帶介面快照（布林）

若未指定 `Oem.Pelx`，推送 payload 仍含標準 Redfish Event 欄位；啟用 `IncludeAlarmSeries`／`IncludeInterfaceSnapshot` 時，於事件 payload 的 `Oem.Pelx` 附上 `AlarmSeries` 或 `InterfaceSnapshot`。

推送 payload 範例（POST 至 `Destination`）：

```json
{
  "@odata.type": "#Event.v1_7_0.Event",
  "Name": "Event Array",
  "Context": "Pelx monitoring",
  "Events": [
    {
      "@odata.type": "#Event.v1_11_0.Event",
      "Id": "1",
      "Name": "High Warning",
      "EventType": "Alert",
      "Severity": "Warning",
      "Message": "Infeed1 V High Warning",
      "MessageId": "Pelx.1.0.highWarningAlarm",
      "EventTimestamp": "2026-06-10T08:30:00Z",
      "OriginOfCondition": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
      },
      "Oem": {
        "Pelx": {
          "@odata.type": "#Pelx.v1_0_0.Pelx",
          "Interface": {
            "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
          },
          "Name": "Infeed1",
          "Alias": "V",
          "Value": 241.2,
          "Unit": "V",
          "Status": "hw",
          "Seq": 1
        }
      }
    }
  ]
}
```

### GET https://<host>/redfish/v1/EventService/Subscriptions/{id}

查詢單一訂閱。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 訂閱不存在

### DELETE https://<host>/redfish/v1/EventService/Subscriptions/{id}

刪除訂閱。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 已刪除
401   | 未認證
404   | 訂閱不存在

### GET https://<host>/redfish/v1/EventService/Events

目前告警快照（**Pelx 擴充**。

```json
{
  "@odata.id": "/redfish/v1/EventService/Events",
  "Members": [
    {
      "@odata.id": "/redfish/v1/EventService/Events/1"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 事件集合資源 URI，固定 `/redfish/v1/EventService/Events`
* **Members**: 告警事件連結陣列，元素為 `{ "@odata.id": "..." }`
  * **@odata.id**: 單一事件資源 URI，如 `/redfish/v1/EventService/Events/1`
* **Members@odata.count**: `Members` 陣列筆數，目前告警事件數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/EventService/Events/{eventId}

```json
{
  "@odata.id": "/redfish/v1/EventService/Events/1",
  "@odata.type": "#Event.v1_11_0.Event",
  "Id": "1",
  "Name": "High Warning",
  "EventType": "Alert",
  "Severity": "Warning",
  "Message": "Infeed1 Voltage high warning",
  "MessageId": "Pelx.1.0.VoltageHighWarning",
  "Created": "2026-06-10T08:30:00Z",
  "Oem": {
    "Pelx": {
      "@odata.type": "#Pelx.v1_0_0.Pelx",
      "Interface": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
      },
      "Name": "Infeed1",
      "Alias": "V",
      "Value": 241.2,
      "Unit": "V",
      "Status": "hw"
    }
  }
}
```

#### 欄位說明如下:

* **id**（路徑參數）: 事件識別碼
* **@odata.id**: 事件資源 URI，如 `/redfish/v1/EventService/Events/1`
* **@odata.type**: 資源型別，固定 `#Event.v1_11_0.Event`
* **Id**: 資源識別碼，與路徑參數 `{id}` 相同
* **Name**: 事件顯示名稱，如 `High Warning`
* **EventType**: 事件類型，告警固定 `Alert`
* **Severity**: 嚴重程度，`Warning` 對應 `GET /interfaces/alarms?kind=warnings`；`Critical` 對應 `kind=critical`
* **Message**: 人可讀告警訊息
* **MessageId**: 告警訊息識別碼，如 `Pelx.1.0.VoltageHighWarning`
* **Created**: 事件時間（ISO 8601 UTC），如 `2026-06-10T08:30:00Z`
* **Oem**: 廠商擴充欄位容器
  * **Pelx**: Pelx OEM 命名空間
    * **Interface**: 觸發告警的 Pelx 介面資源連結
    * **Name**: 週邊名稱
    * **Alias**: 介面別名
    * **Value**: 觸發時讀值
    * **Unit**: 單位
    * **Status**: 介面狀態碼（如 `hw`、`hc`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 事件不存在

---

# OutboundConnection（出站 WebSocket 連線）

DMTF **Redfish 2023.2** 起新增 **OutboundConnection** schema（`OutboundConnection.v1_0_2`）：設備在防火牆或 NAT 後方時，可**主動**以 **WebSocket（`wss://`）** 連至外部服務（雲端 DCIM、事件閘道等），由遠端接收 Redfish 請求／回應，無須對設備開放 inbound 連線。

> **實作狀態**：**已實作**（hwctrl）。REST 設定／憑證管理、WebSocket 出站連線、Session 與 Redfish over WebSocket 隧道轉發均已支援。若僅需事件推送，仍可使用 告警與事件 之 `EventService/Subscriptions`；高頻即時監控見 MQTT Discovery。

### 與其他推送機制的分工

| 機制 | 連線方向 | 協議 | 用途 |
|------|----------|------|------|
| **OutboundConnection** | 設備 → 外部 | WebSocket（`wss`） | 防火牆後設備主動連雲端；遠端以 Redfish over WS 操作 |
| **EventService/Subscriptions** | 設備 → 外部 | HTTP POST | OCP 標準告警／事件推送 |
| **MQTT over WebSocket**（Pelx OEM） | 外部 → 設備 | WebSocket + MQTT | 高頻即時監控；非 DMTF OutboundConnection |

### 資源路徑

OutboundConnection 掛於 **AccountService** 下（DMTF 慣例）：

```
/redfish/v1/AccountService
└── OutboundConnections/{id}     出站連線設定與狀態
    ├── Certificates               遠端伺服器憑證（MTLS 驗證用）
    └── ClientCertificates         設備端憑證（MTLS 用）
```

連線建立後，hwctrl 建立對應 **Session** 資源（`Outbound-{id}`）；`Links.Session` 指向該 Session。連線關閉時 Session 刪除。

### Web UI 與 sysctrl 對應

| 項目 | 說明 |
|------|------|
| Web UI「Redfish 出站連線」 | 僅管理 id=`1`；`enabled` 對應 `ConnectionEnabled` |
| 多筆連線並存 | 各 id 獨立；`ConnectionEnabled: true` 者重啟後皆會自動連線 |

詳見 modules/sysctrl/web.md。

### 使用限制

整合方與操作人員須注意下列限制（與 DMTF schema 不可變欄位及 Pelx id 保留策略有關）：

| 限制 | 說明 |
|------|------|
| **PATCH 不可改端點** | `EndpointURI`、`Authentication`、`Roles`、`PreUpgradeHTTPHeaders` 建立後**不可**以 Redfish PATCH 修改；嘗試 PATCH 上述欄位回 **400** |
| **id≥`2` 改端點** | 須 Redfish **DELETE + POST** 重建（新 id 由伺服器自動分配，可能與刪除前不同） |
| **多筆連線並存** | 各 id 獨立運作、各自連線；`ConnectionEnabled: true` 者**重啟後皆會自動連線** |
| **Redfish 須認證** | `GET` 須 **Operator 以上**；`POST`／`PATCH`／`DELETE` 須 **Administrator** |
| **EndpointURI 須 wss** | 僅支援 `wss://`；`ws://` 或非 WebSocket URI 建立時回 **400** |
| **MTLS 憑證** | 須分別 `POST` 至 `Certificates`／`ClientCertificates`；Client 須含私鑰；GET 不回傳私鑰 |

#### 常見操作對照

| 目的 | 建議做法 |
|------|----------|
| 變更 id≥`2` 的遠端位址 | Redfish `DELETE` 後 `POST` 重建 |
| 額外雲端連線（非 Web UI） | Redfish `POST`（得 id≥`2`） |

### GET https://<host>/redfish/v1/AccountService/OutboundConnections

列出出站連線設定。**須 Operator 以上**。

```json
{
  "@odata.id": "/redfish/v1/AccountService/OutboundConnections",
  "@odata.type": "#OutboundConnectionCollection.OutboundConnectionCollection",
  "Members": [],
  "Members@odata.count": 0
}
```

#### 欄位說明如下:

* **@odata.id**: 集合 URI，固定 `/redfish/v1/AccountService/OutboundConnections`
* **Members**: 各 OutboundConnection 資源連結
* **Members@odata.count**: 連線設定數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足（ReadOnly）

### POST https://<host>/redfish/v1/AccountService/OutboundConnections

建立出站連線。**須 Administrator**。若 `ConnectionEnabled` 為 `true`，建立後即嘗試連線。

```json
{
  "Name": "cloud-dcim",
  "Description": "Primary cloud gateway",
  "EndpointURI": "wss://dcim.example.com/redfish/ws",
  "Authentication": "MTLS",
  "ConnectionEnabled": true,
  "WebSocketPingIntervalMinutes": 5,
  "Roles": ["Operator"],
  "RetryPolicy": {
    "ConnectionRetryPolicy": "RetryForever",
    "RetryIntervalMinutes": 5
  },
  "PreUpgradeHTTPHeaders": {
    "Authorization": "Bearer <token>"
  }
}
```

#### 請求欄位（`requiredOnCreate` 摘要）

* **EndpointURI**（必填）: 遠端 WebSocket URI；**須為 `wss://`**（RFC6455）
* **Authentication**（必填）: `None`｜`MTLS`｜`JWT`｜`OEM`
* **Roles**（必填）: 遠端客戶端在此連線上擁有的 Redfish 角色（如 `Operator`）；hwctrl 以**第一個**角色建立 Session
* **WebSocketPingIntervalMinutes**（必填）: WebSocket ping 間隔（分）；`0` 表示不送 ping
* **ConnectionEnabled**: 是否啟用；省略時預設 `true`
* **PreUpgradeHTTPHeaders**: WebSocket 升級前送出的 HTTP 標頭（如 JWT 的 `Authorization: Bearer ...`）；儲存於設定檔，**GET 回應固定為空物件**（不洩漏敏感標頭）
* **RetryPolicy**: 重連策略（`None`｜`RetryForever`｜`RetryCount`）及 `RetryIntervalMinutes`、`RetryCount`

成功時回 `201 Created`，`Location` 指向 `/redfish/v1/AccountService/OutboundConnections/{id}`。`{id}` 由伺服器自動分配，**從 `2` 起**（`1` 保留給 sysctrl／Web UI）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 已建立
400   | 參數錯誤（如 EndpointURI 非 `wss://`）
401   | 未認證
403   | 權限不足

### GET https://<host>/redfish/v1/AccountService/OutboundConnections/{id}

查詢單一出站連線。

```json
{
  "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1",
  "@odata.type": "#OutboundConnection.v1_0_2.OutboundConnection",
  "Id": "1",
  "Name": "cloud-dcim",
  "Description": "Primary cloud gateway",
  "EndpointURI": "wss://dcim.example.com/redfish/ws",
  "Authentication": "MTLS",
  "ConnectionEnabled": true,
  "WebSocketPingIntervalMinutes": 5,
  "Roles": ["Operator"],
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "RetryPolicy": {
    "ConnectionRetryPolicy": "RetryForever",
    "RetryIntervalMinutes": 5
  },
  "Certificates": {
    "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1/Certificates"
  },
  "ClientCertificates": {
    "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1/ClientCertificates"
  },
  "Links": {
    "Session": {
      "@odata.id": "/redfish/v1/SessionService/Sessions/Outbound-1"
    }
  },
  "PreUpgradeHTTPHeaders": {}
}
```

#### 欄位說明如下:

* **EndpointURI**: 遠端 WebSocket 端點（唯讀；建立後不可改）
* **Authentication**: 認證機制（唯讀）
  * **MTLS**: 雙向 TLS；使用 `Certificates`／`ClientCertificates` 內 PEM
  * **JWT**: 以 `PreUpgradeHTTPHeaders` 帶 Bearer Token（握手時送出）
  * **None**: 不帶客戶端憑證；`wss` 時若未上傳 `Certificates` 則不驗證伺服器憑證
* **ConnectionEnabled**: 是否啟用；`false` 時關閉既有連線
* **Roles**: 遠端客戶端權限角色（唯讀）
* **Status**: 連線狀態（唯讀）
  * **State**: `Enabled`（`ConnectionEnabled=true`）或 `Disabled`
  * **Health**: 已連線為 `OK`；啟用但未連上為 `Warning`
* **Links.Session**: 作用中 WebSocket 對應的 Session（`Outbound-{id}`）；無連線時為 `null`
* **Certificates**／**ClientCertificates**: MTLS 憑證集合連結

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足
404   | 不存在

### PATCH https://<host>/redfish/v1/AccountService/OutboundConnections/{id}

更新可寫欄位。**須 Administrator**。變更後若連線已啟用，hwctrl 會重新套用設定（可能重連）。

可 PATCH 欄位：

* **ConnectionEnabled**: 啟用／停用連線
* **WebSocketPingIntervalMinutes**: ping 間隔
* **RetryPolicy**: 重連策略（`RetryIntervalMinutes`、`RetryCount` 等）
* **Name**／**Description**: 顯示名稱（Pelx 延伸）

`EndpointURI`、`Authentication`、`Roles`、`PreUpgradeHTTPHeaders` 建立後不可變更；須刪除後重建（id=`1` 見上方[使用限制](#使用限制)）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 已更新；body 為完整資源
400   | 參數錯誤
401   | 未認證
403   | 權限不足
404   | 不存在

### DELETE https://<host>/redfish/v1/AccountService/OutboundConnections/{id}

刪除出站連線設定並關閉作用中連線。**須 Administrator**。

> **id=`1` 注意**：可刪除，但 Redfish `POST` **無法**再建立 id=`1`；Web UI 連線須改由 sysctrl `PATCH /redfish-outbound` 恢復。見[使用限制](#使用限制)。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
204   | 已刪除
401   | 未認證
403   | 權限不足
404   | 不存在

### GET https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/Certificates

列出遠端伺服器信任憑證（MTLS 驗證遠端用）。**須 Operator 以上**。

```json
{
  "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1/Certificates",
  "@odata.type": "#CertificateCollection.CertificateCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1/Certificates/1" }
  ],
  "Members@odata.count": 1
}
```

### POST https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/Certificates

上傳信任憑證 PEM。**須 Administrator**。成功回 `201 Created`。

```json
{
  "Name": "Remote CA",
  "CertificateType": "PEM",
  "CertificateString": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}
```

上傳後若連線已啟用，hwctrl 會重連以套用新憑證。

### GET https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/Certificates/{certId}

查詢單筆信任憑證（`Certificate.v1_8_0`）。**須 Operator 以上**。

```json
{
  "@odata.id": "/redfish/v1/AccountService/OutboundConnections/1/Certificates/1",
  "@odata.type": "#Certificate.v1_8_0.Certificate",
  "Id": "1",
  "Name": "Remote CA",
  "CertificateType": "PEM",
  "CertificateString": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
  "Issuer": { "CommonName": "" },
  "Subject": { "CommonName": "" },
  "ValidNotBefore": "",
  "ValidNotAfter": ""
}
```

### DELETE https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/Certificates/{certId}

刪除信任憑證。**須 Administrator**。回 `204 No Content`。

### GET https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/ClientCertificates

列出設備客戶端憑證。**須 Operator 以上**。格式同 `Certificates` 集合。

### POST https://<host>/redfish/v1/AccountService/OutboundConnections/{id}/ClientCertificates

上傳客戶端憑證與私鑰。**須 Administrator**。**須同時提供** `CertificateString` 與 `PrivateKeyString`（PEM）。

```json
{
  "Name": "Device Client Cert",
  "CertificateType": "PEM",
  "CertificateString": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
  "PrivateKeyString": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}
```

`GET` 單筆客戶端憑證時**不回傳** `PrivateKeyString`（僅內部儲存供 MTLS 握手）。

### GET／DELETE `.../ClientCertificates/{certId}`

語意同 `Certificates/{certId}`；DELETE 回 `204`。

> **與 CertificateService 的差異**：`CertificateService` 管理設備**入站** HTTPS（`https-server`）；OutboundConnection 底下集合為**出站** MTLS 專用，路徑與儲存皆獨立。

### Session（`Outbound-{id}`）

WebSocket 連線成功後，hwctrl 建立 Session：

* **Id**: `Outbound-{id}`（例如連線 `1` → `Outbound-1`）
* **URI**: `/redfish/v1/SessionService/Sessions/Outbound-{id}`
* **權限**: 取自該連線 `Roles[0]`
* **隧道請求**: 遠端經 WebSocket 送出的 Redfish HTTP 請求，hwctrl 以該 Session 的 `X-Auth-Token` 轉發至本機 Redfish（`127.0.0.1`）

刪除 `Sessions/Outbound-{id}` 會關閉 WebSocket 並將 `ConnectionEnabled` 設為 `false`。

### 連線行為（hwctrl 實作）

1. `ConnectionEnabled` 為 `true` 時，向 `EndpointURI` 發起 WebSocket 握手；帶 `Sec-WebSocket-Protocol: Redfish` 及 `PreUpgradeHTTPHeaders`。
2. 若 `Managers/1/NetworkProtocol.Proxy.Enabled` 為 `true` 且目標主機不在 `ExcludeAddresses`，先對代理伺服器發 **HTTP CONNECT** 建立隧道，再於隧道內進行 TLS（`wss`）與 WebSocket 升級。
2. 握手成功後建立 `Outbound-{id}` Session；`Links.Session` 指向該資源。
3. 遠端在 WebSocket payload 送**完整 HTTP 請求**（method、path、headers、body）；hwctrl 回傳**完整 HTTP 回應**（相同 opcode）。
4. 依 `WebSocketPingIntervalMinutes` 送 ping；收到 ping 回 pong。
5. 斷線時依 **RetryPolicy** 重連：`RetryForever` 持續重試；`RetryCount` 超過次數或 `None` 時將 `ConnectionEnabled` 設為 `false`。
6. 遠端主動關閉 WebSocket 時，hwctrl 將 `ConnectionEnabled` 設為 `false` 並刪除 Session。

#### 已知限制（相對 DMTF 完整語意）

| 項目 | 說明 |
|------|------|
| `ProxyAutoConfigURI`（PAC） | 可儲存；連線尚未依 PAC 自動選路 |
| `Authentication=OEM` | 接受欄位值，無額外 OEM 行為 |
| 多角色 `Roles` | Session 僅採 `Roles[0]` |
| 憑證中繼資料 | `Issuer`／`Subject`／有效期尚未自 PEM 解析 |
| 伺服器子協定 | 未驗證回應 `Sec-WebSocket-Protocol` 是否為 `Redfish` |

### curl 範例

```bash
# 列出出站連線
curl -sk -u admin:'<password>' \
  https://<host>/redfish/v1/AccountService/OutboundConnections

# 建立 MTLS 出站連線
curl -sk -u admin:'<password>' -X POST \
  https://<host>/redfish/v1/AccountService/OutboundConnections \
  -H 'Content-Type: application/json' \
  -d '{
    "Name": "cloud-dcim",
    "EndpointURI": "wss://dcim.example.com/redfish/ws",
    "Authentication": "MTLS",
    "ConnectionEnabled": true,
    "WebSocketPingIntervalMinutes": 5,
    "Roles": ["Operator"],
    "RetryPolicy": {
      "ConnectionRetryPolicy": "RetryForever",
      "RetryIntervalMinutes": 5
    }
  }'

# 上傳遠端 CA
curl -sk -u admin:'<password>' -X POST \
  https://<host>/redfish/v1/AccountService/OutboundConnections/1/Certificates \
  -H 'Content-Type: application/json' \
  -d @remote-ca.json

# 上傳客戶端憑證（含私鑰）
curl -sk -u admin:'<password>' -X POST \
  https://<host>/redfish/v1/AccountService/OutboundConnections/1/ClientCertificates \
  -H 'Content-Type: application/json' \
  -d @client-cert.json

# 停用連線
curl -sk -u admin:'<password>' -X PATCH \
  https://<host>/redfish/v1/AccountService/OutboundConnections/1 \
  -H 'Content-Type: application/json' \
  -d '{"ConnectionEnabled": false}'
```

### 持久化與權限

| 項目 | 說明 |
|------|------|
| `GET` 集合／單筆／憑證 | **Operator 以上** |
| `POST`／`PATCH`／`DELETE` | **Administrator** |
| OCP Profile | **非** Rack PDU Profile 必填；屬 DMTF Service Baseline 選配（Redfish 2023.2+） |

### 相關章節

* 認證 — AccountService、`SessionService`、`CertificateService`（入站 HTTPS）
* 告警與事件 — EventService/Subscriptions（HTTP 事件推送）
* MQTT Discovery — MQTT over WebSocket（Pelx 即時監控）

# 歷史訊息（LogServices）

事件／操作 **Log 歷史**使用 `Managers/1/LogServices`。數值趨勢／圖表 API 見下方 **歷史趨勢（TelemetryService）**。

| 需求 | 入口 |
|------|------|
| 插座操作、系統操作 Log | `.../LogServices/Operational` → `Entries` |
| 登入／登出稽核 | `.../LogServices/Audit` → `Entries` |
| **主機補同步事件**（依 seq 區間） | `.../LogServices/Oem/Pelx/MaxSeq`、`.../LogServices/Oem/Pelx/LogSync`（見下文） |

### Operational 與 Audit 的區別

| Log 服務 | 內容 | `Oem.Pelx` 常見欄位 |
|----------|------|------------------------|
| **Operational** | 插座開關等操作（`webOutletCtrl` 等） | `Action`、`OutletId`、`PowerState` |
| **Audit** | 登入、登出 | `Username`、`Ip`（**無** `Action`） |

### 與 EventService、TelemetryService 的區別

| 服務 | 用途 |
|------|------|
| **TelemetryService** | 歷史量測、趨勢圖（見下方） |
| **LogServices** | 稽核、操作紀錄、系統 Log 流水帳 |
| **EventService** | **目前**告警／事件列表（見上方） |

探索時須依 `Managers/1` 的 `@odata.id` 與 `Members` 走訪，勿猜 URL。

---

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices

管理器的 Log 服務集合；本文件以 `Managers/{managerId}` 為例（路徑依 `Managers` 成員 `@odata.id` 為準）。

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices",
  "@odata.type": "#LogServiceCollection.LogServiceCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational"
    },
    {
      "@odata.id": "/redfish/v1/Managers/1/LogServices/Audit"
    }
  ],
  "Members@odata.count": 2,
  "Oem": {
    "Pelx": {
      "MaxSeq": {
        "@odata.id": "/redfish/v1/Managers/1/LogServices/Oem/Pelx/MaxSeq"
      },
      "LogSync": {
        "@odata.id": "/redfish/v1/Managers/1/LogServices/Oem/Pelx/LogSync"
      }
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 集合 URI，如 `/redfish/v1/Managers/1/LogServices`
* **@odata.type**: 集合型別
* **Members**: Log 服務連結陣列
  * **@odata.id**: 單一 LogService URI，如 `.../LogServices/Operational`
* **Members@odata.count**: Log 服務數量
* **Oem.Pelx.MaxSeq** / **LogSync**: 主機依 **seq** 補同步設備事件之 OEM 資源連結（非 DMTF 標準；詳下文）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

---

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices/{logId}

單一 Log 服務，描述日誌容量、覆寫策略與 Entries 集合連結。

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational",
  "@odata.type": "#LogService.v1_5_0.LogService",
  "Id": "Operational",
  "Name": "Operational Log",
  "ServiceEnabled": true,
  "LogEntryType": "Event",
  "LogPurposes": ["Operations"],
  "OverWritePolicy": "WrapsWhenFull",
  "MaxNumberOfRecords": 2000,
  "DateTime": "2026-06-15T10:00:00+08:00",
  "DateTimeLocalOffset": "+08:00",
  "Entries": {
    "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational/Entries"
  }
}
```

#### 欄位說明如下:

* **{logId}**（路徑參數）: Log 服務識別碼，如 `Operational`、`Audit`
* **@odata.id**: LogService URI
* **@odata.type**: 資源型別，如 `#LogService.v1_5_0.LogService`
* **Id**: 與 `{logId}` 相同
* **Name**: 顯示名稱
* **ServiceEnabled**: 是否啟用
* **LogEntryType**: 日誌項目型別（`Event`）
* **LogPurposes**: 日誌用途；`Operational` 為 `Operations`，`Audit` 為 `Audit`
* **OverWritePolicy**: 滿載策略，如 `WrapsWhenFull`（循環覆寫）、`NeverOverWrites`
* **MaxNumberOfRecords**: 最大保存筆數；依產品規格為 **2000**（小容量）或 **10000**（大容量），對應 history 事件庫容量
* **DateTime**: 管理器目前時間（ISO 8601）
* **DateTimeLocalOffset**: 本地時區偏移（ISO 8601）
* **Entries**: 日誌項目集合連結
  * **@odata.id**: `/redfish/v1/Managers/1/LogServices/{logId}/Entries`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | Log 服務不存在

---

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices/{logId}/Entries

日誌項目集合，含歷史操作與系統事件。

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational/Entries",
  "@odata.type": "#LogEntryCollection.LogEntryCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational/Entries/1"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **{logId}**（路徑參數）: 上層 Log 服務識別碼
* **@odata.id**: Entries 集合 URI
* **Members**: 日誌項目連結陣列
  * **@odata.id**: 單一 Entry URI
* **Members@odata.count**: 日誌筆數

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

---

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices/{logId}/Entries/{entryId}

單一日誌項目。`{logId}` 為 `Operational` 或 `Audit` 時，**Oem.Pelx 欄位不同**（見上表）；請勿將插座操作欄位套用於 Audit。

#### Operational — 插座操作範例

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Operational/Entries/1",
  "@odata.type": "#LogEntry.v1_15_0.LogEntry",
  "Id": "1",
  "Name": "Outlet Power Control",
  "EntryType": "Event",
  "Severity": "OK",
  "Created": "2026-06-10T09:15:00+08:00",
  "Message": "Outlet %1 power turned %2 by %3",
  "MessageId": "Pelx.1.0.OutletPowerOff",
  "MessageArgs": ["1", "Off", "admin"],
  "EventGroupId": "Pelx.Operational",
  "Oem": {
    "Pelx": {
      "Action": "Outlet.PowerControl",
      "OutletId": "1",
      "PowerState": "Off"
    }
  }
}
```

#### Audit — 登入／登出範例

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Audit/Entries/1",
  "@odata.type": "#LogEntry.v1_15_0.LogEntry",
  "Id": "1",
  "Name": "User Login",
  "EntryType": "Event",
  "Severity": "OK",
  "Created": "2026-06-10T08:00:00+08:00",
  "Message": "User %1 logged in from %2",
  "MessageId": "Pelx.1.0.UserLogin",
  "MessageArgs": ["admin", "192.168.1.10"],
  "EventGroupId": "Pelx.Audit",
  "Oem": {
    "Pelx": {
      "Username": "admin",
      "Ip": "192.168.1.10"
    }
  }
}
```

#### 欄位說明如下:

* **{logId}**（路徑參數）: Log 服務識別碼，`Operational` 或 `Audit`
* **{entryId}**（路徑參數）: 日誌項目識別碼
* **@odata.id**: Entry URI
* **@odata.type**: 資源型別，如 `#LogEntry.v1_15_0.LogEntry`
* **Id**: 與 `{entryId}` 相同
* **Name**: 事件摘要標題
* **EntryType**: 項目類型，如 `Event`、`Oem`
* **Severity**: 嚴重程度，`OK` / `Warning` / `Critical`
* **Created**: 事件時間（ISO 8601，可含時區）
* **Message**: 人可讀訊息；可由日誌 **template** 與參數組合（未必含 `%1` 占位）
* **MessageId**: 訊息識別碼
* **MessageArgs**: 訊息參數陣列（Baseline **Recommended**）
* **EventGroupId**: 事件群組識別碼（Baseline **Recommended**）；固定 `Pelx.Operational` 或 `Pelx.Audit`
* **Oem**: 廠商擴充（可選）
  * **Pelx**:
    * **Operational**：`Action`（如 `Outlet.PowerControl`）、`OutletId`、`PowerState`（`On`／`Off`）
    * **Audit**：`Username`、`Ip`（登入／登出來源；**不含** `Action`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 日誌項目不存在

---

## 主機事件補同步（Pelx OEM）

設備事件平時寫入本機 **history**（``）；**統一中控／DCIM 主機**若因離線、重啟或上報失敗而缺少部分紀錄，可透過下列 Redfish API 依 **seq 流水號** 分批拉回。。

事件庫保存容量：**小容量 2000 筆**、**大容量 10000 筆**（循環覆寫）。

訊息 `template`／`args` 語意見 歷史訊息格式說明。

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices/Oem/Pelx/MaxSeq

查詢設備事件庫目前**最大流水號**，供主機決定 `LogSync` 的 `toSeq` 或判斷是否尚有未同步紀錄。

#### 回傳資料格式如下:

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Oem/Pelx/MaxSeq",
  "@odata.type": "#PelxLogMaxSeq.v1_0_0.PelxLogMaxSeq",
  "maxSeq": 5230
}
```

#### 欄位說明如下:

* **maxSeq**: 設備上最新一筆事件之 `seq`；尚無任何事件時為 **0**

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

---

### GET https://<host>/redfish/v1/Managers/{managerId}/LogServices/Oem/Pelx/LogSync?fromSeq={fromSeq}&toSeq={toSeq}&lang={lang}

依 **seq 區間** 拉回事件列，供主機補足缺失紀錄。單次**最多回傳 100 筆**（`seq` 遞增）；區間超過 100 筆時僅回傳自 `fromSeq` 起連續 100 筆，主機須分批再查。

#### 查詢參數

| 參數 | 必填 | 說明 |
|------|------|------|
| **fromSeq** | 是 | 查詢起始流水號（**含**） |
| **toSeq** | 是 | 查詢結束流水號（**含**）；須 `toSeq >= fromSeq`，且不建議大於設備 `maxSeq`（可先呼叫 `MaxSeq`） |
| **lang** | 是 | 語系：`zh-hant` 或 `en-us` |

單次回傳筆數：`min(toSeq - fromSeq + 1, 100)`。

#### 回傳資料格式如下:

```json
{
  "@odata.id": "/redfish/v1/Managers/1/LogServices/Oem/Pelx/LogSync",
  "@odata.type": "#PelxLogSync.v1_0_0.PelxLogSync",
  "fromSeq": 1001,
  "toSeq": 1100,
  "count": 100,
  "maxCount": 100,
  "deviceId": "device1",
  "columns": ["seq", "time", "level", "username", "template", "args", "alarmSeries", "msg"],
  "data": [
    {
      "seq": 1001,
      "time": 1627453800000,
      "level": 5,
      "username": "admin",
      "template": "highWarningAlarm",
      "args": "{\"iAValue\":30,\"iName\":\"室內溫度\",\"iUnit\":\"°C\",\"iValue\":50.0}",
      "alarmSeries": [
        { "time": 1634114700, "value": 5 }
      ],
      "msg": "[溫濕度1]濕度回覆正常[59%]"
    }
  ]
}
```

#### 欄位說明如下:

* **fromSeq** / **toSeq**: 本次請求之查詢區間（與查詢參數相同）
* **count**: 本次實際回傳筆數
* **maxCount**: 單次上限，固定 **100**
* **deviceId**: 設備識別（與 history 回傳一致）
* **columns**: `data` 各列欄位順序
* **data**: 事件列陣列（`seq` 遞增）；`msg` 為依 `lang` 組出之顯示文字

#### 主機補足缺失記錄（建議流程）

1. 主機保存該設備之同步游標 `syncSeq`（已**連續**同步到的最後 seq）。
2. **`GET .../MaxSeq`** 取得設備 `maxSeq`。
3. 若 `syncSeq < maxSeq`，以 **`GET .../LogSync`** 分批拉取，例如 `fromSeq = syncSeq + 1`、`toSeq = min(fromSeq + 99, maxSeq)`，直到追上 `maxSeq`。
4. 若主機 seq **中間不連續**，對缺口另行指定 `fromSeq`／`toSeq` 補齊。
5. 寫入主機後更新 `syncSeq`。

#### curl 範例

```bash
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/Managers/1/LogServices/Oem/Pelx/MaxSeq

curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/Managers/1/LogServices/Oem/Pelx/LogSync?fromSeq=1001&toSeq=1100&lang=zh-hant'
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常（含區間內 0 筆，`count` 為 0）
400   | 參數錯誤（如 `toSeq < fromSeq`）
401   | 未認證

---

# 歷史趨勢（TelemetryService）

數值趨勢、量測歷史（圖表）使用 `TelemetryService`。與 `EventService`（目前告警）、`LogServices`（操作 Log）不同，本節提供時間序列量測。

| 需求 | 入口 |
|------|------|
| DMTF 趨勢圖、批量時序（依 `reportId`） | `MetricReportDefinitions`、`MetricReports/{reportId}` |
| **主機補同步分鐘統計**（依 `addr`、時間區間） | `.../Oem/Pelx/RollupRange/{addr}`、`.../Oem/Pelx/InterfaceRollup/{addr}`（見下文） |

**批量讀值**：DMTF 設計上，`MetricReport` 的 **`MetricValues` 陣列**即為「一次 HTTP 回應取得多筆量測」的標準機制——整合方只需 `GET .../MetricReports/{id}`，即可取得該報告定義下、一段時間內的多筆 `MetricId`／`MetricValue`／`Timestamp`（例如多個插座電流、多路進線電壓的歷史曲線）。詳見 「總覽與合規」章節 — 一次回應多筆資料。

探索時須依 Service Root 的 `TelemetryService` 連結與 `Members` 走訪，勿猜 URL。`{addr}` 為週邊介面位址（與 `Oem/Pelx/Interfaces/{addr}` 相同字串）。

### MetricReportDefinition、MetricReport、MetricDefinition 的區別

| 資源 | 用途 | 典型問題 |
|------|------|----------|
| **MetricReportDefinition** | 報告**如何產生**（週期、包含哪些 Metric、寫入哪份 Report） | 「多久取樣一次？」 |
| **MetricReport** | **已產出**的歷史量測序列（`MetricValues`） | 「過去 24 小時電壓曲線？」 |
| **MetricDefinition** | 單一 Metric 的**語意**（單位、型別、物理意義） | 「這個值單位是 V 還是 A？」 |

建議流程：`MetricReportDefinitions`（或 `MetricReports` 內連結）→ `MetricReports/{id}` 取資料；需單位／型別時再查 `MetricDefinitions/{metricId}`。

### 產品預設（MetricReports）

本產品 **`MetricReports`** 預設供第三方 DCIM 趨勢圖；與下方 **Pelx OEM `InterfaceRollup`** 分工，**不併入同一端點**（見下文 OEM 章節）。

| 項目 | 預設值 | 說明 |
|------|--------|------|
| **`RecurrenceInterval`** | **`PT1M`** | 每 **1 分鐘**一筆；配合 DCIM 輪詢 ≥5 秒，較 `PT5M` 更適合短期趨勢 |
| **`CollectionDuration`** | **`PT1M`** | 與取樣週期一致 |
| **`CollectionFunction`** | **`Average`** | 單一 `MetricValue` 為週期內平均值 |
| **`AppendLimit`** | **`120`** | 報告緩衝最多 **120** 筆 ≈ **2 小時**（`PT1M` 時） |
| **`ReportUpdates`** | **`AppendWrapsWhenFull`** | 滿載後循環覆寫最舊資料 |
| **時間過濾** | OData **`$filter`** on **`Timestamp`** | 須 Service Root 宣告 `FilterQuery`（見 探索與識別）；**勿**使用非標準 `startTime`／`endTime` query |

| 對照 | **`MetricReports`** | **`InterfaceRollup`**（OEM） |
|------|---------------------|------------------------------|
| 用途 | 標準 DCIM 趨勢 | 主機補件、`avg`／`max`／`min` |
| 設備緩衝 | **120 筆**（≈2h） | **1500 筆** `1min`（≈25h，見 history） |
| 查詢 | `$filter`（ISO 8601） | `startTime`／`endTime`（Unix 秒）、`by` |
| 單次 GET 上限 | 整份緩衝（≤`AppendLimit`） | `by=1min` 最多 **120** 筆 |

### GET https://<host>/redfish/v1/TelemetryService

Telemetry 服務根資源，由此探索 `MetricReportDefinitions`、`MetricReports`、`MetricDefinitions` 等子集合。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService",
  "@odata.type": "#TelemetryService.v1_3_0.TelemetryService",
  "Id": "TelemetryService",
  "Name": "Telemetry Service",
  "ServiceEnabled": true,
  "MetricReportDefinitions": {
    "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions"
  },
  "MetricReports": {
    "@odata.id": "/redfish/v1/TelemetryService/MetricReports"
  },
  "MetricDefinitions": {
    "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions"
  },
  "Triggers": {
    "@odata.id": "/redfish/v1/TelemetryService/Triggers"
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 資源 URI，固定 `/redfish/v1/TelemetryService`
* **@odata.type**: 資源型別，如 `#TelemetryService.v1_3_0.TelemetryService`
* **Id**: 資源識別碼，固定 `TelemetryService`
* **Name**: 顯示名稱
* **ServiceEnabled**: Telemetry 服務是否啟用
* **MetricReportDefinitions**: 報告定義集合連結（描述如何週期性產出報告）
  * **@odata.id**: `/redfish/v1/TelemetryService/MetricReportDefinitions`
* **MetricReports**: 已產出之報告集合連結
  * **@odata.id**: `/redfish/v1/TelemetryService/MetricReports`
* **MetricDefinitions**: Metric 定義集合連結
  * **@odata.id**: `/redfish/v1/TelemetryService/MetricDefinitions`
* **Triggers**: 觸發條件集合連結（可選）
  * **@odata.id**: `/redfish/v1/TelemetryService/Triggers`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/TelemetryService/Triggers

觸發條件集合（選用；若 `TelemetryService` 暴露 `Triggers` 連結，**必須**含 `@odata.type`）。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/Triggers",
  "@odata.type": "#TriggerCollection.TriggerCollection",
  "Members": [],
  "Members@odata.count": 0
}
```

若尚未實作觸發條件，可回傳空集合；勿省略 `@odata.type`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/TelemetryService/MetricReports

已產出的 Metric 報告集合。每份報告含一段時間內的量測值序列，適合趨勢圖。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricReports",
  "@odata.type": "#MetricReportCollection.MetricReportCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/TelemetryService/MetricReports/VoltageA"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 集合 URI，固定 `/redfish/v1/TelemetryService/MetricReports`
* **@odata.type**: 集合型別
* **Members**: 報告連結陣列
  * **@odata.id**: 單一報告 URI，如 `.../MetricReports/VoltageA`
* **Members@odata.count**: 報告數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/TelemetryService/MetricReports/{reportId}

單一 Metric 報告，含歷史量測值陣列。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricReports/VoltageA",
  "@odata.type": "#MetricReport.v1_4_0.MetricReport",
  "Id": "VoltageA",
  "Name": "Infeed1 Voltage History",
  "MetricReportDefinition": {
    "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions/VoltageA"
  },
  "MetricValues": [
    {
      "MetricId": "VoltageA",
      "MetricValue": "113.2",
      "Timestamp": "2026-06-10T08:00:00Z",
      "MetricProperty": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageA"
    },
    {
      "MetricId": "VoltageA",
      "MetricValue": "113.5",
      "Timestamp": "2026-06-10T08:01:00Z",
      "MetricProperty": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageA"
    },
    {
      "MetricId": "VoltageA",
      "MetricValue": "114.0",
      "Timestamp": "2026-06-10T08:02:00Z",
      "MetricProperty": "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageA"
    }
  ]
}
```

未帶查詢參數時，回傳該報告緩衝內**全部** `MetricValues`（最多 **`AppendLimit`** 筆，預設 **120**）。

#### 查詢參數（`$filter`）

依 DMTF 慣例，以 OData **`$filter`** 過濾 `MetricValues` 的 **`Timestamp`**（ISO 8601 UTC）。須 Service Root **`ProtocolFeaturesSupported.FilterQuery`** 為 `true`。

| 參數 | 說明 |
|------|------|
| **`$filter`** | 例如 `Timestamp ge 2026-06-10T07:00:00Z`（**含**該時刻起）；可組合 `and Timestamp le ...` 指定上界 |

```bash
# 自某時刻起的分鐘趨勢（預設 PT1M）
curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/MetricReports/VoltageA?$filter=Timestamp%20ge%202026-06-10T07:00:00Z'
```

> **勿**在 `MetricReports` 使用 `startTime`／`endTime` query（非 DMTF 標準）。主機補件、需 `avg`／`max`／`min` 或 `by=1h`／`1d` 切換時，請用 **`InterfaceRollup`**（見下文）。

`$filter` 無符合資料時，`MetricValues` 可為空陣列 `[]`；結構仍為完整 `MetricReport` 資源。

#### 欄位說明如下:

* **{reportId}**（路徑參數）: 報告識別碼，通常與對應 `MetricReportDefinition`、`MetricDefinition` 的 `Id` 相同（如 `VoltageA`）
* **@odata.id**: 報告 URI
* **@odata.type**: 資源型別，如 `#MetricReport.v1_4_0.MetricReport`
* **Id**: 與 `{reportId}` 相同
* **Name**: 報告顯示名稱
* **MetricReportDefinition**: 對應之報告定義連結
  * **@odata.id**: 報告定義 URI，如 `.../MetricReportDefinitions/VoltageA`
* **MetricValues**: 歷史量測值陣列；**一次回應可含多筆讀值**（同一 Metric 的多時間點，或報告定義含多個 Metric 時的多種量測）
  * **MetricId**: Metric 識別碼
  * **MetricValue**: 量測值（字串，依 Metric 型別解析）
  * **Timestamp**: 取樣時間（ISO 8601 UTC）
  * **MetricProperty**: 對應即時感測資源 URI（如 RackPDU Sensor）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 報告不存在

### GET https://<host>/redfish/v1/TelemetryService/MetricReportDefinitions

報告定義集合，描述各歷史報告的產生方式（取樣週期、包含的 Metric、對應 Sensor 等）。`{definitionId}` 通常與 `MetricReports/{reportId}`、`MetricDefinitions/{metricId}` 使用相同識別碼（如 `VoltageA`）。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions",
  "@odata.type": "#MetricReportDefinitionCollection.MetricReportDefinitionCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions/VoltageA"
    },
    {
      "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions/CurrentA"
    }
  ],
  "Members@odata.count": 2
}
```

#### 欄位說明如下:

* **@odata.id**: 集合 URI，固定 `/redfish/v1/TelemetryService/MetricReportDefinitions`
* **@odata.type**: 集合型別
* **Members**: 報告定義連結陣列
  * **@odata.id**: 單一定義 URI，如 `.../MetricReportDefinitions/VoltageA`
* **Members@odata.count**: 定義數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/TelemetryService/MetricReportDefinitions/{definitionId}

單一報告定義，說明該歷史報告如何從 Sensor 週期性彙整寫入 `MetricReports`。 rollup 設定。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricReportDefinitions/VoltageA",
  "@odata.type": "#MetricReportDefinition.v1_3_0.MetricReportDefinition",
  "Id": "VoltageA",
  "Name": "Infeed1 Voltage History",
  "MetricReportDefinitionEnabled": true,
  "MetricReportDefinitionType": "Periodic",
  "Schedule": {
    "RecurrenceInterval": "PT1M"
  },
  "ReportActions": [
    "LogToMetricReports"
  ],
  "ReportUpdates": "AppendWrapsWhenFull",
  "AppendLimit": 120,
  "Metrics": [
    {
      "MetricId": "VoltageA",
      "MetricProperties": [
        "/redfish/v1/PowerEquipment/RackPDUs/1/Sensors/VoltageA"
      ],
      "CollectionFunction": "Average",
      "CollectionDuration": "PT1M"
    }
  ],
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  }
}
```

#### 欄位說明如下:

* **{definitionId}**（路徑參數）: 報告定義識別碼，如 `VoltageA`、`Outlet1Current`
* **@odata.id**: 定義 URI
* **@odata.type**: 資源型別，如 `#MetricReportDefinition.v1_3_0.MetricReportDefinition`
* **Id**: 與 `{definitionId}` 相同
* **Name**: 顯示名稱
* **MetricReportDefinitionEnabled**: 是否啟用此報告定義
* **MetricReportDefinitionType**: 定義類型，本產品固定 `Periodic`（週期性）
* **Schedule**: 排程物件
  * **RecurrenceInterval**: 取樣週期（ISO 8601 duration）；本產品預設 **`PT1M`**（1 分鐘）
* **ReportActions**: 報告動作陣列，固定含 `LogToMetricReports`（寫入 `MetricReports`）
* **ReportUpdates**: 報告更新策略；本產品預設 **`AppendWrapsWhenFull`**（滿載循環覆寫）
* **AppendLimit**: 報告最多累積筆數；本產品預設 **`120`**（`PT1M` 時約 **2 小時**緩衝）。當 `ReportUpdates` 為 `AppendWrapsWhenFull` 或 `AppendStopsWhenFull` 時，DMTF 要求提供此欄位
* **Metrics**: 本報告包含的 Metric 陣列
  * **MetricId**: Metric 識別碼，對應 `MetricDefinitions/{metricId}`
  * **MetricProperties**: 來源感測資源 URI 陣列（通常為 RackPDU `Sensors/{id}`）
  * **CollectionFunction**: 彙整函數；本產品預設 **`Average`**
  * **CollectionDuration**: 彙整時間窗（ISO 8601 duration）；本產品預設 **`PT1M`**
* **Status**: 運作與健康狀態物件
  * **State**: 運作狀態，如 `Enabled`
  * **Health**: 健康狀態，`OK` 表示定義正常

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 定義不存在

### GET https://<host>/redfish/v1/TelemetryService/MetricDefinitions

Metric 定義集合，描述各 Metric 的單位、資料型別與來源屬性。

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions",
  "@odata.type": "#MetricDefinitionCollection.MetricDefinitionCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/VoltageA"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 集合 URI
* **Members**: 定義連結陣列
  * **@odata.id**: 單一定義 URI
* **Members@odata.count**: 定義數量

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/TelemetryService/MetricDefinitions/{metricId}

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/VoltageA",
  "@odata.type": "#MetricDefinition.v1_3_0.MetricDefinition",
  "Id": "VoltageA",
  "Name": "Infeed1 Voltage",
  "MetricType": "Numeric",
  "MetricDataType": "Decimal",
  "Units": "V",
  "Implementation": "PhysicalSensor",
  "PhysicalContext": "VoltageRegulator",
  "CalculationAlgorithm": "Average",
  "CalculationTimeInterval": "PT1M"
}
```

#### 欄位說明如下:

* **{metricId}**（路徑參數）: Metric 定義識別碼
* **@odata.id**: 定義 URI
* **Id**: 與 `{metricId}` 相同
* **Name**: 顯示名稱
* **MetricType**: Metric 類型，如 `Numeric`、`String`、`Discrete`
* **MetricDataType**: 資料型別，如 `Integer`、`Decimal`
* **Units**: 單位，如 `W`、`V`、`A`、`C`
* **Implementation**: 實作方式，如 `PhysicalSensor`
* **PhysicalContext**: 物理情境，如 `PowerSupply`、`Temperature`
* **CalculationAlgorithm**: 彙整演算法，如 `Average`、`Maximum`
* **CalculationTimeInterval**: 取樣間隔（ISO 8601 duration）；本產品預設 **`PT1M`**（1 分鐘）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 定義不存在

---

## 主機統計補同步（Pelx OEM）

設備平時以分鐘／時／日／月統計並上送主機。若主機因離線、重啟或上送失敗而缺少部分紀錄，可透過下列 Redfish API 依 **介面位址（`addr`）與時間區間** 分批補齊。

### 從 Mains／Outlet 取得 addr（不需專用 Rollup API）

本節 API 以 **`addr`** 為路徑參數，**不**在 `Mains`／`Outlets` 上另設專用 Rollup 端點，**亦不併入** DMTF **`MetricReports`**（標準趨勢用 `$filter` + `PT1M`／`AppendLimit` 120，見上文）。進線（power）與插座等各有多個量測介面（電壓、電流、功率…），補件須針對**單一量測**之 `addr`；整合方自 OCP 資源讀取 **`Oem.Pelx.Interfaces`**（三相進線用 **`InterfaceGroups`**）即可對照。

```
GET .../RackPDUs/1/Mains/{mainId}        # 進線；見「電力與配電」章節
  或 .../RackPDUs/1/Outlets/{outletId}  # 插座；見「插座」章節
  → Oem.Pelx.Interfaces.{量測名}.@odata.id
  → 路徑最後一段即 addr（如 AI2103）
  → GET .../RollupRange/{addr}
  → GET .../InterfaceRollup/{addr}?startTime=&endTime=&by=
```

| 欲補之統計 | 讀取 `Interfaces` 的 key |
|-----------|--------------------------|
| 電壓 | `Voltage` |
| 電流 | `CurrentAmps` |
| 功率 | `PowerWatts` |
| 電能／瓦時 | `EnergykWh` |
| 開關狀態 | `PowerState`（`DO...`，通常無 rollup） |

進線 JSON 範例見 電力與配電；插座範例見 插座。亦可 `GET .../Oem/Pelx/Interfaces/{addr}`，以 **`peripheralAlias`**（`INFEED`／`OUTLET`）、**`elementId`** 核對是否為目標路數。

#### 範例（插座電流）

```bash
# 1) 從 Outlet 取得電流介面 addr
curl -sk -u dcim-read:'<password>' \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1
# → Oem.Pelx.Interfaces.CurrentAmps → .../Interfaces/AI00102

# 2) 查保存區間並補件
curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/Oem/Pelx/RollupRange/AI00102'

curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/Oem/Pelx/InterfaceRollup/AI00102?startTime=1627453800&endTime=1627461000&by=1min'
```

### GET https://<host>/redfish/v1/TelemetryService/Oem/Pelx/RollupRange/{addr}

查詢該週邊介面在各時間聚合粒度下，設備目前已保存資料的**最早**與**最後**一筆時間；供 UI 設定查詢範圍，或供主機判斷 `InterfaceRollup` 補件時設備端可拉回之區間。

#### 回傳資料格式如下:

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/Oem/Pelx/RollupRange/AI2101",
  "@odata.type": "#PelxRollupRange.v1_0_0.PelxRollupRange",
  "addr": "AI2101",
  "Interface": {
    "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
  },
  "earliest": {
    "1min": 1625000000,
    "1h": 1625100000,
    "1d": 1626000000,
    "1mo": 1630000000
  },
  "latest": {
    "1min": 1625100000,
    "1h": 1626000000,
    "1d": 1630000000,
    "1mo": 1631000000
  }
}
```

#### 欄位說明如下:

* **{addr}**（路徑參數）: 週邊介面位址
* **addr**: 與路徑參數相同
* **Interface**: 對應 `Oem/Pelx/Interfaces/{addr}` 連結
* **earliest** / **latest**: 各粒度最早／最後資料時間（Unix **秒**）
  * **1min**: 1 分鐘
  * **1h**: 1 小時
  * **1d**: 1 天
  * **1mo**: 1 個月

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | **addr** 不存在

---

### GET https://<host>/redfish/v1/TelemetryService/Oem/Pelx/InterfaceRollup/{addr}?startTime={startTime}&endTime={endTime}&by={by}&fill={fill}

依 **時間區間** 拉回週邊歷史統計，供主機補足缺失之分鐘級資料，或 UI 查詢趨勢。單次 **`by=1min`** 時**最多回傳 120 筆**（`time` 遞增）；區間超過 120 筆時僅回傳自 `startTime` 起連續 120 筆，主機須以本批最末 `time + 60` 作為下一批 `startTime` 分批再查。

#### 查詢參數

| 參數 | 必填 | 說明 |
|------|------|------|
| **startTime** | 是 | 查詢起始時間，Unix **秒**（**含**） |
| **endTime** | 是 | 查詢結束時間，Unix **秒**（**含**）；須 `endTime >= startTime` |
| **by** | 是 | 時間聚合單位：`1min`、`1h`、`1d`、`1mo` |
| **fill** | 否 | `null`：依 `by` 把區間內**每一時間格**都回一筆，無採樣則值為 `null`（趨勢圖用）。省略時只回實際有寫入的格（稀疏，供主機同步）。缺口多為設備重啟或關機，**不要**用上一筆或內插填值 |

#### by 欄位值

| by | 說明 | 設備保存時間 | 設備保存筆數 | 單次回傳上限 |
| --- | --- | --- | --- | --- |
| 1min | 1 分鐘 | 25 小時 | 1500 筆 | **120** 筆 |
| 1h | 1 小時 | 80 天 | 1920 筆 | — |
| 1d | 1 天 | 1125 天 | 1125 筆 | — |
| 1mo | 1 個月 | 3650 天 | 120 筆 | — |

單次回傳筆數（`by=1min`）：`min(符合區間之筆數, 120)`。

#### 回傳資料格式如下:

```json
{
  "@odata.id": "/redfish/v1/TelemetryService/Oem/Pelx/InterfaceRollup/AI2101",
  "@odata.type": "#PelxInterfaceRollup.v1_0_0.PelxInterfaceRollup",
  "addr": "AI2101",
  "by": "1min",
  "startTime": 1627453800,
  "endTime": 1627461000,
  "count": 3,
  "agg": "sum",
  "positive": true,
  "Interface": {
    "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
  },
  "data": [
    { "time": 1627453800, "avg": 50.0, "max": 51.2, "min": 49.8 },
    { "time": 1627454100, "avg": 50.1, "max": 51.3, "min": 49.9 },
    { "time": 1627454400, "avg": 50.2, "max": 51.4, "min": 50.0 }
  ]
}
```

#### 欄位說明如下:

* **{addr}**（路徑參數）: 週邊介面位址
* **addr** / **by** / **startTime** / **endTime**: 與請求參數一致（回顯）
* **count**: 本批 `data` 筆數
* **agg**: 聚合方式，`sum`（加總）或 `avg`（平均）
* **positive**: 是否為正數量測
* **Interface**: 對應 `Oem/Pelx/Interfaces/{addr}` 連結
* **data**: 統計列陣列
  * **time**: Unix **秒** 時間戳
  * **avg** / **max** / **min**: 平均值、最大值、最小值（`agg=sum` 時語意同歷史服務彙總）；**`fill=null` 且該格無採樣時為 `null`**

趨勢圖請帶 **`fill=null`**，前端遇 `null` **斷線**。主機補資料**不要**帶 `fill`，亦勿把 `null` 列寫入主機。

#### 主機補足缺失資料（建議流程）

設備平時每分鐘上送分鐘統計至主機。主機若缺少部分紀錄，可搭配 **`RollupRange`** 得知設備保存區間後，再以本 API 依時間區間自設備拉回 **`by=1min`** 資料併入主機。

1. 主機保存該設備（＋週邊 **addr**）已**連續**同步到的最後分鐘 **`syncMinTime`**（Unix **秒**，對齊整分鐘）。
2. 對需同步之 **addr** 呼叫 **`GET .../RollupRange/{addr}`**，以設備 **`latest.1min`** 與主機尾端比對，找出缺口起訖。
3. 若主機尾端落後設備，以本 API 分批拉回，例如 **`by=1min`**、`startTime = syncMinTime + 60`、`endTime = min(startTime + 7199, latest.1min)`，直到追上 **`latest.1min`**。**一次只處理一個設備、一個 addr**。**不要**帶 `fill=null`。
4. 若主機 **time 中間不連續**，對該缺口區間另行指定 **`startTime`／`endTime`** 再查。
5. 將回傳 **`data`** 各列加上 **`addr`**、**`type`** 後，以與設備上送相同之合併邏輯寫入主機；寫入格式仍以 history **`POST /interfaces/min`** 為準。
6. 寫入主機後更新 **`syncMinTime`**；補入近 **7 天**窗口內資料後，主機可重算 **`1h`／`1d`／`1mo`** rollup（若主機實作）。

> **保留限制**：設備端 **`1min`** 約保留 **25 小時**，超出此窗口之缺口**無法**自設備補回。

#### 範例

```bash
curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/Oem/Pelx/RollupRange/AI2101'

curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/Oem/Pelx/InterfaceRollup/AI2101?startTime=1627453800&endTime=1627461000&by=1min'

# 趨勢圖：缺採樣的時間格回 null
curl -sk -u dcim-read:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/Oem/Pelx/InterfaceRollup/AI2101?startTime=1627453800&endTime=1627457400&by=1min&fill=null'
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 參數缺漏、**by**／**fill** 不支援或時間區間不合法
401   | 未認證
404   | **addr** 不存在

---

# 韌體與組態（UpdateService）

韌體更新與組態（cfg）管理 API 遵循 DMTF `UpdateService` 規範。本節包含**兩條獨立流程**，請勿混用：

| 流程 | API | 說明 |
|------|-----|------|
| **韌體更新** | `upload`、`SimpleUpdate`、`FirmwareInventory` | 替換整機設備映像（`.bin`），完成後重啟 |
| **組態更新** | `Oem/Pelx/Configuration` 的 Download／Upload | 單獨下載或還原組態檔（`.cfg`），與韌體更新無關 |

兩者分開儲存、分開操作：**更新韌體不會改動組態**；**上傳組態不會觸發韌體更新**。

### 權限

韌體更新與組態 Download／Upload 對應 Web **工程模式 → 韌體更新**。**須 Administrator**（工程模式；`403` 若為 Operator／ReadOnly）：

* `POST .../UpdateService/upload`
* `POST .../Actions/UpdateService.SimpleUpdate`
* `POST .../Oem/Pelx/Configuration/Actions/PelxConfiguration.Upload`
* `POST .../Oem/Pelx/Configuration/Actions/PelxConfiguration.Download`（觸發匯出）

`GET` 韌體版本、Task 狀態依預設（ReadOnly 以上）。詳見 認證「文件撰寫慣例」。

> **上傳格式**：`UpdateService/upload` 與 `PelxConfiguration.Upload` **僅支援** `POST` + `Content-Type: application/octet-stream`。**不支援** `multipart/form-data`（回 `400`）。`MultipartHttpPushUri` 為 Redfish Schema 欄位名稱，實際請求請用 octet-stream 本體。

### 韌體更新

**對象為整台設備映像（device image）**：上傳或遠端拉取的 `.bin` 為完整設備韌體包，更新後設備會重啟並以新映像運行。PDU 僅有一組可更新映像，無 BIOS／BMC 分離更新。映像版本對應 `Managers/1.FirmwareVersion`（`Managers/1.FirmwareVersion`）。

### 組態更新

**組態以獨立檔案整包更新**：透過 `PelxConfiguration.Download` 匯出、`PelxConfiguration.Upload` 還原。還原後設備參數（插座名稱、閾值等）以檔案內容為準；此流程不替換設備映像。個別即時參數亦可透過各資源 `PATCH`（如 ATS `Parameters`），與整包 cfg 互補。

### GET https://<host>/redfish/v1/UpdateService

查詢更新服務能力與可用 Action。

```json
{
  "@odata.id": "/redfish/v1/UpdateService",
  "@odata.type": "#UpdateService.v1_14_0.UpdateService",
  "Id": "UpdateService",
  "Name": "Update Service",
  "ServiceEnabled": true,
  "FirmwareInventory": {
    "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory"
  },
  "Actions": {
    "#UpdateService.SimpleUpdate": {
      "target": "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate",
      "@Redfish.ActionInfo": "/redfish/v1/UpdateService/SimpleUpdateActionInfo"
    }
  },
  "Oem": {
    "Pelx": {
      "Configuration": {
        "@odata.id": "/redfish/v1/UpdateService/Oem/Pelx/Configuration"
      }
    }
  },
  "MultipartHttpPushUri": "/redfish/v1/UpdateService/upload",
  "HttpPushUriTargets": [
    "/redfish/v1/Chassis/1"
  ]
}
```

#### 欄位說明如下:

* **@odata.id**: 更新服務 URI，固定 `/redfish/v1/UpdateService`
* **@odata.type**: 資源型別，固定 `#UpdateService.v1_14_0.UpdateService`
* **Id**: 資源識別碼，固定 `UpdateService`
* **Name**: 顯示名稱，固定 `Update Service`
* **ServiceEnabled**: 是否允許韌體更新，`true` 表示可用
* **FirmwareInventory**: 韌體清單集合連結
  * **@odata.id**: `/redfish/v1/UpdateService/FirmwareInventory`
* **Actions**: 可用操作
  * **#UpdateService.SimpleUpdate**: 遠端 URI 簡易更新
    * **target**: Action URI（`.../Actions/UpdateService.SimpleUpdate`）
    * **@Redfish.ActionInfo**: 參數說明資源 URI
* **Oem**: 廠商擴充
  * **Pelx**: Pelx OEM 命名空間
    * **Configuration**: 組態單獨下載／上傳資源連結（與韌體 `upload` 無關）
      * **@odata.id**: `/redfish/v1/UpdateService/Oem/Pelx/Configuration`
* **MultipartHttpPushUri**: 本地上傳 URI，固定 `.../upload`（Redfish Schema 欄位名；**僅接受** `application/octet-stream`，不支援 multipart）
* **HttpPushUriTargets**: 允許的更新目標，整機映像固定 `["/redfish/v1/Chassis/1"]`（代表整台 PDU）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足

### GET https://<host>/redfish/v1/UpdateService/FirmwareInventory

```json
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory",
  "@odata.type": "#SoftwareInventoryCollection.SoftwareInventoryCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Image"
    }
  ],
  "Members@odata.count": 1
}
```

#### 欄位說明如下:

* **@odata.id**: 韌體清單集合 URI
* **Members**: 韌體／映像項目連結陣列
  * **@odata.id**: 單一項目 URI（PDU 固定 `Image`，整機設備映像）
* **Members@odata.count**: 項目數，PDU 為 `1`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/UpdateService/FirmwareInventory/Image

查詢目前安裝的整機設備映像版本（對應 `Managers/1.FirmwareVersion`、`Managers/1.FirmwareVersion`）。

```json
{
  "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/Image",
  "@odata.type": "#SoftwareInventory.v1_10_0.SoftwareInventory",
  "Id": "Image",
  "Name": "Device Firmware Image",
  "Version": "1.60.3",
  "Updateable": true,
  "Status": {
    "State": "Enabled",
    "Health": "OK"
  },
  "RelatedItem": [
    {
      "@odata.id": "/redfish/v1/Chassis/1"
    },
    {
      "@odata.id": "/redfish/v1/Managers/1"
    }
  ]
}
```

#### 欄位說明如下:

* **@odata.id**: 設備映像項目 URI
* **Id**: 固定 `Image`
* **Name**: 顯示名稱，整機設備韌體映像
* **Version**: 目前映像版本，與 `Managers/1.FirmwareVersion` 相同
* **Updateable**: 是否允許更新
* **Status**: 狀態物件
  * **State**: `Enabled` 表示正常
  * **Health**: `OK` 表示無異常
* **RelatedItem**: 關聯資源（整台設備）
  * **@odata.id**: 機箱 URI（`/redfish/v1/Chassis/1`）
  * **@odata.id**: 管理控制器 URI（`/redfish/v1/Managers/1`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 資源不存在

### GET https://<host>/redfish/v1/UpdateService/SimpleUpdateActionInfo

`UpdateService.SimpleUpdate` 的參數定義。

```json
{
  "@odata.id": "/redfish/v1/UpdateService/SimpleUpdateActionInfo",
  "@odata.type": "#ActionInfo.v1_4_2.ActionInfo",
  "Id": "SimpleUpdate",
  "Name": "Simple Update Action Info",
  "Parameters": [
    {
      "Name": "ImageURI",
      "Required": true,
      "DataType": "String"
    },
    {
      "Name": "TransferProtocol",
      "Required": false,
      "DataType": "String",
      "AllowableValues": ["HTTP", "HTTPS", "FTP"]
    },
    {
      "Name": "Targets",
      "Required": false,
      "DataType": "StringArray"
    }
  ]
}
```

#### 欄位說明如下:

* **@odata.id**: ActionInfo 資源 URI，固定 `/redfish/v1/UpdateService/SimpleUpdateActionInfo`
* **@odata.type**: 資源型別，固定 `#ActionInfo.v1_4_2.ActionInfo`
* **Id**: Action 識別碼，固定 `SimpleUpdate`
* **Name**: 顯示名稱
* **Parameters**: `UpdateService.SimpleUpdate` 可接受的參數定義陣列
  * **Name**: 參數名稱
  * **Required**: 是否必填（`true`／`false`）
  * **DataType**: 參數型別（`String`、`StringArray` 等）
  * **AllowableValues**: 允許值清單（僅部分參數有）
  * **ImageURI**（必填）: 遠端設備映像完整 URL（含檔名）；`POST .../SimpleUpdate` **唯一實際讀取**的參數，下載至暫存後套用
  * **TransferProtocol**（選填）: 傳輸協定提示，`HTTP`／`HTTPS`／`FTP`；PDU 整機映像，`POST` 時目前**未讀取**（固定更新整機）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### POST https://<host>/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate

自遠端檔案伺服器（HTTP／HTTPS／FTP）拉取**整機設備映像**並更新（遠端 Simple Update）。更新為非同步作業，成功回 `202` 並建立 Task；完成後設備重啟。

```json
{
  "ImageURI": "https://fileserver.example.com/firmware/pdu-image-1.60.4.bin",
  "TransferProtocol": "HTTPS",
  "Targets": [
    "/redfish/v1/Chassis/1"
  ],
  "@Redfish.OperationApplyTime": "Immediate"
}
```

#### 欄位說明如下:

* **ImageURI**: 設備映像檔完整 URL（含檔名），為整機 `.bin` 韌體包
* **TransferProtocol**: 傳輸協定，`HTTP`、`HTTPS` 或 `FTP`
* **Targets**: 更新目標；整機映像固定 `["/redfish/v1/Chassis/1"]`，亦可寫 `["/redfish/v1/UpdateService/FirmwareInventory/Image"]`
* **@Redfish.OperationApplyTime**: 套用時機，PDU 支援 `Immediate`（立即開始）

> 韌體更新僅替換設備映像，**不修改、不覆寫**使用者組態；無需也無 `PreserveConfig` 等參數。

#### 回傳資料

成功時回 `202 Accepted`，`Location` 標頭指向 Task URI，例如 `/redfish/v1/TaskService/Tasks/1`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
202   | 已接受，更新進行中
400   | 參數錯誤（URI 無效、協定不支援）
401   | 未認證
403   | 權限不足
409   | 已有更新進行中

### POST https://<host>/redfish/v1/UpdateService/upload

從本機上傳**整機設備映像**更新。請使用**`POST` + `application/octet-stream` + 映像本體**。

> **注意**
> * 必須使用 **POST**（不可用 GET；否則常見 `write EPIPE`）
> * **不支援** `multipart/form-data`（回 `400`）；請用 `application/octet-stream`

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/UpdateService/upload \
  -H "Content-Type: application/octet-stream" \
  --data-binary @dph_1u-1.4.10.swu
```

> `SimpleUpdate` 下載至同一暫存路徑後，亦走 `upgrade/apply`。

#### 欄位說明如下:

* **Body**（Mandatory）: 整機 `.swu` 映像二進位內容（`Content-Type: application/octet-stream`）

#### 回傳資料

成功時回 `202 Accepted`，`Location` 指向 Task；更新完成、設備重啟後可查 `FirmwareInventory/Image.Version` 或 `Managers/1.FirmwareVersion` 確認版本。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
202   | 已接受，更新進行中
400   | Content-Type 非 octet-stream、使用 multipart、或映像驗證失敗
401   | 未認證
403   | 權限不足
409   | 已有更新進行中
413   | 檔案過大

### GET https://<host>/redfish/v1/TaskService/Tasks

列出非同步任務（韌體更新等 `202` 回應所建立者）。

```json
{
  "@odata.id": "/redfish/v1/TaskService/Tasks",
  "@odata.type": "#TaskCollection.TaskCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/TaskService/Tasks/1" }
  ],
  "Members@odata.count": 1
}
```

### GET https://<host>/redfish/v1/TaskService/Tasks/{taskId}

查詢韌體更新等非同步任務進度（`SimpleUpdate`／`upload` 回 `202` 後使用）。

```json
{
  "@odata.id": "/redfish/v1/TaskService/Tasks/1",
  "@odata.type": "#Task.v1_7_2.Task",
  "Id": "1",
  "Name": "Device Image Update",
  "TaskState": "Running",
  "TaskStatus": "OK",
  "PercentComplete": 45,
  "StartTime": "2026-06-15T10:00:00+08:00",
  "Messages": [
    {
      "Message": "Writing device image",
      "MessageSeverity": "OK"
    }
  ]
}
```

#### 欄位說明如下:

* **{taskId}**（路徑參數）: 任務識別碼，由 `202` 回應 `Location` 取得
* **TaskState**: 任務狀態，`New`、`Running`、`Completed`、`Exception` 等
* **TaskStatus**: 整體狀態，`OK`、`Warning`、`Critical`
* **PercentComplete**: 完成百分比（0–100）
* **StartTime**: 開始時間（ISO 8601）
* **Messages**: 進度訊息陣列
  * **Message**: 說明文字
  * **MessageSeverity**: 嚴重程度

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 任務不存在

### GET https://<host>/redfish/v1/UpdateService/Oem/Pelx/Configuration

組態**單獨**備份／還原能力與 Action 入口。

```json
{
  "@odata.id": "/redfish/v1/UpdateService/Oem/Pelx/Configuration",
  "@odata.type": "#PelxConfiguration.v1_0_0.PelxConfiguration",
  "Id": "Configuration",
  "Name": "Pelx Device Configuration",
  "Actions": {
    "#PelxConfiguration.Download": {
      "target": "/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Download"
    },
    "#PelxConfiguration.Upload": {
      "target": "/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Upload"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 組態資源 URI
* **Id**: 固定 `Configuration`
* **Name**: 顯示名稱
* **Actions**: 可用操作
  * **#PelxConfiguration.Download**: 下載組態備份檔（唯讀匯出）
  * **#PelxConfiguration.Upload**: 上傳組態檔、**單獨還原**（不更新韌體映像）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足

### POST https://<host>/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Download

下載設備組態備份檔。請求 body 可為空物件 `{}`，或指定檔名：

```json
{
  "FileName": "pdu-backup.cfg"
}
```

#### 欄位說明如下:

* **FileName**: 建議檔名（可選）；未指定時伺服器以 `backup-YYYYMMDD-HHMMSS.cfg` 命名

#### 回傳資料

成功時回 `200`，`Content-Type: application/octet-stream`，`Content-Disposition: attachment; filename="pdu-backup.cfg"`，body 為組態二進位檔。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常，回傳備份檔
401   | 未認證
403   | 權限不足
500   | 備份失敗

### POST https://<host>/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Upload

**單獨上傳組態檔還原**。上傳後**立即回 202**，背景執行還原（不重傳本體）。僅覆寫設備參數，**不觸發韌體映像更新**。

請求與韌體上傳相同：**`POST` + `Content-Type: application/octet-stream` + 組態檔本體**。**不支援** `multipart/form-data`。Postman 請在 Headers 手動加上 `Content-Type: application/octet-stream`（僅選 binary 可能缺此 header）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
202   | 已接受，檔案已寫入暫存；還原於背景執行（重啟後生效）
400   | 暫存檔缺失、Content-Type 非 octet-stream，或使用 multipart
401   | 未認證
403   | 權限不足

> 還原為非同步作業，**先回 202** 再於背景完成；客戶端不應等待還原完成。檔案格式錯誤等問題不會在 202 階段回報。

### 操作範例（curl）

遠端 URI 更新設備映像：

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate \
  -H "Content-Type: application/json" \
  -d '{
    "ImageURI": "https://fileserver/firmware/pdu-image-1.60.4.bin",
    "TransferProtocol": "HTTPS",
    "Targets": ["/redfish/v1/Chassis/1"]
  }'
```

本地上傳設備映像（建議 octet-stream，）：

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/UpdateService/upload \
  -H "Content-Type: application/octet-stream" \
  --data-binary @dph_1u-1.4.10.swu
```

下載組態備份：

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Download \
  -o pdu-backup.cfg
```

上傳組態還原：

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/UpdateService/Oem/Pelx/Configuration/Actions/PelxConfiguration.Upload \
  -H "Content-Type: application/octet-stream" \
  --data-binary "@pdu-backup.cfg"
```

---

# 讀取流程建議

1. `POST /SessionService/Sessions` 建立 Session，保存 `X-Auth-Token`
2. `GET /redfish/v1` 探索資源連結（須含 `PowerEquipment`）
3. 讀取 `PowerEquipment/RackPDUs/{id}` → `Metrics` 取得彙總功率／能耗
4. 讀取 `Mains` → `Outlets` 取得配電狀態與插座控制
5. 批次控制：`RackPDUs/1/OutletGroups/{id}`（見 插座群組）
6. 讀取 `Chassis/1`（含 `Links.PowerDistribution`）與 `Thermal` 取得環境感測
7. 事件訂閱：`EventService/Subscriptions`（OCP 標準）；目前告警快照見 `EventService/Events`（Pelx）
8. 事件／Log 歷史：`Managers/1/LogServices` → `{logId}/Entries`
9. 網路設定：`Managers/1/EthernetInterfaces`、`NetworkProtocol`（NTP、SNMP 見 網路協定）
10. 韌體／組態：`UpdateService`（韌體）與 `Oem/Pelx/Configuration`（組態，獨立流程）
11. ATS：`PowerEquipment/TransferSwitches` → `Feeders`（見 ATS 轉換開關；設備支援 ATS 時）
12. 歷史量測：`TelemetryService`（見 歷史趨勢）
13. 非標準週邊（單點）：`Oem/Pelx/Interfaces`（見 OEM 介面）
14. **週邊結構盤點（一次取整樹）**：`Oem/Pelx/PeripheralTree`
15. **大量即時**：`GET /redfish/v1` 讀 `Oem.Pelx.MqttEndpoint` → MQTT 訂閱 `/updates/local`、`/update/local/#`（見 MQTT Discovery、第 11 章）
16. 工程組態（須 **Administrator**；依 `devinfo` 旗標出現）：`Oem/Pelx/SerialBuses`、`VNodes`、`HmiScreens`（含樣版匯出／載入）、`HmiImageLibraries`、`Automations`（見 Pelx 擴充）
17. 完成後 `DELETE /SessionService/Sessions/{id}` 登出

### 減少請求次數（一次回多筆）

| 場景 | 做法 | 範例 |
|------|------|------|
| 整機功率／能耗／負載 | 單一 **Metrics** 資源（OCP 必填） | `GET .../RackPDUs/1/Metrics` |
| 所有插座完整狀態 | **`$expand`**（須 `ExpandQuery` 支援） | `GET .../Outlets?$expand=.` |
| 歷史趨勢多筆讀值 | **`MetricReports`** 的 `MetricValues[]`（預設 **PT1M**、緩衝 **120** 筆） | `GET .../MetricReports/VoltageA` 或 `...?$filter=Timestamp ge ...` |
| 僅要成員 URI 列表 | Collection 或 **`$only`** | `GET .../Outlets` 或 `.../Outlets?$only` |

```bash
# 整機彙總（一次回 PowerWatts + EnergykWh + PowerLoadPercent）
curl -sk -u admin:'<password>' \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Metrics

# 展開所有插座（若服務支援 $expand）
curl -sk -u admin:'<password>' \
  'https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets?$expand=.'

# 歷史量測陣列（PT1M；可選 $filter）
curl -sk -u admin:'<password>' \
  https://<host>/redfish/v1/TelemetryService/MetricReports/VoltageA

curl -sk -u admin:'<password>' \
  'https://<host>/redfish/v1/TelemetryService/MetricReports/VoltageA?$filter=Timestamp%20ge%202026-06-10T07:00:00Z'
```

詳見 「總覽與合規」章節 — 一次回應多筆資料。

### curl 範例

建立 Session：

```bash
curl -u admin:password -X POST \
  https://<host>/redfish/v1/SessionService/Sessions
```

讀取插座 1（帶 Token）：

```bash
curl -H "X-Auth-Token: 7c3f8a2b9e1d4f6a8c0b2d4e6f8a0c2" \
  https://<host>/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1
```

對外請使用 `https://<host>/redfish/v1/...`。

### redfishtool 測試

建議以 [DMTF redfishtool](https://github.com/DMTF/redfishtool) 手動探查單一 API；合規與回歸測試請用 **OCP Interop Validator**（見下方）。

**安裝**

```bash
brew install pipx && pipx install redfishtool
# 或: pip install redfishtool
```

**手動查詢（HTTPS 443，對外設備）**

```bash
# Service Root
redfishtool.py -u admin -p 'admin123' -r 113.196.183.199:443 -S Always -A Basic \
  raw GET /redfish/v1

# 插座 1
redfishtool.py -u admin -p 'admin123' -r 113.196.183.199:443 -S Always -A Basic \
  raw GET /redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1

  raw GET /redfish/v1

# 設備映像版本
redfishtool.py -u admin -p 'admin123' -r 113.196.183.199:443 -S Always -A Basic \
  raw GET /redfish/v1/UpdateService/FirmwareInventory/Image
```

**Session 生命週期**（加 `-sssss` 可印出回應標頭，取得 `X-Auth-Token`）

```bash
redfishtool.py -u admin -p 'admin123' -r 113.196.183.199:443 -S Always -A Basic -sssss \
  raw POST /redfish/v1/SessionService/Sessions '{}'

redfishtool.py -r 113.196.183.199:443 -S Always \
  -H '{"X-Auth-Token":"<token>"}' \
  raw GET /redfish/v1/SessionService/Sessions/<sessionId>

redfishtool.py -r 113.196.183.199:443 -S Always \
  -H '{"X-Auth-Token":"<token>"}' \
  raw DELETE /redfish/v1/SessionService/Sessions/<sessionId>
```

**OCP Interop Validator（合規驗證，建議）**

合規與回歸測試以 [DMTF Redfish Interop Validator](https://github.com/DMTF/Redfish-Interop-Validator) 搭配 OCP Profile JSON 為準（見上文「OCP Rack PDU Profile 對照」）。

```bash
pipx install redfish-interop-validator
git clone https://github.com/opencomputeproject/HWMgmt-OCP-Profiles.git ~/HWMgmt-OCP-Profiles

rf_interop_validator \
  -r https://<host> \
  -u admin -p '<password>' \
  --authtype Session \
  --required_profiles_dir ~/HWMgmt-OCP-Profiles \
  ~/HWMgmt-OCP-Profiles/RackAndPower/OCPRackPDU.v1_0_0.json

# OCP Baseline Hardware Management（Service Baseline 延伸）
rf_interop_validator \
  -r https://<host> \
  -u admin -p '<password>' \
  --authtype Session \
  --required_profiles_dir ~/HWMgmt-OCP-Profiles \
  ~/HWMgmt-OCP-Profiles/OCPBaselineHardwareManagement.v1_1_1.json

open logs/InteropHtmlLog_*.html
```

> **RBAC 權限矩陣**：Interop Validator **不會**以 ReadOnly 帳號做 403 負向測試（僅驗 Role 資源結構）。請用 `../scripts/redfish-rbac-check.sh`（對照 認證）做**分層負向**測試：
>
> | 區段 | 測試帳號 | 目標 API | 預期 |
> |------|----------|----------|------|
> | [1] | ReadOnly | Operator+（控制、一般寫入、帳號清單等） | 403 |
> | [2] | ReadOnly | Administrator（工程模式） | 403 |
> | [3] | Operator | Administrator-only | 403 |
> | [4] | 各角色 | 抽樣正向（應 200） | 200 |
>
> 腳本會自動建立 `dcim-read-rbac`（ReadOnly）與 `dcim-ctrl-rbac`（Operator）；可用 `--no-create-accounts` 略過。設備無 outlet／排程等資源時相關案例會 SKIP。

```bash
chmod +x redfish/scripts/redfish-rbac-check.sh
./redfish/scripts/redfish-rbac-check.sh -r https://<host> -u admin -p '<password>'
# 自簽 HTTPS 可加 -k；未加時腳本會自動重試一次
```

---

# 通用錯誤回應

角色與預設權限見 認證；`403` 表示呼叫者 `RoleId` 不足以執行該操作。

未列於各 API 的錯誤，回傳 Redfish 標準 `error` 物件：

```json
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "Message": "The resource at the URI was not found.",
        "MessageId": "Base.1.16.ResourceNotFound",
        "Severity": "Critical",
        "Resolution": "Provide a valid resource URI."
      }
    ],
    "code": "Base.1.16.ResourceNotFound",
    "message": "The resource at the URI was not found."
  }
}
```

#### 欄位說明如下:

* **error**: 錯誤物件
  * **code**: 錯誤代碼（如 `Base.1.16.ResourceNotFound`）
  * **message**: 錯誤訊息摘要
  * **@Message.ExtendedInfo**: 延伸錯誤資訊陣列
    * **Message**: 詳細說明
    * **MessageId**: 訊息識別碼
    * **Severity**: 嚴重程度
    * **Resolution**: 建議處理方式

> **無參數 Action**：對於不帶參數的 Action（如 `ResetMetrics`），請送 `Content-Type: application/json` 且 body 為 `{}`；完全省略 body 可能回 `400`。

常見狀態碼：

狀態碼 | 說明
----- | -------------
200   | 成功
201   | 建立成功（Session）
202   | 已接受（非同步控制）
400   | 請求格式錯誤
401   | 未認證
403   | 權限不足
404   | 資源不存在
409   | 資源衝突（如插座操作中）
500   | 伺服器內部錯誤
503   | 服務暫時不可用

# iLock 電子鎖主機

本章描述 **iLock 電子鎖主機**（`ilock.cpp`，iLock 電子鎖主機）的 Redfish API。**此為獨立產品線，不是 Rack PDU**，亦不適用 OCP Rack PDU Profile。

## 產品與協議範圍

| 項目 | 說明 |
|------|------|
| 主要產品 | **iLock**（電子鎖連接埠 ×12） |
| 與 PDU 關係 | **無**；量測／開關型 PDU（DPM、DPH、DPP 等）不提供本章 API |
| 其他機型 | **iEnv** 環控主機可外接電子鎖（外接電子鎖功能時 時暴露相同 API）；主體仍為環控，非 PDU |
| OCP 合規 | **不跑** Rack PDU Profile；可沿用 OCP Service Baseline 之 Session、Account、LogService、EventService、UpdateService 等 |
| 門禁建模 | DMTF／OCP **無**統一 ElectronicLock 資源；Pelx 以 `Oem/Pelx/ElectronicLocks` 實作 |

### Service Root 差異（相對於 PDU）

iLock 裝置的 `/redfish/v1` **不含** `PowerEquipment`、`RackPDUs`、`Outlets` 等配電資源。典型連結如下：

```json
{
  "@odata.id": "/redfish/v1",
  "Chassis": { "@odata.id": "/redfish/v1/Chassis" },
  "Managers": { "@odata.id": "/redfish/v1/Managers" },
  "SessionService": { "@odata.id": "/redfish/v1/SessionService" },
  "AccountService": { "@odata.id": "/redfish/v1/AccountService" },
  "EventService": { "@odata.id": "/redfish/v1/EventService" },
  "UpdateService": { "@odata.id": "/redfish/v1/UpdateService" },
  "Oem": {
    "Pelx": {
      "Interfaces": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces" },
      "ElectronicLocks": { "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks" },
      "ElectronicLockCards": { "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards" }
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 本服務根資源的 URI（`GET /redfish/v1` 時為 `/redfish/v1`）
* **Chassis**: 機箱集合連結；iLock 通常僅 `Chassis/1` 代表整機機櫃
* **Managers**: 管理控制器集合連結；iLock 為 `Managers/1`
* **SessionService**: 登入／Session 管理（見 認證）
* **AccountService**: 帳號與角色管理
* **EventService**: 事件訂閱與推送
* **UpdateService**: 韌體更新
* **Oem.Pelx.Interfaces**: Pelx 介面（DI／SI／CS 等）集合；可讀取底層即時點位
* **Oem.Pelx.ElectronicLocks**: 電子鎖路數集合（本章主資源）
* **Oem.Pelx.ElectronicLockCards**: **主機驗證**授權卡集合（主機端授權資料庫

> iLock **不含** `PowerEquipment`、`Schedules`（無 `DO` 輸出位址）、`TelemetryService`（若未外接 PDU 相關硬體）等 PDU 專用連結；完整 Service Root 尚含 `CertificateService`、`TaskService`、`NetworkProtocol` 等 Baseline 資源，見 總覽與合規。

認證、日誌、事件訂閱等共用章節見 認證、歷史訊息、告警與事件。

### 與 Chassis 的關係

電子鎖**物理上**裝設於機櫃／機箱門（門把、磁簧、鎖舌等），由 iLock 主機透過 RS485 等匯流排管理；在 Redfish 裡，這些門所屬的「機箱」以 **`/redfish/v1/Chassis/1`** 代表（設備識別、位置、整體健康彙整）。

| 層面 | 說明 |
|------|------|
| 物理 | 每路鎖對應一扇門／一個機櫃門禁點，裝在 Chassis 所代表的機櫃上 |
| 管理 | `Managers/1` 管理 `Chassis/1`；門禁業務由 `Oem/Pelx/ElectronicLocks` 建模 |
| 狀態讀取 | **不在** `GET /Chassis/1` 回應內嵌各路鎖狀態；請讀 `ElectronicLocks/{id}` 或 `Interfaces/{addr}` |
| 探索路徑 | 可自 Chassis 連結至門禁集合（實作建議於 `Chassis/1` 的 `Oem.Pelx.ElectronicLocks` 或 `Links` 提供 `@odata.id`） |

```json
{
  "@odata.id": "/redfish/v1/Chassis/1",
  "@odata.type": "#Chassis.v1_22_0.Chassis",
  "Id": "1",
  "Name": "Chassis",
  "ChassisType": "RackMount",
  "Status": { "State": "Enabled", "Health": "OK" },
  "Links": {
    "ManagedBy": [{ "@odata.id": "/redfish/v1/Managers/1" }]
  },
  "Oem": {
    "Pelx": {
      "ElectronicLocks": { "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks" },
      "ElectronicLockCards": { "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards" }
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 本 Chassis 資源 URI
* **@odata.type**: Redfish 結構描述型別
* **Id**: Chassis 識別碼（固定 `"1"`）
* **Name**: 顯示名稱
* **ChassisType**: 機箱類型；iLock 為 `RackMount`（機櫃掛載）
* **Status.State**: 資源狀態（`Enabled`／`Disabled` 等）
* **Status.Health**: 整體健康（`OK`／`Warning`／`Critical` 等）；**不含**各路電子鎖細項
* **Links.ManagedBy**: 管理本 Chassis 的 Manager 連結陣列
* **Oem.Pelx.ElectronicLocks**: 門禁業務入口；各路鎖狀態請讀此集合或其成員
* **Oem.Pelx.ElectronicLockCards**: **主機驗證**授權卡管理入口（非本體白名單）

> **與 PDU 文件之差異**：PDU 的 `Chassis/1` 另含 `PowerDistribution`、`Sensors`（電氣量測）等；iLock 的 Chassis 以**機櫃本體＋門禁**為主，不配電樹。門磁／門把等**語意化狀態**仍由 `ElectronicLocks` 彙整，底層 DI／SI 可從 `Interfaces` 讀取。

---

## 電子鎖資源（Oem/Pelx/ElectronicLocks）

> **權限**：預設見 認證（`GET` ReadOnly 以上；**控制 Action** 與寫入至少 **Operator**）。

#### 出現條件

僅當設備具電子鎖功能 時暴露。每路鎖對應機櫃上的一個門禁點（見上方「與 Chassis 的關係」）。即時狀態（連線、門把、磁簧、最後卡號等）亦可透過 OEM 介面 依位址查詢；本章提供**以鎖路數 `{id}` 為單位**的整合介面。

#### 介面連結

每把電子鎖以，Redfish 以 `Links.Interfaces` 連結至 `Oem/Pelx/Interfaces/{addr}`：

| 語意 | 別名 | 位址類型 | 說明 |
|------|-------------|----------|------|
| 連線狀態 | CS | CS | 週邊連線 |
| 開鎖狀態 | US | DI | 是否處於開鎖 |
| 門把狀態 | HS | DI | 門把位置 |
| 磁簧狀態 | MS | DI | 門磁 |
| 最後卡號 | CARD | SI | 最近一次刷卡卡號 |
| 開鎖結果 | UR | SI | 最近一次開鎖結果代碼 |

位址格式為 `{類型}{十六進制編碼}`，路數 `{id}` 編入低位元組，例如路數 1 常見為 `CSA101`、`DIA201`…`SIA601`（實際值依韌體為準，以 `GET .../Interfaces` 為準）。

#### 路數與硬體埠對照

Redfish 資源 `{id}` 採**硬體埠標籤**（與面板 A/B 列一致）：

| Redfish `{id}` | 說明 |
| ---------------- | ------ |
| `1A` | 第 1 組 A 埠 |
| `1B` | 第 1 組 B 埠 |
| `2A` | 第 2 組 A 埠 |
| … | … |
| `6A` | 第 6 組 A 埠 |
| `6B` | 第 6 組 B 埠 |

公式：路數 `n` → `{ceil(n/2)}{A|B}`（奇數為 A、偶數為 B）。路徑亦接受舊式數字 `11`（等同 `6A`），建議客戶端改用埠標籤。

#### 卡號兩種資料源

| 類型 | Redfish | 說明 |
| ------ | --------- | ------ |
| **本體白名單** | `.../ElectronicLocks/{id}/Cards` | 卡號寫入鎖模組，設備端驗證（如 `12345678`） |
| **主機驗證** | `.../ElectronicLockCards` | 主機資料庫，含持卡人、時段、適用路數（如 `2543209217`） |

兩者**互不取代**：同一張實體卡可同時存在於本體白名單與主機驗證庫，但卡號與管理路徑不同。

#### 未連線時的讀寫行為

`Status.Connection` 為 `Disconnected` 表示該路鎖模組目前無法透過 RS485 通訊（可能離線、拔除或逾時）。

| 操作 | 未連線行為 |
|------|------------|
| `GET .../ElectronicLocks/{id}` | **允許**；回傳最後已知狀態，`Connection` 為 `Disconnected` |
| `GET .../ElectronicLocks/{id}/Cards` | **允許** `200`；`Members` 為空，並於 `Oem.Pelx.Connection` 標示 `Disconnected`（**不代表**「尚未設定卡號」） |
| `PATCH .../ElectronicLocks/{id}` | **拒絕** `400`，`Base.1.16.ResourceNotReady` |
| `POST .../Actions/PelxElectronicLock.Control` | **拒絕** `400`，`Base.1.16.ResourceNotReady` |
| `POST/DELETE .../ElectronicLocks/{id}/Cards` | **拒絕** `400`，`Base.1.16.ResourceNotReady` |

未連線時拒絕寫入的原因：參數修改、控制命令、本體卡號維護皆需寫入鎖模組；若仍回 `200`／`201`，客戶端會誤以為操作成功，但實際未生效。

錯誤回應範例：

```json
{
  "error": {
    "@Message.ExtendedInfo": [
      {
        "Message": "Electronic lock is not connected",
        "MessageArgs": [],
        "MessageId": "Base.1.16.ResourceNotReady",
        "Severity": "Warning"
      }
    ],
    "code": "Base.1.16.ResourceNotReady",
    "message": "Electronic lock is not connected"
  }
}
```

建議客戶端在 `PATCH`／`POST` 前先讀 `GET .../ElectronicLocks/{id}` 確認 `Status.Connection` 為 `Connected`；若為 `Disconnected`，應提示使用者檢查配線或等待連線恢復後重試。

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks

取得所有電子鎖（需認證）。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks",
  "@odata.type": "#PelxElectronicLockCollection.PelxElectronicLockCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/1A"
    },
    {
      "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/1B"
    }
  ],
  "Members@odata.count": 2,
  "AuthorizedCards": {
    "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards"
  },
  "Settings": {
    "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/Settings"
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 電子鎖集合資源 URI
* **@odata.type**: Pelx 電子鎖集合型別
* **Members**: 成員連結陣列；每項僅含 `@odata.id`，指向單路電子鎖
  * **Members[].@odata.id**: 單路資源 URI；`{id}` 為硬體埠標籤（`1A`…`6B`，見上路數對照表）
* **Members@odata.count**: `Members` 陣列長度（等於電子鎖路數）
* **AuthorizedCards**: **主機驗證**授權卡集合連結（主機端授權資料庫；與本體白名單不同，見 `ElectronicLockCards`）
* **Settings**: 電子鎖全域設定資源連結（背景檢查間隔等）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}

取得單一電子鎖狀態與參數。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/6A",
  "@odata.type": "#PelxElectronicLock.v1_0_0.PelxElectronicLock",
  "Id": "6A",
  "Name": "2F-L-21-前門",
  "UnlockTimeSec": 5,
  "Status": {
    "Connection": "Connected",
    "Unlock": "Locked",
    "Handle": "Closed",
    "Magnetic": "Closed",
    "LastUnlockResult": "None"
  },
  "LastCardId": "1234567890",
  "Links": {
    "Interfaces": {
      "Connection": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/CSA101" },
      "Unlock": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DIA201" },
      "Handle": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DIA301" },
      "Magnetic": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DIA401" },
      "LastCardId": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/SIA501" },
      "UnlockResult": { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/SIA601" }
    }
  },
  "Cards": {
    "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/6A/Cards"
  },
  "Actions": {
    "#PelxElectronicLock.Control": {
      "target": "/redfish/v1/Oem/Pelx/ElectronicLocks/6A/Actions/PelxElectronicLock.Control"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 本路電子鎖資源 URI（`{id}` 為埠標籤，如 `6A`）
* **@odata.type**: Pelx 單路電子鎖型別
* **Id**: 資源識別碼（字串，與路徑 `{id}` 相同，如 `6A`
* **Name**: 顯示名稱（ELOCK 元素之 `caption`，如 `2F-L-21-前門`；未設定時為 `Elock6A`）
* **UnlockTimeSec**: 開鎖維持秒數（整數
* **Status**: 語意化即時狀態（由底層 DI／SI／CS 彙整，非原始點位值）
  * **Connection**: 週邊連線狀態，`Connected`／`Disconnected`
  * **Unlock**: 鎖舌／開鎖狀態，`Open`（已開鎖）／`Locked`（已閉鎖）
  * **Handle**: 門把狀態，`Open`／`Closed`
  * **Magnetic**: 門磁狀態，`Open`／`Closed`
  * **LastUnlockResult**: 最近一次開鎖結果代碼（字串枚舉），見下表
* **LastCardId**: 最近一次刷卡卡號（字串；無刷卡紀錄時為空字串）
* **Links.Interfaces**: 各狀態對應之 Pelx 介面資源連結（唯讀探索用）
  * **Connection**: 連線狀態介面（CS 類型，如 `CSA101`）
  * **Unlock**: 開鎖狀態介面（DI）
  * **Handle**: 門把介面（DI）
  * **Magnetic**: 門磁介面（DI）
  * **LastCardId**: 最後卡號介面（SI）
  * **UnlockResult**: 開鎖結果介面（SI）
* **Cards**: 本路電子鎖**本體白名單**連結（寫入鎖模組
* **Actions**: 可執行動作
  * **#PelxElectronicLock.Control**: 遠端控制（開鎖、閉鎖等）
    * **target**: `POST` 控制動作的 URI

#### LastUnlockResult 對照

代碼 | Redfish 值 | 說明
--------|------------|------
0 | None | 無
1 | CardValid | 設備卡號驗證成功
2 | CardInvalid | 設備卡號驗證失敗
3 | CardByHost | 卡號由主機判斷
4 | HostCardValid | 主機卡號驗證成功
5 | HostCardInvalid | 主機卡號驗證失敗
6 | Rs485Unlock | RS485 命令開鎖
7 | KeyUnlock | 鑰匙開鎖
8 | DiUnlock | DI 開鎖
9 | HostCardNotFound | 主機卡號不存在
10 | HostCardExpired | 主機卡號已過期
11 | HostCardNotInPeriod | 主機卡號不在有效期間

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 路數不存在

### PATCH https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}

修改電子鎖參數。**該路須為連線狀態**。

```json
{
  "UnlockTimeSec": 8
}
```

#### 欄位說明如下:

* **UnlockTimeSec**（必填）: 開鎖維持秒數（正整數

成功時回 `200`，body 為更新後的完整電子鎖資源（結構同 `GET .../ElectronicLocks/{id}`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常；body 為更新後資源
400   | 參數錯誤，或電子鎖未連線（`ResourceNotReady`）
401   | 未認證
403   | 權限不足
404   | 路數不存在

### POST https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}/Actions/PelxElectronicLock.Control

控制電子鎖。**該路須為連線狀態**。

```json
{
  "ControlType": "Unlock"
}
```

#### 欄位說明如下:

* **ControlType**（與 `CtrlKind` 擇一）: 控制類型字串，見下表
* **CtrlKind**（與 `ControlType` 擇一）: 控制類型數值 1–5，；兩者同時存在時以 `ControlType` 為準

#### ControlType 對照

ControlType | ctrlKind | 說明
------------|---------------|------
Unlock | 1 | 開鎖
Lock | 2 | 閉鎖
HostCardValid | 3 | 主機卡號驗證成功
HostCardInvalid | 4 | 主機卡號驗證失敗
ResetUnlockStatus | 5 | 將開鎖狀態值重設為 0

亦可改送數值欄位 `CtrlKind`（1–5），；兩者擇一，同時存在時以 `ControlType` 為準。

成功時回 `200`，body 為執行後的完整電子鎖資源（結構同 `GET .../ElectronicLocks/{id}`，可讀取更新後的 `Status`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 控制失敗、參數錯誤，或電子鎖未連線（`ResourceNotReady`）
401   | 未認證
403   | 權限不足
404   | 路數不存在

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}/Cards

取得該路電子鎖**本體白名單**卡號集合（需認證。卡號寫入鎖模組，供**設備端**驗證刷卡；與主機驗證用的 `ElectronicLockCards`（auth）為不同資料源。未連線時仍回 `200`（供 Redfish 連結遍歷），但 `Oem.Pelx.Connection` 為 `Disconnected` 且 `Members` 為空；請勿將此情況解讀為「無卡號」。

連線時範例：

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/6A/Cards",
  "@odata.type": "#PelxElectronicLockCardCollection.PelxElectronicLockCardCollection",
  "Members": [
    {
      "Id": "12345678"
    }
  ],
  "Members@odata.count": 1,
  "Oem": {
    "Pelx": {
      "Connection": "Connected"
    }
  }
}
```

未連線時範例：

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/1A/Cards",
  "@odata.type": "#PelxElectronicLockCardCollection.PelxElectronicLockCardCollection",
  "Members": [],
  "Members@odata.count": 0,
  "Oem": {
    "Pelx": {
      "Connection": "Disconnected"
    }
  }
}
```

本體卡僅有卡號字串，**不提供** `GET .../Cards/{cardId}` 單卡資源；請自 `Members[].Id` 讀取卡號，刪除時使用 `DELETE .../Cards/{cardId}`。

#### 欄位說明如下:

* **@odata.id**: 本路本體卡號集合 URI（`{id}` 為埠標籤，如 `6A`）
* **@odata.type**: Pelx 卡號集合型別
* **Members**: 寫入該路鎖模組的卡號陣列
  * **Members[].Id**: 卡號字串（與鎖模組儲存值相同）
* **Members@odata.count**: `Members` 陣列長度
* **Oem.Pelx.Connection**: 本路鎖模組連線狀態（`Connected`／`Disconnected`）；為 `Disconnected` 時 `Members` 不可信，請改讀父資源 `GET .../ElectronicLocks/{id}` 的 `Status.Connection`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常（含未連線時之空集合）
401   | 未認證
404   | 路數不存在
503   | 電子鎖服務不可用

### POST https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}/Cards

新增本體白名單卡號。**該路電子鎖須為連線狀態**（`GET .../ElectronicLocks/{id}` 的 `Status.Connection` 為 `Connected`）；未連線時回 `400`，卡號不會寫入鎖模組。

```json
{
  "Id": "12345678"
}
```

亦可使用欄位 `CardId`。

#### 欄位說明如下:

* **Id** / **CardId**（擇一，必填）: 卡號字串（寫入鎖模組）

成功時回 `201 Created`，body 為：

```json
{
  "Id": "12345678"
}
```

#### 回應欄位說明如下:

* **Id**: 已寫入鎖模組的卡號

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功
400   | 卡號格式錯誤，或電子鎖未連線（`ResourceNotReady`）
401   | 未認證
403   | 權限不足
404   | 路數不存在

### DELETE https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/{id}/Cards/{cardId}

刪除本體白名單卡號。**該路電子鎖須為連線狀態**；未連線時回 `400`。

成功時回 `200`，body 為 `{}`。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 電子鎖未連線（`ResourceNotReady`）
401   | 未認證
403   | 權限不足
404   | 路數或卡號不存在

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLockCards

取得**主機驗證**授權卡號集合（需認證。與 per-lock 本體白名單不同：此處含持卡人、到期日、適用路數、時段等，供**主機端**驗證刷卡。資料來源為主機授權服務，**不受**單路電子鎖連線狀態影響。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards",
  "@odata.type": "#PelxElectronicLockCardCollection.PelxElectronicLockCardCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards/2543209217"
    }
  ],
  "Members@odata.count": 1
}
```

集合亦可自 `GET .../ElectronicLocks` 的 `AuthorizedCards` 連結進入。

#### 欄位說明如下:

* **@odata.id**: 全域授權卡號集合 URI
* **@odata.type**: Pelx 授權卡號集合型別
* **Members**: 全部授權卡連結陣列
  * **Members[].@odata.id**: 單張授權卡資源 URI；`GET` 該 URI 可取得完整卡資訊
* **Members@odata.count**: `Members` 陣列長度

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
503   | 主機授權服務不可用

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLockCards/{cardId}

取得單一授權卡號完整資訊。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLockCards/2543209217",
  "@odata.type": "#PelxElectronicLockCard.v1_0_0.PelxElectronicLockCard",
  "Id": "2543209217",
  "Name": "張三",
  "Username": "張三",
  "ExpireTime": 1735689600,
  "NeverExpires": false,
  "PeriodIds": [1, 2],
  "ElectronicLocks": ["6A", "6B"]
}
```

#### 欄位說明如下:

* **@odata.id**: 本授權卡資源 URI（`{cardId}` 為實體卡號字串）
* **@odata.type**: Pelx 授權卡型別
* **Id**: 卡號識別碼（字串；、刷卡機讀取之卡號）
* **Name**: 顯示名稱（通常與 `Username` 相同；未設定持卡人時回退為卡號）
* **Username**: 持卡人名稱
* **ExpireTime**: 到期 Unix 時間戳（秒，UTC）；`0` 表示永不過期
* **NeverExpires**: 布林值；`ExpireTime == 0` 時為 `true`，否則 `false`
* **PeriodIds**: 允許刷卡之時段規則 ID 陣列
* **ElectronicLocks**: 本卡可開啟之電子鎖路數（埠標籤字串陣列，如 `6A`、`6B`； 經轉換）
* **Oem.Pelx**（選填）: 廠商擴充欄位；對應廠商擴充物件 物件，僅在 `extra` 非空時出現

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 卡號不存在
503   | 主機授權服務不可用

### POST https://<host>/redfish/v1/Oem/Pelx/ElectronicLockCards

新增授權卡號。

```json
{
  "Id": "2543209217",
  "Username": "張三",
  "ExpireTime": 0,
  "PeriodIds": [1],
  "ElectronicLocks": ["6A", "6B"]
}
```

#### 欄位說明如下:

* **Id**（必填）: 卡號（字串；；不可與既有卡重複）
* **Username**（必填）: 持卡人名稱
* **ExpireTime**（選填，預設 `0`）: 到期 Unix 時間戳（秒）；`0` 表示永不過期
* **PeriodIds**（選填，預設 `[]`）: 時段規則 ID 陣列；空陣列表示不限制時段（依設備驗證邏輯）
* **ElectronicLocks**（必填）: 適用電子鎖埠標籤陣列（如 `["6A","6B"]`）
* **elockIds**（可替代 `ElectronicLocks`）: 路數整數陣列（如 `[11,12]`），與埠標籤擇一語意
* **Oem.Pelx**（選填）: 廠商擴充物件；對應廠商擴充物件（未提供時送空物件 `{}`）

`ExpireTime` 為 `0` 或不填表示永不過期。

成功時回 `201 Created`，`Location` 指向 `/redfish/v1/Oem/Pelx/ElectronicLockCards/{cardId}`，body 為建立後的完整卡資源（結構同 `GET .../ElectronicLockCards/{cardId}`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功
400   | 參數錯誤或建立失敗
401   | 未認證
403   | 權限不足

### PATCH https://<host>/redfish/v1/Oem/Pelx/ElectronicLockCards/{cardId}

修改授權卡號。**須提供完整欄位**（與資源完整欄位定義一致；未送出的欄位會被視為空值覆寫）。

```json
{
  "Username": "李四",
  "ExpireTime": 1735689600,
  "PeriodIds": [1, 2],
  "ElectronicLocks": ["6A"]
}
```

#### 欄位說明如下:

* **Username**（必填）: 持卡人名稱
* **ExpireTime**（必填）: 到期 Unix 時間戳（秒）；`0` 表示永不過期
* **PeriodIds**（必填）: 時段規則 ID 陣列（可為空陣列 `[]`）
* **ElectronicLocks**（必填）: 適用電子鎖埠標籤陣列；亦可改送 **elockIds** 整數陣列
* **Oem.Pelx** / **extra**（選填）: 廠商擴充物件；未提供時送 `{}`

成功時回 `200`，body 為更新後的完整卡資源（結構同 `GET .../ElectronicLockCards/{cardId}`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 參數錯誤
401   | 未認證
403   | 權限不足
404   | 卡號不存在

### DELETE https://<host>/redfish/v1/Oem/Pelx/ElectronicLockCards/{cardId}

刪除授權卡號。

成功時回 `200`，body 為空 JSON 物件：

```json
{}
```

#### 欄位說明如下:

* 無請求 body；回應 `{}` 表示刪除成功（Redfish 慣例空物件）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足
404   | 卡號不存在

### GET https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/Settings

取得電子鎖全域設定（需認證。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/ElectronicLocks/Settings",
  "@odata.type": "#PelxElectronicLockSettings.v1_0_0.PelxElectronicLockSettings",
  "Id": "Settings",
  "Name": "Electronic Lock Settings",
  "IntervalCheckMinutes": 5
}
```

#### 欄位說明如下:

* **@odata.id**: 電子鎖全域設定資源 URI
* **@odata.type**: Pelx 電子鎖設定型別
* **Id**: 資源識別碼（固定 `"Settings"`）
* **Name**: 顯示名稱（固定 `"Electronic Lock Settings"`）
* **IntervalCheckMinutes**: 背景檢查間隔（分鐘，整數

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### PATCH https://<host>/redfish/v1/Oem/Pelx/ElectronicLocks/Settings

修改全域設定。

```json
{
  "IntervalCheckMinutes": 10
}
```

#### 欄位說明如下:

* **IntervalCheckMinutes**（必填）: 背景檢查間隔（分鐘，正整數

成功時回 `200`，body 為更新後的完整設定資源（結構同 `GET .../ElectronicLocks/Settings`）。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
400   | 參數錯誤
401   | 未認證
403   | 權限不足

#### 事件與日誌

開鎖、刷卡、卡號維護等事件請讀 `Managers/1/LogServices/Operational` 與 `Audit`（見 歷史訊息）；即時狀態可訂閱 MQTT 或輪詢 `Oem/Pelx/ElectronicLocks`。

# Pelx 擴充（OEM）

下列為 **Pelx OEM 路徑**（`Oem/Pelx/*`），非 DMTF 標準資源模型。整合方若僅需 OCP 合規可忽略本章節。

> **同一套入口**：RS485、VNode、圖控、自動化流程等工程組態，對外一律經 `https://<host>/redfish/v1/Oem/Pelx/...`；沿用 auth.md 既有 RBAC（工程寫入須 **Administrator**）。**不**另開對外 REST。

| 模組 | 說明 | 權限 |
|------|------|------|
| OEM 介面 | 完整介面列表（Oem/Pelx/Interfaces） | 讀：ReadOnly；寫：見 auth |
| 週邊樹 | 週邊結構樹（Oem/Pelx/PeripheralTree；設備週邊結構服務） | 讀：ReadOnly |
| MQTT Discovery | MQTT 連線資訊（Oem.Pelx.MqttEndpoint） | 讀 |
| 排程 | 排程管理（Oem/Pelx/Schedules） | 寫：Operator |
| oem serial buses | RS485 串列參數（Oem/Pelx/SerialBuses） | **Administrator** |
| oem vnodes | VNode 組態（Oem/Pelx/VNodes） | **Administrator** |
| oem hmi screens | 圖控畫面與樣版匯出／載入（Oem/Pelx/HmiScreens） | **Administrator** |
| oem hmi image libraries | 圖控圖庫上傳／匯入（Oem/Pelx/HmiImageLibraries） | **Administrator** |
| oem automations | 自動化流程／Flow（Oem/Pelx/Automations） | **Administrator** |
| e ports | E-Port 週邊名稱 | 見 hwctrl |

> 電子鎖為 **iLock 獨立產品**，規格見「iLock 電子鎖」章節，不列於 PDU 擴充目錄。

## OEM 擴充：完整介面列表（Pelx 擴充）

標準 Chassis / PowerEquipment 資源未涵蓋的 DI、SI、HR、VNode 等週邊，透過 OEM 資源輸出完整 `interfaces` 資料。

**`addr` 以 `DO` 開頭**的介面為 Discrete Output，代表 PDU 上可輸出控制的外接設備（如 E-Port）；排程 `command: out` 的非 OCP 目標可引用此類介面，見 排程。電子鎖門禁請用「iLock 電子鎖」章節。

### GET https://<host>/redfish/v1/Oem/Pelx/Interfaces

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces",
  "@odata.type": "#PelxInterfaceCollection.PelxInterfaceCollection",
  "Members": [
    { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101" }
  ],
  "Members@odata.count": 1
}
```

集合內 `Members` 為 Redfish 慣例的 `@odata.id` 連結；單筆詳情見 `GET .../Interfaces/{addr}`。

> **大量即時監控**：Pelx 多點即時看板請用 **MQTT** `/update`（第 11 章），**不需**擴充本集合為內嵌 `value`。本 API 供資源探索、單筆讀取、排程／連結對照。若需一次取得完整**週邊結構樹**（分類／路數／介面），請用 週邊樹（`Oem/Pelx/PeripheralTree`）。

#### 欄位說明如下:

* **@odata.id**: 介面集合資源 URI，固定 `/redfish/v1/Oem/Pelx/Interfaces`
* **@odata.type**: 資源型別，固定 `#PelxInterfaceCollection.PelxInterfaceCollection`
* **Members**: 介面資源連結陣列（元素為 `{ "@odata.id": "..." }`）
* **Members@odata.count**: 介面總數

#### 單筆介面欄位（`GET .../Interfaces/{addr}`）

| 欄位 | 說明 |
|------|------|
| **addr** | 介面位址，格式見 `Oem/Pelx/Interfaces` |
| **name** | 介面名稱，顯示名稱 |
| **alias** | 介面別名 |
| **peripheralAlias** | 週邊別名（如 `INFEED`、`OUTLET`） |
| **elementId** | 週邊路數 |
| **unit** / **type** / **value** | 單位、型別、即時讀值 |
| **status** / **params** / **health** | 狀態、閾值、Redfish Health |

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證

### GET https://<host>/redfish/v1/Oem/Pelx/Interfaces/{addr}

依介面位址查詢單筆，例如 `AI2101`。`{addr}` 為介面位址。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101",
  "@odata.type": "#PelxInterface.v1_0_0.PelxInterface",
  "Id": "AI2101",
  "Name": "Infeed1 Voltage",
  "addr": "AI2101",
  "name": "Infeed1 Voltage",
  "alias": "V",
  "peripheralAlias": "INFEED",
  "elementId": 1,
  "unit": "V",
  "type": "FLOAT",
  "value": 220.4,
  "status": "ok",
  "params": {
    "hc": 250,
    "hw": 240,
    "lc": 190,
    "lw": 200
  },
  "health": "OK"
}
```

#### 欄位說明如下:

* **@odata.type**: 資源型別，固定 `#PelxInterface.v1_0_0.PelxInterface`（**Mandatory**；缺此欄位 Validator 報錯）
* **Id**: 與 `{addr}` 相同
* **Name**: 顯示名稱
* **addr**: 介面位址（body 欄位），與路徑參數相同
* **name**: 介面名稱，顯示名稱
* **alias**: 介面別名，別名
* **peripheralAlias**: 所屬週邊分類別名（如 `INFEED`、`OUTLET`）
* **elementId**: 所屬週邊路數，週邊路數
* **unit**: 資料單位
* **type**: 資料型別，如 `FLOAT`、`BOOL`、`STRING`
* **value**: 即時讀值，對應 `GET /interfaces` 的 **value**
* **status**: 介面狀態，相關說明請參考 介面狀態
* **params**: 閾值參數物件
  * **hc**: 過高異常值
  * **hw**: 過高警告值
  * **lc**: 過低異常值
  * **lw**: 過低警告值
* **health**: 已由 **status** 轉換的 Redfish Health（`OK` / `Warning` / `Critical`）

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
404   | 介面位址不存在

### Pelx CSDL 與 `$metadata`

其他資源上的 `Oem.Pelx` 欄位（`Interface`、`Interfaces`、`InterfaceGroups`）由 **Pelx.v1_0_0** schema 定義：

| 端點 | 說明 |
|------|------|
| `GET /redfish/v1/$metadata` | OData 中繼資料；**內嵌**完整 `Pelx_v1.xml` CSDL |
| `GET /redfish/v1/schemas/Pelx_v1.xml` | 獨立 schema 文件（與源碼 `hwctrl/redfish/schema/Pelx_v1.xml` 同步） |

設備部署路徑：`/root/rpm6/share/rpm6/redfish/schemas/Pelx_v1.xml`。執行 DMTF Service Validator 時，本機 `Redfish-Publications/csdl/Pelx_v1.xml` 須與設備版本一致，否則 `Oem.Pelx.Interface` 等欄位會被判為 Unknown Property。

---

## 週邊樹（PeripheralTree，Pelx 擴充）

本章提供設備**週邊結構樹** API。一次回傳分類 → 路數（elements）→ 介面的完整結構，供 AI／規劃工具／整合方盤點週邊節點，無需對 `Oem/Pelx/Interfaces` 逐筆組樹。

此能力不屬 OCP Rack PDU Profile 必填。

> **入口原則**：對外只走 `https://<host>/redfish/v1`；閘道轉呼叫設備週邊結構，**不**另開對外 REST，亦**不**在路徑或資源名稱使用內部結構名稱。

> **與 Interfaces 分工**：
> * **`PeripheralTree`**：結構盤點（名稱、別名、路數、`addr`、單位、型別等）；**不含**即時 `value`／告警 `status`／閾值 `params`。
> * **`Oem/Pelx/Interfaces/{addr}`**：單點即時值、狀態、閾值。
> * 大量即時看板仍用 **MQTT**（見 MQTT Discovery）。

> **權限**：讀取 **ReadOnly** 即可（同 `Oem/Pelx/Interfaces`）。本資源為唯讀；不提供 PATCH／POST／DELETE。

### GET https://<host>/redfish/v1/Oem/Pelx/PeripheralTree

取得整機週邊樹（單一路徑資源，非 Collection）。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/PeripheralTree",
  "@odata.type": "#PelxPeripheralTree.v1_0_0.PelxPeripheralTree",
  "Id": "PeripheralTree",
  "Name": "Peripheral Tree",
  "Timestamp": 1733284850,
  "Peripherals": [
    {
      "Name": "Infeed",
      "Alias": "INFEED",
      "Elements": [
        {
          "Name": "Infeed1",
          "Alias": "INFEED",
          "ElementId": 1,
          "Interfaces": [
            {
              "Name": "Voltage",
              "Alias": "V",
              "Addr": "AI2101",
              "Unit": "V",
              "Type": "FLOAT",
              "DecimalPlaces": 1,
              "Access": "RW",
              "Interface": {
                "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2101"
              }
            },
            {
              "Name": "Frequency",
              "Alias": "FREQ",
              "Addr": "AI2102",
              "Unit": "Hz",
              "Type": "FLOAT",
              "DecimalPlaces": 1,
              "Access": "RW",
              "Interface": {
                "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/AI2102"
              }
            }
          ]
        }
      ]
    },
    {
      "Name": "Input",
      "Alias": "INPUT",
      "Elements": [],
      "Interfaces": [
        {
          "Name": "DI1",
          "Alias": "DI1",
          "Addr": "DI6101",
          "Type": "BOOL",
          "Access": "RO",
          "Interface": {
            "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DI6101"
          }
        }
      ]
    }
  ],
  "Languages": {
    "zh-TW": {
      "INFEED": "電源進線",
      "V": "電壓",
      "FREQ": "頻率"
    }
  }
}
```

#### 欄位說明如下:

* **@odata.id**: 固定 `/redfish/v1/Oem/Pelx/PeripheralTree`
* **@odata.type**: 固定 `#PelxPeripheralTree.v1_0_0.PelxPeripheralTree`
* **Id** / **Name**: 資源識別與顯示名稱
* **Timestamp**: Unix 時間戳（秒）
* **Peripherals**: 週邊分類陣列
  * **Name**: 分類名稱
  * **Alias**: 分類別名（如 `INFEED`、`OUTLET`、`TEMPRH`）
  * **Elements**: 週邊路數列表；內建乾接點等可為空陣列
    * **Name** / **Alias** / **ElementId**: 路數名稱、別名、序號
    * **Interfaces**: 該路下之介面列表
  * **Interfaces**:（選用）分類層級介面（無 `ElementId` 時，如內建 `INPUT` 的 DI）
* **介面物件**（出現於 `Elements[].Interfaces` 或 `Peripherals[].Interfaces`）:
  * **Name** / **Alias**: 介面名稱／別名
  * **Addr**: 介面位址字串（與 `Oem/Pelx/Interfaces/{addr}` 相同）
  * **Unit** / **Type** / **DecimalPlaces** / **Size** / **Access**: 單位、型別（`BOOL`／`INT`／`FLOAT`／`STRING`）、小數位、字串長度、存取（`RW`／`RO`／`WO`）；無則省略
  * **Interface**: 指向即時介面資源的連結 `{ "@odata.id": ".../Interfaces/{Addr}" }`
* **Languages**: 語言包；無則省略或為空物件

#### 回傳資料狀態

| 狀態碼 | 說明 |
|--------|------|
| 200 | 正常 |
| 401 | 未認證 |

### Service Root 連結

`GET /redfish/v1` 的 `Oem.Pelx` 應提供：

```json
"PeripheralTree": {
  "@odata.id": "/redfish/v1/Oem/Pelx/PeripheralTree"
}
```

### 使用建議（AI／整合）

1. 啟動或組態變更後：**一次** `GET PeripheralTree` 建立週邊／點位對照並快取。
2. 需要即時值時：依樹中的 `Addr` 或 `Interface.@odata.id` 讀 `Oem/Pelx/Interfaces/{addr}`，或改訂 MQTT。
3. 勿高頻輪詢本資源；結構變動遠少於量測值。

## OEM 擴充：MQTT 連線資訊（Pelx 擴充）

大量即時監控使用 **MQTT over WebSocket**（非 Redfish 協議）。本節定義如何透過 **Redfish OEM** 提供 MQTT 連線資訊，供整合方 Discovery 後建立 MQTT Client。

> **僅 Discovery／連線入口**：Redfish 回傳 URL 與認證提示；即時 `value`／`status` 仍經 MQTT 訂閱 **`local`** topic，**不**經 Redfish 輪詢或代理。整合指南見 第 11 章。

### 暴露位置

| 資源 | 路徑 | 說明 |
|------|------|------|
| **OEM 資源** | `GET /redfish/v1/Oem/Pelx/Mqtt` | 建議；完整 OEM JSON，含 `Endpoint` |
| Service Root | `GET /redfish/v1` → `Oem.Pelx` | 可含 `MqttEndpoint` 連結或字串 |
| Manager | `GET /redfish/v1/Managers/1` → `Oem.Pelx` | 可選；可含 `MqttEndpoint` |

屬 **Pelx OEM 擴充**，**非 OCP 必填**；不影響 Interop Validator。

### GET `/redfish/v1/Oem/Pelx/Mqtt` 範例

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/Mqtt",
  "@odata.type": "#Pelx.MqttConnection.v1_0_0.MqttConnection",
  "Id": "Mqtt",
  "Name": "Pelx MQTT WebSocket",
  "Endpoint": "wss://pdu.example.com/redfish/v1/Oem/Pelx/Mqtt",
  "Protocol": "MQTT",
  "Transport": "WebSocket",
  "MqttAuth": "RedfishSession",
  "Description": "Connect with X-Auth-Token or Basic Auth; subscribe to /updates/local and /update/local/#"
}
```

WebSocket 連線 URL 與 **Endpoint** 相同（`wss://<host>/redfish/v1/Oem/Pelx/Mqtt`），

### Service Root 範例（精簡）

```json
{
  "@odata.id": "/redfish/v1",
  ...
  "Oem": {
    "Pelx": {
      "Interfaces": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces"
      },
      "TelemetryService": {
        "@odata.id": "/redfish/v1/TelemetryService"
      },
      "Mqtt": {
        "@odata.id": "/redfish/v1/Oem/Pelx/Mqtt"
      },
      "MqttEndpoint": "wss://pdu.example.com/redfish/v1/Oem/Pelx/Mqtt",
      "MqttAuth": "RedfishSession"
    }
  }
}
```

### MQTT Topic

| Topic | 方向 | 說明 |
|-------|------|------|
| **`/updates/local`** | 設備 → 客戶端 | 每秒批量 `value` |
| **`/update/local/{addr}`** | 設備 → 客戶端 | 單一介面變更（value／status） |
| **`/updates/ePort`** | 設備 → 客戶端 | E-Port 相關批量（若有） |

### 欄位說明

| 欄位 | 類型 | 說明 |
|------|------|------|
| **Endpoint** / **MqttEndpoint** | 字串（URI） | MQTT over WebSocket 對外 URL；Redfish 整合為 `wss://<host>/redfish/v1/Oem/Pelx/Mqtt` |

**Redfish 整合認證**（`/redfish/v1/Oem/Pelx/Mqtt`）：

* Header：`X-Auth-Token: <session token>`（`POST /redfish/v1/SessionService/Sessions`）
* Header：`Authorization: Basic <base64(user:pass)>`
* MQTT broker 不接受 CONNECT 層帳密作為 Redfish 認證 帳密作為 Redfish 認證；Postman 等工具請在 **HTTP Headers** 帶 token，**勿**使用 Authorization 分頁的 Basic Auth（會變成 MQTT 帳密）

### 串接 Slave

Primary 串接時 endpoint 可能為：

```
wss://<Primary>/slave/<id>/redfish/v1/Oem/Pelx/Mqtt
```

`MqttEndpoint`／`Endpoint` 應反映**目前請求所見**的對外 URL（對外 URL）。

### 整合流程

```
GET /redfish/v1/Oem/Pelx/Mqtt   → 讀 Endpoint、MqttAuth
POST SessionService/Sessions         → 取得 X-Auth-Token（或 Basic Auth）
WebSocket connect Endpoint           → 帶 X-Auth-Token 或 Authorization
訂閱 /updates/local、/update/local/#
控制／告警                             → 仍用 Redfish REST
```

### 手動測試

**curl（HTTP／WebSocket 握手）**

```bash
HOST=113.196.183.194   # 替換為設備 IP

# GET 無 auth → 401
curl -sk -o /dev/null -w "%{http_code}\n" "https://${HOST}/redfish/v1/Oem/Pelx/Mqtt"

# GET + Basic → 200
curl -sk -u admin:admin123 -o /dev/null -w "%{http_code}\n" "https://${HOST}/redfish/v1/Oem/Pelx/Mqtt"

# WebSocket 無 auth → 401
curl -sk --max-time 5 -o /dev/null -w "%{http_code}\n" \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  "https://${HOST}/redfish/v1/Oem/Pelx/Mqtt"

# WebSocket + Basic → 101
curl -sk --max-time 5 -o /dev/null -w "%{http_code}\n" \
  -u admin:admin123 \
  -H "Connection: Upgrade" -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
  "https://${HOST}/redfish/v1/Oem/Pelx/Mqtt"
```

**MQTTX CLI（訂閱 MQTT，需 ≥ 1.11，支援 `-wh` WebSocket Header）**

MQTTX **Desktop 無法**自訂 WebSocket HTTP Header，Redfish 路徑請用 **CLI** 或 **mqtt.js**（`wsOptions.headers`）。

```bash
npm install -g mqttx-cli@1.12.1

mqttx sub \
  -h <HOST> -p 443 -l wss \
  --path /redfish/v1/Oem/Pelx/Mqtt \
  -t '/updates/local' \
  -wh "Authorization: Basic $(printf 'admin:admin123' | base64)" \
  --insecure
```

設備使用自簽 TLS 憑證時加 **`--insecure`**。認證亦可改 `-wh "X-Auth-Token: <token>"`。

**Postman**

| 類型 | 用途 | Headers |
|------|------|---------|
| **HTTP** Request | GET `/Oem/Pelx/Mqtt` | 手動加 `Authorization` 或 `X-Auth-Token` |
| **WebSocket** Request | 驗證握手 401／101 | 同上 |
| **MQTT** Request | ❌ 不適用 | 無 Headers 分頁；Authorization 分頁變 MQTT 帳密 |
* 第 11 章
* 串接.md §4.5

## 排程（Schedules，Pelx 擴充）

本章提供 Pelx 排程管理 Redfish API（`Oem/Pelx/Schedules`）。此能力不屬 OCP Rack PDU Profile 必填。

> **權限**：預設見「認證」章節（控制 Action 與寫入至少 **Operator**）。

#### 出現條件

僅當裝置具備可排程之**輸出點**時，`GET /redfish/v1` 的 `Oem.Pelx.Schedules` 連結與本章 API 才會出現；否則回 `404`。

| 條件 | 說明 |
|------|------|
| OCP 插座 | 具可控插座時（`Links.Outlets`；底層為 `DO` 位址） |
| DO 介面 | 至少一個 `Oem/Pelx/Interfaces/{addr}` 且 `{addr}` **以 `DO` 開頭** |

僅 **Outlet** 與 **`DO` 開頭位址**可為排程目標；僅有 infeed／ATS／AI／DI／SI 等讀取或量測點位**不會**出現 Schedules。

**iLock 純電子鎖主機**（僅 CS／DI／SI 等讀取或門禁點位，無 `DO` 輸出）**不提供** Schedules。電子鎖門禁請用 `Oem/Pelx/ElectronicLocks`（見「iLock 電子鎖」章節）。

排程的**控制目標**以 Redfish 資源連結（`@odata.id`）表示，以 `@odata.id` 表示：

| 目標類型 | Redfish 欄位 | 說明 |
|----------|--------------|------|
| OCP 插座 | `Links.Outlets[]` | 標準 `PowerEquipment/RackPDUs/1/Outlets/{id}`；底層仍對應 DO 位址 |
| 可輸出控制設備 | `Links.Interfaces[]` | `Oem/Pelx/Interfaces/{addr}`，**`addr` 須以 `DO` 開頭**（見下方） |
| 串接設備（從機） | `Oem.Pelx.SlaveTargets[]` | **僅雙網卡且設為主機時**出現；各項含 `DeviceId` 與 `Interfaces[]`（`DO` 開頭位址） |

#### SlaveTargets 出現條件

僅當裝置為**雙網卡**且網路模式設為**主機**時，回應才會包含 `Oem.Pelx.SlaveTargets`。單網卡或從機模式不會出現此欄位；`POST`／`PATCH` 帶入 `SlaveTargets` 將回 `400`。

#### DO 位址語意

**`DO` 代表所有透過輸出點操作的設備**，不限單一週邊種類，例如：

* 插座繼電器（`peripheralAlias: OUTLET`）
* E-Port 等乾接點輸出週邊
* 其他僅在 Pelx 介面列表出現、未映射至 OCP `Outlets` 的輸出點

`AI`、`DI`、`SI` 等為讀取或輸入類介面，**不可**作為 `command: out` 的排程目標。位址格式見 `Oem/Pelx/Interfaces`。

`command: out` 時，**插座與其他 DO 設備可混用**於同一排程。。

### GET https://<host>/redfish/v1/Oem/Pelx/Schedules

取得所有排程。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/Schedules",
  "@odata.type": "#PelxScheduleCollection.PelxScheduleCollection",
  "Members": [
    {
      "@odata.id": "/redfish/v1/Oem/Pelx/Schedules/1"
    }
  ],
  "Members@odata.count": 1
}
```

### GET https://<host>/redfish/v1/Oem/Pelx/Schedules/{id}

取得單一排程。

```json
{
  "@odata.id": "/redfish/v1/Oem/Pelx/Schedules/1",
  "@odata.type": "#PelxSchedule.v1_0_0.PelxSchedule",
  "Id": "1",
  "Name": "Task 1",
  "Enabled": true,
  "Type": 1,
  "Month": 1,
  "Day": 1,
  "Weekday": 1,
  "Hour": 1,
  "Minute": 1,
  "SkipHoliday": true,
  "ExecuteOnBoot": true,
  "Command": "out",
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" }
    ],
    "Interfaces": [
      { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0101" },
      { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0102" }
    ]
  },
  "Arg": {
    "Action": 1
  },
  "Actions": {
    "#PelxSchedule.SetEnabled": {
      "target": "/redfish/v1/Oem/Pelx/Schedules/1/Actions/PelxSchedule.SetEnabled"
    }
  }
}
```

#### 欄位說明如下:

* **Id**: 排程唯一識別碼
* **Name**: 排程名稱
* **Enabled**: 是否啟用
* **Type**: 週期類型（1: 特定日期, 2: 每月, 3: 每週, 4: 每日, 5: 每小時）
* **Month**: 月份（1-12）
* **Day**: 日期（1-31）
* **Weekday**: 星期（1-7，1=星期日）
* **Hour**: 小時（0-23）
* **Minute**: 分鐘（0-59）
* **SkipHoliday**: 是否跳過假日
* **ExecuteOnBoot**: 開機補執行
* **Command**: 指令類型（目前 `out`；之後可擴充其他指令）
* **Links.Outlets**: OCP 插座資源連結（選填）；解析為對應的 `DO…` 位址
* **Links.Interfaces**: 可輸出控制之 Pelx 介面連結，**路徑 `{addr}` 須以 `DO` 開頭**（選填；與 `Links.Outlets` 至少擇一非空）
* **Arg.Action**: 指令動作（1: ON, 2: OFF, 3: RESTART, 4: MOMENTARY）
* **Oem.Pelx.SlaveTargets**: 串接從機目標（**僅雙網卡主機模式**；否則省略）
  * **DeviceId**: 串接裝置識別碼
  * **Interfaces**: 該裝置上的介面資源連結

主機模式範例（`Oem.Pelx` 僅在此條件下出現）：

```json
{
  "Oem": {
    "Pelx": {
      "SlaveTargets": [
        {
          "DeviceId": 1,
          "Interfaces": [
            { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0103" }
          ]
        }
      ]
    }
  }
}
```

#### task ↔ Redfish 欄位對照

| task (`/schedules`) | Redfish (`Oem/Pelx/Schedules`) |
|---------------------|-----------------------------------|
| `uId` | `Id` |
| `name` | `Name` |
| `run` | `Enabled` |
| `type` … `minute` | `Type` … `Minute` |
| `skipHoliday` | `SkipHoliday` |
| `executeOnBoot` | `ExecuteOnBoot` |
| `command` | `Command` |
| `arg.action` | `Arg.Action` |
| `arg.targets`（本機 `DO…` 位址） | `Links.Outlets`（→ `DO…`）+ `Links.Interfaces`（`DO…`） |
| `arg.slaveTargets[].id` | `Oem.Pelx.SlaveTargets[].DeviceId`（僅雙網卡主機） |
| `arg.slaveTargets[].targets`（`DO…` 位址） | `Oem.Pelx.SlaveTargets[].Interfaces[]`（僅雙網卡主機） |

> **Outlets 與 Interfaces 的選擇**：已在 OCP `Outlets` 曝光的插座，建議用 `Links.Outlets`；其餘僅能透過 `DO…` 位址操作的外接輸出設備（如 E-Port），用 `Links.Interfaces`。同一實體勿重複列入兩邊。查詢可用目標：`GET Oem/Pelx/Interfaces`，篩選 `addr` 以 `DO` 開頭者。

### POST https://<host>/redfish/v1/Oem/Pelx/Schedules

新增排程。request body 欄位同 `GET .../Schedules/{id}`，但可省略 `Id`、`Enabled`（新建時 task 預設啟用）與 `Actions`。

一般範例（每日排程，控制本機插座與 DO 介面）：

```json
{
  "Name": "Outlet daily on",
  "Type": 4,
  "Month": 1,
  "Day": 1,
  "Weekday": 1,
  "Hour": 8,
  "Minute": 30,
  "SkipHoliday": true,
  "ExecuteOnBoot": false,
  "Command": "out",
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" }
    ],
    "Interfaces": [
      { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0101" }
    ]
  },
  "Arg": {
    "Action": 1
  }
}
```

雙網卡主機模式可另加 `Oem.Pelx.SlaveTargets`（見上方「SlaveTargets 出現條件」）：

```json
{
  "Name": "Host schedule with slaves",
  "Type": 4,
  "Month": 1,
  "Day": 1,
  "Weekday": 1,
  "Hour": 2,
  "Minute": 0,
  "SkipHoliday": false,
  "ExecuteOnBoot": true,
  "Command": "out",
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" }
    ]
  },
  "Arg": {
    "Action": 2
  },
  "Oem": {
    "Pelx": {
      "SlaveTargets": [
        {
          "DeviceId": 1,
          "Interfaces": [
            { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0103" },
            { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0104" }
          ]
        },
        {
          "DeviceId": 2,
          "Interfaces": [
            { "@odata.id": "/redfish/v1/Oem/Pelx/Interfaces/DO0105" }
          ]
        }
      ]
    }
  }
}
```

#### 欄位說明如下:

* **Name**: 排程名稱（**Mandatory**）
* **Type**: 週期類型（**Mandatory**）；1 特定日期、2 每月、3 每週、4 每日、5 每小時
* **Month**: 月份 1–12；`Type` 為 1 時必填
* **Day**: 日期 1–31；`Type` 為 1 或 2 時必填
* **Weekday**: 星期 1–7（1=星期日）；`Type` 為 3 時必填
* **Hour**: 小時 0–23（**Mandatory**）
* **Minute**: 分鐘 0–59（**Mandatory**）
* **SkipHoliday**: 是否跳過假日（**Mandatory**）
* **ExecuteOnBoot**: 開機補執行（**Mandatory**）
* **Command**: 指令類型，目前固定 `out`（**Mandatory**）
* **Links.Outlets**: OCP 插座連結（選填）；與 `Links.Interfaces` 至少擇一非空
* **Links.Interfaces**: `DO` 開頭之 Pelx 介面連結（選填）
* **Arg.Action**: 指令動作（**Mandatory**）；1 ON、2 OFF、3 RESTART、4 MOMENTARY
* **Oem.Pelx.SlaveTargets**: 從機目標（選填；**僅雙網卡主機**）

成功時回 `201 Created`，`Location` 指向 `/redfish/v1/Oem/Pelx/Schedules/{id}`，body 為建立後的排程資源。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
201   | 建立成功
400   | 參數錯誤（含非主機模式帶 `SlaveTargets`、無效連結 URI）
401   | 未認證
403   | 權限不足

### PATCH https://<host>/redfish/v1/Oem/Pelx/Schedules/{id}

修改排程。，須送出**完整**排程內容（與 `POST` 相同欄位集合），不可僅送部分欄位。

```json
{
  "Name": "Outlet daily on (updated)",
  "Type": 4,
  "Month": 1,
  "Day": 1,
  "Weekday": 1,
  "Hour": 9,
  "Minute": 0,
  "SkipHoliday": true,
  "ExecuteOnBoot": false,
  "Command": "out",
  "Links": {
    "Outlets": [
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/1" },
      { "@odata.id": "/redfish/v1/PowerEquipment/RackPDUs/1/Outlets/2" }
    ],
    "Interfaces": []
  },
  "Arg": {
    "Action": 1
  }
}
```

僅變更啟用狀態時，請使用 `POST .../Actions/PelxSchedule.SetEnabled`，勿僅 PATCH `Enabled` 單一欄位。

#### 欄位說明如下:

* **id**（路徑參數）: 排程識別碼
* 其餘欄位同 `POST`；主機模式下可含 `Oem.Pelx.SlaveTargets`

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常；body 為更新後的排程資源
400   | 參數錯誤
401   | 未認證
403   | 權限不足
404   | 排程不存在

### DELETE https://<host>/redfish/v1/Oem/Pelx/Schedules/{id}

刪除排程。

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足
404   | 排程不存在

### POST https://<host>/redfish/v1/Oem/Pelx/Schedules/{id}/Actions/PelxSchedule.SetEnabled

啟用或停用排程。

```json
{
  "Enabled": true
}
```

#### 回傳資料狀態

狀態碼 | 說明
----- | -------------
200   | 正常
401   | 未認證
403   | 權限不足
404   | 排程不存在
