iobroker.anomaly-detection 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +323 -0
- package/admin/anomaly-detection-icon.png +0 -0
- package/admin/anomaly-detection.png +0 -0
- package/admin/i18n/de.json +32 -0
- package/admin/i18n/en.json +32 -0
- package/admin/i18n/es.json +32 -0
- package/admin/i18n/fr.json +32 -0
- package/admin/i18n/it.json +32 -0
- package/admin/i18n/nl.json +32 -0
- package/admin/i18n/pl.json +32 -0
- package/admin/i18n/pt.json +32 -0
- package/admin/i18n/ru.json +32 -0
- package/admin/i18n/uk.json +32 -0
- package/admin/i18n/zh-cn.json +32 -0
- package/admin/jsonConfig.json +220 -0
- package/build/lib/advanced-detectors.js +149 -0
- package/build/lib/advanced-detectors.js.map +7 -0
- package/build/lib/context-value.js +42 -0
- package/build/lib/context-value.js.map +7 -0
- package/build/lib/detectors.js +76 -0
- package/build/lib/detectors.js.map +7 -0
- package/build/lib/history-provider.js +58 -0
- package/build/lib/history-provider.js.map +7 -0
- package/build/lib/history-source-resolver.js +109 -0
- package/build/lib/history-source-resolver.js.map +7 -0
- package/build/lib/model/contextual-model.js +98 -0
- package/build/lib/model/contextual-model.js.map +7 -0
- package/build/lib/model/statistics.js +78 -0
- package/build/lib/model/statistics.js.map +7 -0
- package/build/lib/model/temporal-model.js +98 -0
- package/build/lib/model/temporal-model.js.map +7 -0
- package/build/lib/scoring.js +57 -0
- package/build/lib/scoring.js.map +7 -0
- package/build/lib/source-cleanup.js +58 -0
- package/build/lib/source-cleanup.js.map +7 -0
- package/build/lib/source-monitor.js +348 -0
- package/build/lib/source-monitor.js.map +7 -0
- package/build/main.js +589 -0
- package/build/main.js.map +7 -0
- package/io-package.json +95 -0
- package/package.json +105 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Anomaly threshold": "Anomaly threshold",
|
|
3
|
+
"Context state ID": "ID do estado do contexto",
|
|
4
|
+
"Context states (maximum 3)": "Estados de contexto (máximo 3)",
|
|
5
|
+
"Enable context-aware detection": "Habilitar detecção baseada no contexto",
|
|
6
|
+
"Enable persistent level-shift detection": "Habilitar detecção persistente de mudança de nível",
|
|
7
|
+
"Enable rate-of-change detector": "Enable rate-of-change detector",
|
|
8
|
+
"Enable stuck-state detector": "Enable stuck-state detector",
|
|
9
|
+
"Enable trend detection": "Ativar detecção de tendências",
|
|
10
|
+
"Enable value deviation detector": "Enable value deviation detector",
|
|
11
|
+
"Enabled": "Enabled",
|
|
12
|
+
"History adapter instance": "History adapter instance",
|
|
13
|
+
"History availability": "History availability",
|
|
14
|
+
"History source": "History source",
|
|
15
|
+
"History training period (days)": "History training period (days)",
|
|
16
|
+
"Import existing history": "Import existing history",
|
|
17
|
+
"Initial training": "Initial training",
|
|
18
|
+
"Learn from live values only": "Learn from live values only",
|
|
19
|
+
"Maximum imported samples": "Maximum imported samples",
|
|
20
|
+
"Minimum anomaly duration (minutes)": "Minimum anomaly duration (minutes)",
|
|
21
|
+
"Minimum learned samples": "Amostras mínimas aprendidas",
|
|
22
|
+
"Monitored numerical states": "Monitored numerical states",
|
|
23
|
+
"Name": "Name",
|
|
24
|
+
"Numeric bucket width": "Largura numérica do intervalo",
|
|
25
|
+
"Sensitivity (robust z-score)": "Sensitivity (robust z-score)",
|
|
26
|
+
"Source state ID": "Source state ID",
|
|
27
|
+
"Start monitoring after history import": "Start monitoring after history import",
|
|
28
|
+
"Stuck duration (minutes)": "Stuck duration (minutes)",
|
|
29
|
+
"Time bucket size (minutes)": "Tamanho do intervalo de tempo (minutos)",
|
|
30
|
+
"Use time-of-day context": "Use time-of-day context",
|
|
31
|
+
"Use weekday context": "Use weekday context"
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Anomaly threshold": "Anomaly threshold",
|
|
3
|
+
"Context state ID": "Идентификатор состояния контекста",
|
|
4
|
+
"Context states (maximum 3)": "Состояния контекста (максимум 3)",
|
|
5
|
+
"Enable context-aware detection": "Включить контекстно-зависимое обнаружение",
|
|
6
|
+
"Enable persistent level-shift detection": "Включить постоянное обнаружение сдвига уровня",
|
|
7
|
+
"Enable rate-of-change detector": "Enable rate-of-change detector",
|
|
8
|
+
"Enable stuck-state detector": "Enable stuck-state detector",
|
|
9
|
+
"Enable trend detection": "Включить обнаружение тенденций",
|
|
10
|
+
"Enable value deviation detector": "Enable value deviation detector",
|
|
11
|
+
"Enabled": "Enabled",
|
|
12
|
+
"History adapter instance": "History adapter instance",
|
|
13
|
+
"History availability": "History availability",
|
|
14
|
+
"History source": "History source",
|
|
15
|
+
"History training period (days)": "History training period (days)",
|
|
16
|
+
"Import existing history": "Import existing history",
|
|
17
|
+
"Initial training": "Initial training",
|
|
18
|
+
"Learn from live values only": "Learn from live values only",
|
|
19
|
+
"Maximum imported samples": "Maximum imported samples",
|
|
20
|
+
"Minimum anomaly duration (minutes)": "Minimum anomaly duration (minutes)",
|
|
21
|
+
"Minimum learned samples": "Минимальные изученные образцы",
|
|
22
|
+
"Monitored numerical states": "Monitored numerical states",
|
|
23
|
+
"Name": "Name",
|
|
24
|
+
"Numeric bucket width": "Числовая ширина ковша",
|
|
25
|
+
"Sensitivity (robust z-score)": "Sensitivity (robust z-score)",
|
|
26
|
+
"Source state ID": "Source state ID",
|
|
27
|
+
"Start monitoring after history import": "Start monitoring after history import",
|
|
28
|
+
"Stuck duration (minutes)": "Stuck duration (minutes)",
|
|
29
|
+
"Time bucket size (minutes)": "Размер интервала времени (минуты)",
|
|
30
|
+
"Use time-of-day context": "Use time-of-day context",
|
|
31
|
+
"Use weekday context": "Use weekday context"
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Anomaly threshold": "Anomaly threshold",
|
|
3
|
+
"Context state ID": "Ідентифікатор стану контексту",
|
|
4
|
+
"Context states (maximum 3)": "Стани контексту (максимум 3)",
|
|
5
|
+
"Enable context-aware detection": "Увімкнути контекстне виявлення",
|
|
6
|
+
"Enable persistent level-shift detection": "Увімкнути постійне виявлення зміни рівня",
|
|
7
|
+
"Enable rate-of-change detector": "Enable rate-of-change detector",
|
|
8
|
+
"Enable stuck-state detector": "Enable stuck-state detector",
|
|
9
|
+
"Enable trend detection": "Увімкнути виявлення тенденції",
|
|
10
|
+
"Enable value deviation detector": "Enable value deviation detector",
|
|
11
|
+
"Enabled": "Enabled",
|
|
12
|
+
"History adapter instance": "History adapter instance",
|
|
13
|
+
"History availability": "History availability",
|
|
14
|
+
"History source": "History source",
|
|
15
|
+
"History training period (days)": "History training period (days)",
|
|
16
|
+
"Import existing history": "Import existing history",
|
|
17
|
+
"Initial training": "Initial training",
|
|
18
|
+
"Learn from live values only": "Learn from live values only",
|
|
19
|
+
"Maximum imported samples": "Maximum imported samples",
|
|
20
|
+
"Minimum anomaly duration (minutes)": "Minimum anomaly duration (minutes)",
|
|
21
|
+
"Minimum learned samples": "Мінімум вивчених зразків",
|
|
22
|
+
"Monitored numerical states": "Monitored numerical states",
|
|
23
|
+
"Name": "Name",
|
|
24
|
+
"Numeric bucket width": "Числова ширина відра",
|
|
25
|
+
"Sensitivity (robust z-score)": "Sensitivity (robust z-score)",
|
|
26
|
+
"Source state ID": "Source state ID",
|
|
27
|
+
"Start monitoring after history import": "Start monitoring after history import",
|
|
28
|
+
"Stuck duration (minutes)": "Stuck duration (minutes)",
|
|
29
|
+
"Time bucket size (minutes)": "Розмір інтервалу часу (хвилини)",
|
|
30
|
+
"Use time-of-day context": "Use time-of-day context",
|
|
31
|
+
"Use weekday context": "Use weekday context"
|
|
32
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Anomaly threshold": "Anomaly threshold",
|
|
3
|
+
"Context state ID": "上下文状态ID",
|
|
4
|
+
"Context states (maximum 3)": "上下文状态(最多 3 个)",
|
|
5
|
+
"Enable context-aware detection": "启用上下文感知检测",
|
|
6
|
+
"Enable persistent level-shift detection": "启用持续电平转换检测",
|
|
7
|
+
"Enable rate-of-change detector": "Enable rate-of-change detector",
|
|
8
|
+
"Enable stuck-state detector": "Enable stuck-state detector",
|
|
9
|
+
"Enable trend detection": "启用趋势检测",
|
|
10
|
+
"Enable value deviation detector": "Enable value deviation detector",
|
|
11
|
+
"Enabled": "Enabled",
|
|
12
|
+
"History adapter instance": "History adapter instance",
|
|
13
|
+
"History availability": "History availability",
|
|
14
|
+
"History source": "History source",
|
|
15
|
+
"History training period (days)": "History training period (days)",
|
|
16
|
+
"Import existing history": "Import existing history",
|
|
17
|
+
"Initial training": "Initial training",
|
|
18
|
+
"Learn from live values only": "Learn from live values only",
|
|
19
|
+
"Maximum imported samples": "Maximum imported samples",
|
|
20
|
+
"Minimum anomaly duration (minutes)": "Minimum anomaly duration (minutes)",
|
|
21
|
+
"Minimum learned samples": "最小学习样本",
|
|
22
|
+
"Monitored numerical states": "Monitored numerical states",
|
|
23
|
+
"Name": "Name",
|
|
24
|
+
"Numeric bucket width": "数字桶宽度",
|
|
25
|
+
"Sensitivity (robust z-score)": "Sensitivity (robust z-score)",
|
|
26
|
+
"Source state ID": "Source state ID",
|
|
27
|
+
"Start monitoring after history import": "Start monitoring after history import",
|
|
28
|
+
"Stuck duration (minutes)": "Stuck duration (minutes)",
|
|
29
|
+
"Time bucket size (minutes)": "时间段大小(分钟)",
|
|
30
|
+
"Use time-of-day context": "Use time-of-day context",
|
|
31
|
+
"Use weekday context": "Use weekday context"
|
|
32
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
{
|
|
2
|
+
"i18n": true,
|
|
3
|
+
"type": "panel",
|
|
4
|
+
"items": {
|
|
5
|
+
"sources": {
|
|
6
|
+
"type": "table",
|
|
7
|
+
"label": "Monitored numerical states",
|
|
8
|
+
"newLine": true,
|
|
9
|
+
"xs": 12,
|
|
10
|
+
"sm": 12,
|
|
11
|
+
"md": 12,
|
|
12
|
+
"lg": 12,
|
|
13
|
+
"xl": 12,
|
|
14
|
+
"uniqueColumns": ["id"],
|
|
15
|
+
"useCardFor": ["xs", "sm", "md", "lg", "xl"],
|
|
16
|
+
"titleAttribute": "id",
|
|
17
|
+
"items": [
|
|
18
|
+
{ "attr": "enabled", "type": "checkbox", "label": "Enabled", "default": true, "xs": 12 },
|
|
19
|
+
{
|
|
20
|
+
"attr": "id",
|
|
21
|
+
"type": "objectId",
|
|
22
|
+
"label": "Source state ID",
|
|
23
|
+
"types": "state",
|
|
24
|
+
"xs": 12
|
|
25
|
+
},
|
|
26
|
+
{ "attr": "name", "type": "text", "label": "Name", "default": "", "xs": 12 },
|
|
27
|
+
{
|
|
28
|
+
"attr": "initialTraining",
|
|
29
|
+
"type": "select",
|
|
30
|
+
"label": "Initial training",
|
|
31
|
+
"default": "live",
|
|
32
|
+
"xs": 6,
|
|
33
|
+
"options": [
|
|
34
|
+
{ "label": "Learn from live values only", "value": "live" },
|
|
35
|
+
{ "label": "Import existing history", "value": "history" }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"attr": "historyInstance",
|
|
40
|
+
"type": "selectSendTo",
|
|
41
|
+
"label": "History source (enabled compatible providers only)",
|
|
42
|
+
"default": "",
|
|
43
|
+
"xs": 6,
|
|
44
|
+
"command": "getHistoryProviders",
|
|
45
|
+
"jsonData": "{\"sourceId\": \"${data.id}\"}",
|
|
46
|
+
"alsoDependsOn": ["id"],
|
|
47
|
+
"manual": false,
|
|
48
|
+
"noTranslation": true,
|
|
49
|
+
"hidden": "data.initialTraining !== 'history'"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"attr": "trainingDays",
|
|
53
|
+
"type": "number",
|
|
54
|
+
"label": "History training period (days)",
|
|
55
|
+
"min": 7,
|
|
56
|
+
"max": 365,
|
|
57
|
+
"step": 1,
|
|
58
|
+
"default": 30,
|
|
59
|
+
"xs": 6,
|
|
60
|
+
"hidden": "data.initialTraining !== 'history'"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"attr": "maxHistorySamples",
|
|
64
|
+
"type": "number",
|
|
65
|
+
"label": "Maximum imported samples",
|
|
66
|
+
"min": 30,
|
|
67
|
+
"max": 10000,
|
|
68
|
+
"step": 10,
|
|
69
|
+
"default": 1000,
|
|
70
|
+
"xs": 6,
|
|
71
|
+
"hidden": "data.initialTraining !== 'history'"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"attr": "autoStartMonitoringAfterImport",
|
|
75
|
+
"type": "checkbox",
|
|
76
|
+
"label": "Start monitoring after history import",
|
|
77
|
+
"default": true,
|
|
78
|
+
"xs": 12,
|
|
79
|
+
"hidden": "data.initialTraining !== 'history'"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"attr": "minimumSamples",
|
|
83
|
+
"type": "number",
|
|
84
|
+
"label": "Minimum learned samples",
|
|
85
|
+
"min": 5,
|
|
86
|
+
"max": 240,
|
|
87
|
+
"step": 1,
|
|
88
|
+
"default": 30,
|
|
89
|
+
"xs": 6
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"attr": "bucketMinutes",
|
|
93
|
+
"type": "number",
|
|
94
|
+
"label": "Time bucket size (minutes)",
|
|
95
|
+
"min": 5,
|
|
96
|
+
"max": 720,
|
|
97
|
+
"step": 5,
|
|
98
|
+
"default": 60,
|
|
99
|
+
"xs": 6
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"attr": "sensitivity",
|
|
103
|
+
"type": "number",
|
|
104
|
+
"label": "Sensitivity (robust z-score)",
|
|
105
|
+
"min": 0.1,
|
|
106
|
+
"max": 20,
|
|
107
|
+
"step": 0.1,
|
|
108
|
+
"default": 3.5,
|
|
109
|
+
"xs": 6
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"attr": "anomalyThreshold",
|
|
113
|
+
"type": "number",
|
|
114
|
+
"label": "Anomaly threshold",
|
|
115
|
+
"min": 1,
|
|
116
|
+
"max": 100,
|
|
117
|
+
"step": 1,
|
|
118
|
+
"default": 70,
|
|
119
|
+
"xs": 6
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"attr": "minimumAnomalyDurationMinutes",
|
|
123
|
+
"type": "number",
|
|
124
|
+
"label": "Minimum anomaly duration (minutes)",
|
|
125
|
+
"min": 0,
|
|
126
|
+
"max": 10080,
|
|
127
|
+
"step": 1,
|
|
128
|
+
"default": 5,
|
|
129
|
+
"xs": 6
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"attr": "enableMad",
|
|
133
|
+
"type": "checkbox",
|
|
134
|
+
"label": "Enable value deviation detector",
|
|
135
|
+
"default": true,
|
|
136
|
+
"xs": 6
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"attr": "enableRate",
|
|
140
|
+
"type": "checkbox",
|
|
141
|
+
"label": "Enable rate-of-change detector",
|
|
142
|
+
"default": true,
|
|
143
|
+
"xs": 6
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"attr": "enableStuck",
|
|
147
|
+
"type": "checkbox",
|
|
148
|
+
"label": "Enable stuck-state detector",
|
|
149
|
+
"default": false,
|
|
150
|
+
"xs": 6
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"attr": "stuckDurationMinutes",
|
|
154
|
+
"type": "number",
|
|
155
|
+
"label": "Stuck duration (minutes)",
|
|
156
|
+
"min": 1,
|
|
157
|
+
"max": 10080,
|
|
158
|
+
"step": 1,
|
|
159
|
+
"default": 120,
|
|
160
|
+
"xs": 6
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"attr": "timeContext",
|
|
164
|
+
"type": "checkbox",
|
|
165
|
+
"label": "Use time-of-day context",
|
|
166
|
+
"default": true,
|
|
167
|
+
"xs": 6
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"attr": "weekdayContext",
|
|
171
|
+
"type": "checkbox",
|
|
172
|
+
"label": "Use weekday context",
|
|
173
|
+
"default": false,
|
|
174
|
+
"xs": 6
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"attr": "enableContext",
|
|
178
|
+
"type": "checkbox",
|
|
179
|
+
"label": "Enable context-aware detection",
|
|
180
|
+
"default": false,
|
|
181
|
+
"xs": 6
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"attr": "contextStates",
|
|
185
|
+
"type": "table",
|
|
186
|
+
"label": "Context states (maximum 3)",
|
|
187
|
+
"hidden": "data.enableContext !== true",
|
|
188
|
+
"xs": 12,
|
|
189
|
+
"items": [
|
|
190
|
+
{ "attr": "id", "type": "objectId", "label": "Context state ID", "types": "state", "xs": 8 },
|
|
191
|
+
{
|
|
192
|
+
"attr": "bucketWidth",
|
|
193
|
+
"type": "number",
|
|
194
|
+
"label": "Numeric bucket width",
|
|
195
|
+
"hidden": "await getObject(data.id)?.common?.type !== 'number'",
|
|
196
|
+
"min": 0.0001,
|
|
197
|
+
"max": 1000000,
|
|
198
|
+
"default": 5,
|
|
199
|
+
"xs": 4
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"attr": "enableChangePoint",
|
|
205
|
+
"type": "checkbox",
|
|
206
|
+
"label": "Enable persistent level-shift detection",
|
|
207
|
+
"default": false,
|
|
208
|
+
"xs": 6
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"attr": "enableTrend",
|
|
212
|
+
"type": "checkbox",
|
|
213
|
+
"label": "Enable trend detection",
|
|
214
|
+
"default": false,
|
|
215
|
+
"xs": 6
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var advanced_detectors_exports = {};
|
|
20
|
+
__export(advanced_detectors_exports, {
|
|
21
|
+
AdvancedDetectors: () => AdvancedDetectors
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(advanced_detectors_exports);
|
|
24
|
+
var import_statistics = require("./model/statistics");
|
|
25
|
+
const MAX_RECENT = 48;
|
|
26
|
+
const MIN_RECENT = 12;
|
|
27
|
+
const MIN_TREND_SPAN_MS = 6 * 60 * 60 * 1e3;
|
|
28
|
+
class AdvancedDetectors {
|
|
29
|
+
recentChange;
|
|
30
|
+
recentTrend;
|
|
31
|
+
candidateDirection;
|
|
32
|
+
candidateCount;
|
|
33
|
+
constructor(change, trend) {
|
|
34
|
+
this.recentChange = sanitize(change == null ? void 0 : change.recent);
|
|
35
|
+
this.recentTrend = sanitize(trend == null ? void 0 : trend.recent);
|
|
36
|
+
this.candidateDirection = change == null ? void 0 : change.candidateDirection;
|
|
37
|
+
this.candidateCount = Number.isInteger(change == null ? void 0 : change.candidateCount) ? Math.max(0, change.candidateCount) : 0;
|
|
38
|
+
}
|
|
39
|
+
observe(residual, timestamp, longMedian, longMad, enableChangePoint, enableTrend, sensitivity) {
|
|
40
|
+
if (residual === void 0 || !Number.isFinite(residual)) {
|
|
41
|
+
return { adapt: false };
|
|
42
|
+
}
|
|
43
|
+
if (enableChangePoint) {
|
|
44
|
+
append(this.recentChange, { value: residual, timestamp });
|
|
45
|
+
}
|
|
46
|
+
if (enableTrend) {
|
|
47
|
+
append(this.recentTrend, { value: residual, timestamp });
|
|
48
|
+
}
|
|
49
|
+
const changePoint = enableChangePoint ? this.detectChangePoint(longMedian, longMad, sensitivity) : void 0;
|
|
50
|
+
const trend = enableTrend ? this.detectTrend(sensitivity) : void 0;
|
|
51
|
+
return { changePoint, trend, adapt: changePoint !== void 0 };
|
|
52
|
+
}
|
|
53
|
+
toJSON() {
|
|
54
|
+
return {
|
|
55
|
+
changePoint: {
|
|
56
|
+
recent: [...this.recentChange],
|
|
57
|
+
candidateDirection: this.candidateDirection,
|
|
58
|
+
candidateCount: this.candidateCount
|
|
59
|
+
},
|
|
60
|
+
trend: { recent: [...this.recentTrend] }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
detectChangePoint(longMedian, longMad, sensitivity) {
|
|
64
|
+
if (this.recentChange.length < MIN_RECENT || longMedian === void 0 || longMad === void 0) {
|
|
65
|
+
this.resetCandidate();
|
|
66
|
+
return void 0;
|
|
67
|
+
}
|
|
68
|
+
const recentMedian = (0, import_statistics.median)(this.recentChange.slice(-MIN_RECENT).map((sample) => sample.value));
|
|
69
|
+
if (recentMedian === void 0) {
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
const delta = recentMedian - longMedian;
|
|
73
|
+
const scale = Math.max(longMad, 1e-9);
|
|
74
|
+
const normalized = Math.abs(delta) / scale;
|
|
75
|
+
if (normalized < sensitivity) {
|
|
76
|
+
this.resetCandidate();
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
const direction = delta >= 0 ? "upward" : "downward";
|
|
80
|
+
this.candidateCount = this.candidateDirection === direction ? this.candidateCount + 1 : 1;
|
|
81
|
+
this.candidateDirection = direction;
|
|
82
|
+
if (this.candidateCount < 3) {
|
|
83
|
+
return void 0;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
name: "changePoint",
|
|
87
|
+
score: (0, import_statistics.clamp)(normalized / sensitivity * 80, 70, 100),
|
|
88
|
+
reason: `Persistent ${direction} level shift detected`
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
detectTrend(sensitivity) {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
if (this.recentTrend.length < MIN_RECENT) {
|
|
94
|
+
return void 0;
|
|
95
|
+
}
|
|
96
|
+
const first = this.recentTrend[0];
|
|
97
|
+
const last = this.recentTrend[this.recentTrend.length - 1];
|
|
98
|
+
const span = last.timestamp - first.timestamp;
|
|
99
|
+
if (span < MIN_TREND_SPAN_MS) {
|
|
100
|
+
return void 0;
|
|
101
|
+
}
|
|
102
|
+
const slopes = [];
|
|
103
|
+
for (let left = 0; left < this.recentTrend.length; left++) {
|
|
104
|
+
for (let right = left + 1; right < this.recentTrend.length; right++) {
|
|
105
|
+
const elapsed = this.recentTrend[right].timestamp - this.recentTrend[left].timestamp;
|
|
106
|
+
if (elapsed > 0) {
|
|
107
|
+
slopes.push((this.recentTrend[right].value - this.recentTrend[left].value) / elapsed);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const slope = (0, import_statistics.median)(slopes);
|
|
112
|
+
const center = (_a = (0, import_statistics.median)(this.recentTrend.map((sample) => sample.value))) != null ? _a : 0;
|
|
113
|
+
const residualMad = (_b = (0, import_statistics.median)(this.recentTrend.map((sample) => Math.abs(sample.value - center)))) != null ? _b : 0;
|
|
114
|
+
if (slope === void 0) {
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
const normalized = Math.abs(slope * span) / Math.max(residualMad, 1e-9);
|
|
118
|
+
if (normalized < sensitivity) {
|
|
119
|
+
return void 0;
|
|
120
|
+
}
|
|
121
|
+
const direction = slope >= 0 ? "upward" : "downward";
|
|
122
|
+
return {
|
|
123
|
+
name: "trend",
|
|
124
|
+
score: (0, import_statistics.clamp)(normalized / sensitivity * 60, 55, 95),
|
|
125
|
+
reason: `Sustained ${direction} trend outside normal behavior`
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
resetCandidate() {
|
|
129
|
+
this.candidateDirection = void 0;
|
|
130
|
+
this.candidateCount = 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function append(target, value) {
|
|
134
|
+
if (target.length > 0 && value.timestamp <= target[target.length - 1].timestamp) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
target.push(value);
|
|
138
|
+
if (target.length > MAX_RECENT) {
|
|
139
|
+
target.splice(0, target.length - MAX_RECENT);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function sanitize(values) {
|
|
143
|
+
return (values != null ? values : []).filter((sample) => Number.isFinite(sample.value) && Number.isFinite(sample.timestamp)).sort((left, right) => left.timestamp - right.timestamp).slice(-MAX_RECENT);
|
|
144
|
+
}
|
|
145
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
146
|
+
0 && (module.exports = {
|
|
147
|
+
AdvancedDetectors
|
|
148
|
+
});
|
|
149
|
+
//# sourceMappingURL=advanced-detectors.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/advanced-detectors.ts"],
|
|
4
|
+
"sourcesContent": ["import { clamp, median } from \"./model/statistics\";\nimport type { DetectorResult } from \"./detectors\";\n\nexport interface TimedResidual {\n\tvalue: number;\n\ttimestamp: number;\n}\n\nexport interface ChangePointData {\n\trecent: TimedResidual[];\n\tcandidateDirection?: \"upward\" | \"downward\";\n\tcandidateCount: number;\n}\n\nexport interface TrendData {\n\trecent: TimedResidual[];\n}\n\nexport interface AdvancedEvaluation {\n\tchangePoint?: DetectorResult;\n\ttrend?: DetectorResult;\n\tadapt: boolean;\n}\n\nconst MAX_RECENT = 48;\nconst MIN_RECENT = 12;\nconst MIN_TREND_SPAN_MS = 6 * 60 * 60 * 1000;\n\n/** Maintains bounded residual windows for robust level-shift and trend evaluation. */\nexport class AdvancedDetectors {\n\tprivate recentChange: TimedResidual[];\n\tprivate recentTrend: TimedResidual[];\n\tprivate candidateDirection: \"upward\" | \"downward\" | undefined;\n\tprivate candidateCount: number;\n\n\tpublic constructor(change?: ChangePointData, trend?: TrendData) {\n\t\tthis.recentChange = sanitize(change?.recent);\n\t\tthis.recentTrend = sanitize(trend?.recent);\n\t\tthis.candidateDirection = change?.candidateDirection;\n\t\tthis.candidateCount = Number.isInteger(change?.candidateCount) ? Math.max(0, change!.candidateCount) : 0;\n\t}\n\n\tpublic observe(\n\t\tresidual: number | undefined,\n\t\ttimestamp: number,\n\t\tlongMedian: number | undefined,\n\t\tlongMad: number | undefined,\n\t\tenableChangePoint: boolean,\n\t\tenableTrend: boolean,\n\t\tsensitivity: number,\n\t): AdvancedEvaluation {\n\t\tif (residual === undefined || !Number.isFinite(residual)) {\n\t\t\treturn { adapt: false };\n\t\t}\n\t\tif (enableChangePoint) {\n\t\t\tappend(this.recentChange, { value: residual, timestamp });\n\t\t}\n\t\tif (enableTrend) {\n\t\t\tappend(this.recentTrend, { value: residual, timestamp });\n\t\t}\n\t\tconst changePoint = enableChangePoint ? this.detectChangePoint(longMedian, longMad, sensitivity) : undefined;\n\t\tconst trend = enableTrend ? this.detectTrend(sensitivity) : undefined;\n\t\treturn { changePoint, trend, adapt: changePoint !== undefined };\n\t}\n\n\tpublic toJSON(): { changePoint: ChangePointData; trend: TrendData } {\n\t\treturn {\n\t\t\tchangePoint: {\n\t\t\t\trecent: [...this.recentChange],\n\t\t\t\tcandidateDirection: this.candidateDirection,\n\t\t\t\tcandidateCount: this.candidateCount,\n\t\t\t},\n\t\t\ttrend: { recent: [...this.recentTrend] },\n\t\t};\n\t}\n\n\tprivate detectChangePoint(\n\t\tlongMedian: number | undefined,\n\t\tlongMad: number | undefined,\n\t\tsensitivity: number,\n\t): DetectorResult | undefined {\n\t\tif (this.recentChange.length < MIN_RECENT || longMedian === undefined || longMad === undefined) {\n\t\t\tthis.resetCandidate();\n\t\t\treturn undefined;\n\t\t}\n\t\tconst recentMedian = median(this.recentChange.slice(-MIN_RECENT).map(sample => sample.value));\n\t\tif (recentMedian === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst delta = recentMedian - longMedian;\n\t\tconst scale = Math.max(longMad, 1e-9);\n\t\tconst normalized = Math.abs(delta) / scale;\n\t\tif (normalized < sensitivity) {\n\t\t\tthis.resetCandidate();\n\t\t\treturn undefined;\n\t\t}\n\t\tconst direction = delta >= 0 ? \"upward\" : \"downward\";\n\t\tthis.candidateCount = this.candidateDirection === direction ? this.candidateCount + 1 : 1;\n\t\tthis.candidateDirection = direction;\n\t\tif (this.candidateCount < 3) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn {\n\t\t\tname: \"changePoint\",\n\t\t\tscore: clamp((normalized / sensitivity) * 80, 70, 100),\n\t\t\treason: `Persistent ${direction} level shift detected`,\n\t\t};\n\t}\n\n\tprivate detectTrend(sensitivity: number): DetectorResult | undefined {\n\t\tif (this.recentTrend.length < MIN_RECENT) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst first = this.recentTrend[0];\n\t\tconst last = this.recentTrend[this.recentTrend.length - 1];\n\t\tconst span = last.timestamp - first.timestamp;\n\t\tif (span < MIN_TREND_SPAN_MS) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst slopes: number[] = [];\n\t\tfor (let left = 0; left < this.recentTrend.length; left++) {\n\t\t\tfor (let right = left + 1; right < this.recentTrend.length; right++) {\n\t\t\t\tconst elapsed = this.recentTrend[right].timestamp - this.recentTrend[left].timestamp;\n\t\t\t\tif (elapsed > 0) {\n\t\t\t\t\tslopes.push((this.recentTrend[right].value - this.recentTrend[left].value) / elapsed);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tconst slope = median(slopes);\n\t\tconst center = median(this.recentTrend.map(sample => sample.value)) ?? 0;\n\t\tconst residualMad = median(this.recentTrend.map(sample => Math.abs(sample.value - center))) ?? 0;\n\t\tif (slope === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst normalized = Math.abs(slope * span) / Math.max(residualMad, 1e-9);\n\t\tif (normalized < sensitivity) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst direction = slope >= 0 ? \"upward\" : \"downward\";\n\t\treturn {\n\t\t\tname: \"trend\",\n\t\t\tscore: clamp((normalized / sensitivity) * 60, 55, 95),\n\t\t\treason: `Sustained ${direction} trend outside normal behavior`,\n\t\t};\n\t}\n\n\tprivate resetCandidate(): void {\n\t\tthis.candidateDirection = undefined;\n\t\tthis.candidateCount = 0;\n\t}\n}\n\nfunction append(target: TimedResidual[], value: TimedResidual): void {\n\tif (target.length > 0 && value.timestamp <= target[target.length - 1].timestamp) {\n\t\treturn;\n\t}\n\ttarget.push(value);\n\tif (target.length > MAX_RECENT) {\n\t\ttarget.splice(0, target.length - MAX_RECENT);\n\t}\n}\n\nfunction sanitize(values: readonly TimedResidual[] | undefined): TimedResidual[] {\n\treturn (values ?? [])\n\t\t.filter(sample => Number.isFinite(sample.value) && Number.isFinite(sample.timestamp))\n\t\t.sort((left, right) => left.timestamp - right.timestamp)\n\t\t.slice(-MAX_RECENT);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var context_value_exports = {};
|
|
20
|
+
__export(context_value_exports, {
|
|
21
|
+
createContextPart: () => createContextPart
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(context_value_exports);
|
|
24
|
+
function createContextPart(id, value, bucketWidth) {
|
|
25
|
+
if (typeof value === "boolean") {
|
|
26
|
+
return `${id}=boolean:${value}`;
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
29
|
+
const width = bucketWidth && bucketWidth > 0 ? bucketWidth : 5;
|
|
30
|
+
const start = Math.floor(value / width) * width;
|
|
31
|
+
return `${id}=number:${start}:${start + width}`;
|
|
32
|
+
}
|
|
33
|
+
if (typeof value === "string" && value.trim() && value.length <= 96) {
|
|
34
|
+
return `${id}=string:${value}`;
|
|
35
|
+
}
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
39
|
+
0 && (module.exports = {
|
|
40
|
+
createContextPart
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=context-value.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/context-value.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Creates a stable context-key fragment while preserving valid falsy boolean and numeric values.\n *\n * @param id Configured context state ID.\n * @param value Current context state value.\n * @param bucketWidth Optional width for numerical context buckets.\n */\nexport function createContextPart(\n\tid: string,\n\tvalue: ioBroker.StateValue | undefined,\n\tbucketWidth?: number,\n): string | undefined {\n\tif (typeof value === \"boolean\") {\n\t\treturn `${id}=boolean:${value}`;\n\t}\n\tif (typeof value === \"number\" && Number.isFinite(value)) {\n\t\tconst width = bucketWidth && bucketWidth > 0 ? bucketWidth : 5;\n\t\tconst start = Math.floor(value / width) * width;\n\t\treturn `${id}=number:${start}:${start + width}`;\n\t}\n\tif (typeof value === \"string\" && value.trim() && value.length <= 96) {\n\t\treturn `${id}=string:${value}`;\n\t}\n\treturn undefined;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,kBACf,IACA,OACA,aACqB;AACrB,MAAI,OAAO,UAAU,WAAW;AAC/B,WAAO,GAAG,EAAE,YAAY,KAAK;AAAA,EAC9B;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,GAAG;AACxD,UAAM,QAAQ,eAAe,cAAc,IAAI,cAAc;AAC7D,UAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,IAAI;AAC1C,WAAO,GAAG,EAAE,WAAW,KAAK,IAAI,QAAQ,KAAK;AAAA,EAC9C;AACA,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,KAAK,MAAM,UAAU,IAAI;AACpE,WAAO,GAAG,EAAE,WAAW,KAAK;AAAA,EAC7B;AACA,SAAO;AACR;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var detectors_exports = {};
|
|
20
|
+
__export(detectors_exports, {
|
|
21
|
+
detectMadDeviation: () => detectMadDeviation,
|
|
22
|
+
detectRateDeviation: () => detectRateDeviation,
|
|
23
|
+
detectStuck: () => detectStuck
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(detectors_exports);
|
|
26
|
+
var import_statistics = require("./model/statistics");
|
|
27
|
+
function detectMadDeviation(value, series, minimumSamples, sensitivity) {
|
|
28
|
+
if (series.count < minimumSamples) {
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
const median = series.median();
|
|
32
|
+
const mad = series.mad();
|
|
33
|
+
if (median === void 0 || mad === void 0) {
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
const deviation = Math.abs(value - median);
|
|
37
|
+
const robustZ = mad === 0 ? deviation === 0 ? 0 : Number.POSITIVE_INFINITY : 0.6745 * deviation / mad;
|
|
38
|
+
const score = robustZ === Number.POSITIVE_INFINITY ? 100 : (0, import_statistics.clamp)(robustZ / sensitivity * 100, 0, 100);
|
|
39
|
+
return { name: "value", score, reason: "Value is significantly outside the normal range for this time period" };
|
|
40
|
+
}
|
|
41
|
+
function detectRateDeviation(rate, series, minimumSamples, sensitivity) {
|
|
42
|
+
if (rate === void 0 || !Number.isFinite(rate) || series.count < minimumSamples) {
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
const median = series.median();
|
|
46
|
+
const mad = series.mad();
|
|
47
|
+
if (median === void 0 || mad === void 0) {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
const deviation = Math.abs(rate - median);
|
|
51
|
+
const robustZ = mad === 0 ? deviation === 0 ? 0 : Number.POSITIVE_INFINITY : 0.6745 * deviation / mad;
|
|
52
|
+
const score = robustZ === Number.POSITIVE_INFINITY ? 100 : (0, import_statistics.clamp)(robustZ / sensitivity * 100, 0, 100);
|
|
53
|
+
return { name: "rate", score, reason: "Rate of change is unusually high" };
|
|
54
|
+
}
|
|
55
|
+
function detectStuck(repeatedSince, timestamp, stuckDurationMinutes) {
|
|
56
|
+
if (repeatedSince === void 0 || timestamp < repeatedSince) {
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
const duration = timestamp - repeatedSince;
|
|
60
|
+
const limit = stuckDurationMinutes * 6e4;
|
|
61
|
+
if (limit <= 0 || duration < limit) {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
name: "stuck",
|
|
66
|
+
score: (0, import_statistics.clamp)(duration / limit * 50, 50, 100),
|
|
67
|
+
reason: "Value has remained unchanged significantly longer than configured"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
71
|
+
0 && (module.exports = {
|
|
72
|
+
detectMadDeviation,
|
|
73
|
+
detectRateDeviation,
|
|
74
|
+
detectStuck
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=detectors.js.map
|