Bugs #11493
進行中
[點位告警機制]規則與紀錄
概述
告警規則管理 (Alarm Rules)¶
告警規則初始由 CSV
ALARM欄位同步匯入,後續以 API 入 DB 為唯一來源,修改後立即生效不須重啟服務。
| Method | Uri | 說明 |
|---|---|---|
GET |
/api/v1/alarm-rules |
取得告警規則列表(支援 ?deviceId= 過濾) |
GET |
/api/v1/alarm-rules/{id} |
取得單一告警規則 |
POST |
/api/v1/alarm-rules |
新增告警規則 |
PUT |
/api/v1/alarm-rules/{id} |
修改告警規則 |
PATCH |
/api/v1/alarm-rules/{id}/toggle |
啟用/停用告警規則 |
DELETE |
/api/v1/alarm-rules/{id} |
刪除告警規則 |
// Response ✅ GET /api/v1/alarm-rules?deviceId=5
{
"code": 0, "message": "", "timestamp": 1740902400000,
"payload": [{
"id": 1, "deviceListId": 5, "deviceName": "電錶-01",
"alertId": "HighV", "alertName": "A相電壓高壓告警",
"functionId": "01_Vol_A", "operator": ">=", "threshold": 260.0,
"severity": "Warning",
"messageTemplate": "{DeviceName} A相電壓 {Value}V 超過門檻 {Threshold}V",
"isActive": true, "createdAt": "2026-03-02T00:00:00Z", "updatedAt": "2026-03-02T00:00:00Z"
}]
}
// Request: POST /api/v1/alarm-rules
{
"deviceListId": 5, "alertId": "HighV", "alertName": "A相電壓高壓告警",
"functionId": "01_Vol_A", "operator": ">=", "threshold": 260.0,
"severity": "Warning",
"messageTemplate": "{DeviceName} A相電壓 {Value}V 超過門檻 {Threshold}V",
"isActive": true
}
| 欄位 | 類型 | 說明 |
|---|---|---|
deviceListId |
整數 | 關聯設備 ID |
alertId |
字串 | 告警代碼,同一設備下不可重複(e.g., AR_HighV_1) Format: AR_{fun}_{no} |
functionId |
字串 | 觸發判斷的點位代碼。注意:若是 Modbus 設備,必須加上 群組_ 前綴(例如:01_Vol_A,對應 MQTT 上報之格式),不可僅填寫 Vol_A
|
operator |
字串 | 比較運算子:>=, <=, >, <, ==
|
threshold |
浮點數 | 告警門檻值 |
severity |
字串 | 告警等級:Warning / Critical
|
messageTemplate |
字串 | 訊息樣板,佔位符:{DeviceName}, {Value}, {Threshold}
|
isActive |
布林 | 是否啟用 |
💡 告警等級說明 (Severity)¶
系統目前提供兩種標準的告警等級,主要作為前端介面展示區分與管理員嚴重程度識別:
-
Warning(警告):
表示設備數據偏離正常範圍,但尚未危及整體系統運作或造成損壞。通常用於預防性維護或早期發現異常趨勢。
情境範例:機房溫度略高於標準、電壓出現微幅波動。 -
Critical(嚴重):
表示設備發生嚴重異常、狀態停機,或變數已達危險門檻,需要管理層或運維人員立即介入處理。
情境範例:設備斷電、機房溫度過高可能導致伺服器當機。
ℹ️ 系統行為關聯:
在當前的後端邏輯中,無論等級為Warning或Critical,一旦觸發告警,系統皆會:
- 將紀錄寫入
alarm_log(預設 Status = 0 未結案)。- 依照所屬系統 (EquipmentSystem) 在
system_config_mail的設定,自動派發 Email 或 LINE 訊息。- 目前尚未針對等級差異進行通知渠道的分流(例如:Warning 只發 Email、Critical 才發 LINE),這部分保留給後續業務邏輯或前端做彈性運用。
// PATCH /api/v1/alarm-rules/1/toggle
// Response ✅
{ "code": 0, "message": "告警規則已停用" }
關聯性資料表¶
| 資料表名稱 | 說明 |
|---|---|
| device_list | 設備清單 |
| device_alarm_rule | 告警規則 |
| alarm_log | 告警表 |
| system_config_mail | 通知群郵件紀錄 |
由 Sam Wang 於 14 天 前更新
新增規則範例¶
POST {{baseUrl}}/api/v1/alarm-rules
模組斷線告警¶
{
"deviceListId": 52,
"alertId": "Online",
"alertName": "14F燈控模組斷線告警",
"functionId": "Online",
"operator": "==",
"threshold": 0,
"severity": "Critical",
"messageTemplate": "{DeviceName} 發生斷線異常 (狀態值: {Value})",
"isActive": true
}
點位超出定義範圍告警¶
{
"deviceListId": 1,
"alertId": "HighV_2",
"alertName": "A相電壓高壓告警",
"functionId": "Vol_A",
"operator": ">=",
"threshold": 130,
"severity": "Warning",
"messageTemplate": "{DeviceName} A相電壓 {Value}V 超過門檻 {Threshold}V",
"isActive": true
}
SMTP 設置說明¶
寄件參數設置於 appsettings.json
{
"AppSettings":{
"EmailSettings": {
"SmtpHost": "smtp.gmail.com",
"SmtpPort": 587,
"SmtpUser": "sam8gamma@gmail.com",
"SmtpPass": "xxxxxxxxx",
"FromAddress": "sam8gamma@gmail.com",
"FromName": "IoTServer 系統"
}
}
}
以gmail 為例,"SmtpPass" 取得參考如下:
- App Password 只有在開啟「兩步驟驗證」後才會出現。
https://myaccount.google.com/security - 進入 App Passwords,建立應用程式,並取得16 位密碼
https://myaccount.google.com/apppasswords
由 Sam Wang 於 13 天 前更新
告警紀錄API¶
提供告警紀錄查詢、Excel 匯出及人工結案功能。
人工結案後系統將透過 MQTTclient/alarm廣播alarm.changed通知。
| Method | Uri | 說明 |
|---|---|---|
GET |
/api/v1/alarm-logs |
取得告警紀錄列表(分頁) |
GET |
/api/v1/alarm-logs/export |
匯出告警紀錄為 Excel |
PATCH |
/api/v1/alarm-logs/{alarmId}/close |
人工關閉指定告警 |
◉ 取得告警紀錄列表 [GET]¶
:::info
GET /api/v1/alarm-logs支援多條件篩選與分頁,預設以最新時間排序
:::
Query 參數
| 參數 | 類型 | 說明 |
|---|---|---|
page |
整數 | 頁碼(預設 1) |
pageSize |
整數 | 每頁筆數(預設 10) |
keyword |
字串 | 關鍵字搜尋(設備名稱、空間、告警描述) |
status |
整數 |
0=未結案,1=已結案(不填=全部) |
floor |
字串 | 依樓層篩選 |
startTime |
DateTimeOffset | 觸發時間起始(ISO 8601) |
endTime |
DateTimeOffset | 觸發時間結束(ISO 8601) |
:::spoiler Response ✅ 成功 (200 OK)
{
"code": 0,
"message": "Success",
"timestamp": 1741248000000,
"payload": {
"items": [
{
"id": 1,
"alarmId": "ALM-2026-0001",
"deviceName": "E1401 電錶",
"floor": "1F",
"space": "機房A",
"messageTemplate": "A相電壓 132.1V 超過門檻 120V",
"status": 0,
"triggerTime": "2026-03-06T13:49:02+08:00",
"closeTime": null
}
],
"page": 1,
"pageSize": 10,
"totalRecords": 25,
"totalPages": 3
}
}
:::
◉ 匯出告警紀錄為 Excel [GET]¶
:::info
GET /api/v1/alarm-logs/export依據當前查詢條件將結果匯出成 .xlsx 檔案
:::
Query 參數與取得列表相同(page/pageSize 無效,匯出全部符合條件的紀錄)。
Response: Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,瀏覽器直接下載 AlarmLogs_Export_yyyyMMddHHmmss.xlsx。
◉ 人工關閉告警 [PATCH]¶
:::info
PATCH /api/v1/alarm-logs/{alarmId}/close將指定告警標記為已完成,並透過 MQTT 廣播 alarm.changed 通知
:::
路由參數
| 參數 | 說明 |
|---|---|
alarmId |
告警的 AlarmId,例如 ALM-2026-0001
|
此端點無 Request Body。操作成功後,系統自動:
- 將
status設為1,記錄closeTime - 查詢當前
pendingCount(未結案告警數量) - 發布 MQTT 通知至
client/{OmniID}(與設備狀態異動機制一致)
:::spoiler MQTT 通知範例 (alarm.changed)
{
"system": "Omni_BC241195477F",
"timestamp": 1772787333837,
"cmd": "alarm.changed",
"payload": {
"alarmId": "ALM-2026-0001",
"deviceName": "E1401 電錶",
"message": "A相電壓 132.1V 超過門檻 120V",
"status": 1,
"triggerTime": "2026-03-06T13:49:02+08:00",
"closeTime": "2026-03-06T17:05:00+08:00",
"pendingCount": 4
}
}
:::
:::spoiler Response ✅ 成功 (200 OK)
{
"code": 0,
"message": "告警已成功結案,MQTT 通知已廣播。",
"timestamp": 1741248300000,
"payload": null
}
:::
:::spoiler Response ❌ 紀錄不存在或已結案
{
"code": 404,
"message": "AlarmId 'ALM-2026-0001' 不存在或已結案。",
"timestamp": 1741248300000,
"payload": null
}
:::
◉ 告警狀態異動通知 (alarm.changed)¶
當 alarm_log 產生或狀態變更(結案)時,系統主動廣播通知。前端訂閱 client/{OmniID} 即可接收所有告警異動事件。
觸發場景:
- 告警規則評估後新產生告警(
status: 0) - 告警條件解除,自動關閉(
status: 1) - 透過 API
PATCH /api/v1/alarm-logs/{alarmId}/close人工結案(status: 1)
| 方向 | MQTT 主題 | 訊息內容 |
|---|---|---|
| 通知 (Notify) | client/{OmniID} |
JSON 格式告警異動通知 |
:::spoiler Event Message Example (alarm.changed)
{
"system": "Omni_BC241195477F",
"timestamp": 1772787333837,
"cmd": "alarm.changed",
"payload": {
"alarmId": "ALM-2026-0001",
"deviceName": "E1401 電錶",
"message": "A相電壓 132.1V 超過門檻 120V",
"status": 0,
"triggerTime": "2026-03-06T13:49:02+08:00",
"closeTime": null,
"pendingCount": 5
}
}
Payload 欄位說明:
| 欄位 | 類型 | 說明 |
|---|---|---|
alarmId |
字串 | 告警唯一編號,例如 ALM-2026-0001
|
deviceName |
字串 | 設備名稱(快照) |
message |
字串 | 告警描述文字 |
status |
整數 |
0 = 未結案(新告警),1 = 已結案 |
triggerTime |
字串 | 觸發時間(本地時間,ISO 8601 格式含時區) |
closeTime |
字串/null | 結案時間(未結案時為 null) |
pendingCount |
整數 | 當前尚未結案告警總數量 |
| ::: |