@iobroker/mcp-server 0.0.2
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 +163 -0
- package/build/devices.d.ts +127 -0
- package/build/devices.js +752 -0
- package/build/devices.js.map +1 -0
- package/build/inProcessClient.d.ts +49 -0
- package/build/inProcessClient.js +76 -0
- package/build/inProcessClient.js.map +1 -0
- package/build/index.d.ts +202 -0
- package/build/index.js +1807 -0
- package/build/index.js.map +1 -0
- package/build/iob-uri.d.ts +20 -0
- package/build/iob-uri.js +108 -0
- package/build/iob-uri.js.map +1 -0
- package/build/types.d.ts +17 -0
- package/build/types.js +3 -0
- package/build/types.js.map +1 -0
- package/package.json +73 -0
package/build/devices.js
ADDED
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isValidSmartName = isValidSmartName;
|
|
37
|
+
exports.controls = controls;
|
|
38
|
+
exports.getAiFriendlyStructure = getAiFriendlyStructure;
|
|
39
|
+
/**
|
|
40
|
+
* Device detection utilities, ported from the ioBroker n8n nodes
|
|
41
|
+
* (`IoBrokerNodes/DevicesUtils.ts`).
|
|
42
|
+
*
|
|
43
|
+
* Uses the ioBroker type detector (https://github.com/ioBroker/ioBroker.type-detector)
|
|
44
|
+
* to turn raw states/channels/devices into "controls" (functional devices) and groups
|
|
45
|
+
* them into an AI-friendly structure of rooms -> devices -> named controls.
|
|
46
|
+
*
|
|
47
|
+
* All object reads accept an optional `{ user }` so the detection respects the ACLs of
|
|
48
|
+
* the configured default user (see McpServer).
|
|
49
|
+
*/
|
|
50
|
+
const type_detector_1 = __importStar(require("@iobroker/type-detector"));
|
|
51
|
+
/**
|
|
52
|
+
* Checks whether the provided value is a valid smart name.
|
|
53
|
+
*
|
|
54
|
+
* @param smartName The value to check
|
|
55
|
+
* @param lang Configured language
|
|
56
|
+
* @returns True if a valid smart name, false - otherwise.
|
|
57
|
+
*/
|
|
58
|
+
function isValidSmartName(smartName, lang) {
|
|
59
|
+
let name = smartName;
|
|
60
|
+
if (smartName === false || smartName === 'ignore') {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
if (smartName && typeof smartName === 'object') {
|
|
64
|
+
name = smartName[lang] || smartName.en || smartName.de;
|
|
65
|
+
}
|
|
66
|
+
return ![null, undefined, 'ignore', false].includes(name);
|
|
67
|
+
}
|
|
68
|
+
function isRoom(enumObject) {
|
|
69
|
+
return enumObject?._id?.startsWith('enum.rooms.');
|
|
70
|
+
}
|
|
71
|
+
function isFunctionality(enumObject) {
|
|
72
|
+
return enumObject?._id?.startsWith('enum.functions.');
|
|
73
|
+
}
|
|
74
|
+
async function allEnums(adapter, options) {
|
|
75
|
+
const result = await adapter.getObjectViewAsync('system', 'enum', {}, options);
|
|
76
|
+
return result.rows.map(row => row.value);
|
|
77
|
+
}
|
|
78
|
+
function parentOf(id) {
|
|
79
|
+
const parts = (id || '').split('.');
|
|
80
|
+
parts.pop();
|
|
81
|
+
return parts.join('.');
|
|
82
|
+
}
|
|
83
|
+
async function allObjects(adapter, options) {
|
|
84
|
+
const states = await adapter.getObjectViewAsync('system', 'state', {}, options);
|
|
85
|
+
const channels = await adapter.getObjectViewAsync('system', 'channel', {}, options);
|
|
86
|
+
const devices = await adapter.getObjectViewAsync('system', 'device', {}, options);
|
|
87
|
+
const enums = await adapter.getObjectViewAsync('system', 'enum', {}, options);
|
|
88
|
+
return states.rows
|
|
89
|
+
.concat(channels.rows)
|
|
90
|
+
.concat(devices.rows)
|
|
91
|
+
.concat(enums.rows)
|
|
92
|
+
.reduce((obj, item) => ((obj[item.id] = {
|
|
93
|
+
common: item.value?.common,
|
|
94
|
+
type: item.value?.type,
|
|
95
|
+
}),
|
|
96
|
+
obj), {});
|
|
97
|
+
}
|
|
98
|
+
function getSmartNameFromObj(obj, instanceId, noCommon) {
|
|
99
|
+
if (!obj) {
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
let result;
|
|
103
|
+
// If it is a common object
|
|
104
|
+
if (!obj.common) {
|
|
105
|
+
result = obj.smartName;
|
|
106
|
+
}
|
|
107
|
+
else if (!noCommon) {
|
|
108
|
+
result = obj.common.smartName;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
const custom = obj.common.custom;
|
|
112
|
+
if (!custom) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
result = custom[instanceId] ? custom[instanceId].smartName : undefined;
|
|
116
|
+
}
|
|
117
|
+
if (result && typeof result === 'string') {
|
|
118
|
+
if (result === 'ignore') {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
en: result,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
async function functionalitiesAndRooms(adapter, options) {
|
|
128
|
+
const enumerations = await allEnums(adapter, options);
|
|
129
|
+
// skip empty enums (with no members, i.e. states, assigned)
|
|
130
|
+
const notEmptyRoomsAndFunctionalities = enumerations
|
|
131
|
+
.filter(item => {
|
|
132
|
+
const smartName = getSmartNameFromObj(item, adapter.namespace);
|
|
133
|
+
return smartName !== false;
|
|
134
|
+
})
|
|
135
|
+
.filter(item => item?.common?.members?.length);
|
|
136
|
+
// all enums that are of type 'function'
|
|
137
|
+
const functionalities = notEmptyRoomsAndFunctionalities.filter(item => isFunctionality(item));
|
|
138
|
+
// all enums, that are of type 'room'
|
|
139
|
+
const rooms = notEmptyRoomsAndFunctionalities.filter(item => isRoom(item));
|
|
140
|
+
return [functionalities, rooms];
|
|
141
|
+
}
|
|
142
|
+
function getChannelId(id, objects) {
|
|
143
|
+
if (objects[id] && objects[id].type === 'channel') {
|
|
144
|
+
return id;
|
|
145
|
+
}
|
|
146
|
+
if (objects[id] && objects[id].type === 'state') {
|
|
147
|
+
const channelId = parentOf(id);
|
|
148
|
+
if (objects[channelId] && objects[channelId].type === 'channel') {
|
|
149
|
+
return channelId;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
function getDeviceId(id, objects) {
|
|
155
|
+
const channelId = getChannelId(id, objects);
|
|
156
|
+
if (channelId) {
|
|
157
|
+
const deviceId = parentOf(channelId);
|
|
158
|
+
if (objects[deviceId] && (objects[deviceId].type === 'device' || objects[deviceId].type === 'channel')) {
|
|
159
|
+
return deviceId;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Inspects all objects (states, channels and devices) and tries to identify so-called 'controls'
|
|
166
|
+
*
|
|
167
|
+
* To identify the controls, the ioBroker type detector library is used (https://github.com/ioBroker/ioBroker.type-detector).
|
|
168
|
+
*
|
|
169
|
+
* @param adapter The adapter instance
|
|
170
|
+
* @param lang language
|
|
171
|
+
* @param options read options (ACL user)
|
|
172
|
+
* @returns An array containing the detected controls
|
|
173
|
+
*/
|
|
174
|
+
async function controls(adapter, lang, options) {
|
|
175
|
+
// here we collect ids to inspect
|
|
176
|
+
const list = [];
|
|
177
|
+
// fetch all objects (states, channels and devices in terms of iobroker)
|
|
178
|
+
const devicesObject = await allObjects(adapter, options);
|
|
179
|
+
// fetch all defined rooms and functions (enumerations)
|
|
180
|
+
const [functionalities, rooms] = await functionalitiesAndRooms(adapter, options);
|
|
181
|
+
// every member of a function enumeration is added to the list of ids to inspect
|
|
182
|
+
functionalities.forEach(functionEnumItem => {
|
|
183
|
+
functionEnumItem.common.members?.forEach(id => {
|
|
184
|
+
const smartName = getSmartNameFromObj(devicesObject[id], adapter.namespace);
|
|
185
|
+
const objType = devicesObject[id]?.type;
|
|
186
|
+
if (devicesObject[id]?.common &&
|
|
187
|
+
(objType === 'state' || objType === 'channel' || objType === 'device') &&
|
|
188
|
+
!list.includes(id) &&
|
|
189
|
+
smartName !== false // if the device is not disabled
|
|
190
|
+
) {
|
|
191
|
+
list.push(id);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
// a member of a room enumeration is only added if neither its parent (channel) nor its grandparent (device) is in
|
|
196
|
+
rooms.forEach(roomEnumItem => {
|
|
197
|
+
roomEnumItem.common.members?.forEach(id => {
|
|
198
|
+
if (!devicesObject[id]) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const smartName = getSmartNameFromObj(devicesObject[id], adapter.namespace);
|
|
202
|
+
const objType = devicesObject[id].type;
|
|
203
|
+
if (devicesObject[id]?.common &&
|
|
204
|
+
(objType === 'state' || objType === 'channel' || objType === 'device') &&
|
|
205
|
+
!list.includes(id) &&
|
|
206
|
+
smartName !== false // if the device is not disabled
|
|
207
|
+
) {
|
|
208
|
+
const channelId = getChannelId(id, devicesObject);
|
|
209
|
+
if (channelId) {
|
|
210
|
+
if (!list.includes(channelId)) {
|
|
211
|
+
const deviceId = getDeviceId(id, devicesObject);
|
|
212
|
+
if (deviceId) {
|
|
213
|
+
if (!list.includes(deviceId)) {
|
|
214
|
+
list.push(id);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
list.push(id);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
list.push(id);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
// all ids, i.e. ids of all iobroker states/channels/devices
|
|
229
|
+
const keys = Object.keys(devicesObject).sort();
|
|
230
|
+
const idsWithSmartName = [];
|
|
231
|
+
// if a state has got a smart name directly assigned and neither itself nor its channel is in the list, add its id to the inspection list
|
|
232
|
+
// and process it first
|
|
233
|
+
keys.forEach(id => {
|
|
234
|
+
const smartName = devicesObject[id] && getSmartNameFromObj(devicesObject[id], adapter.namespace);
|
|
235
|
+
const objType = devicesObject[id].type;
|
|
236
|
+
if (isValidSmartName(smartName, lang) &&
|
|
237
|
+
devicesObject[id].common &&
|
|
238
|
+
(objType === 'state' || objType === 'channel' || objType === 'device')) {
|
|
239
|
+
idsWithSmartName.push(id);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
// collect first all smart names and remove them from the auto-groups
|
|
243
|
+
const detectedControls = [];
|
|
244
|
+
const detector = new type_detector_1.default();
|
|
245
|
+
const patterns = type_detector_1.default.getPatterns();
|
|
246
|
+
// process states with defined smartName
|
|
247
|
+
for (let s = 0; s < idsWithSmartName.length; s++) {
|
|
248
|
+
const id = idsWithSmartName[s];
|
|
249
|
+
const common = devicesObject[id].common;
|
|
250
|
+
const smartName = getSmartNameFromObj(devicesObject[id], adapter.namespace);
|
|
251
|
+
// try to convert the state to typeDetector format
|
|
252
|
+
// "smartName": {
|
|
253
|
+
// "de": "Rote Lampe",
|
|
254
|
+
// "smartType": "LIGHT", // optional
|
|
255
|
+
// "byON": 80 // optional
|
|
256
|
+
// }
|
|
257
|
+
if (!smartName.smartType) {
|
|
258
|
+
// by default,
|
|
259
|
+
// all booleans are sockets
|
|
260
|
+
// all numbers are dimmer
|
|
261
|
+
// string is not possible to control
|
|
262
|
+
if (common.type === 'boolean' || common.type === 'mixed') {
|
|
263
|
+
// we will write boolean
|
|
264
|
+
smartName.smartType = 'socket';
|
|
265
|
+
}
|
|
266
|
+
else if (common.type === 'number') {
|
|
267
|
+
smartName.smartType = 'dimmer';
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
smartName.smartType = 'socket';
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// try to simulate typeDetector format
|
|
274
|
+
if (patterns[smartName.smartType]) {
|
|
275
|
+
const control = JSON.parse(JSON.stringify(patterns[smartName.smartType]));
|
|
276
|
+
// find first required
|
|
277
|
+
const state = control.states.find(state => state.required);
|
|
278
|
+
if (state) {
|
|
279
|
+
state.id = id;
|
|
280
|
+
// process control
|
|
281
|
+
// remove all unassigned control register
|
|
282
|
+
control.states = control.states.filter(s => s.id);
|
|
283
|
+
// take all smartNames if any
|
|
284
|
+
control.states.forEach(s => {
|
|
285
|
+
s.smartName = getSmartNameFromObj(devicesObject[s.id], adapter.namespace);
|
|
286
|
+
s.common = {
|
|
287
|
+
min: devicesObject[s.id]?.common?.min,
|
|
288
|
+
max: devicesObject[s.id]?.common?.max,
|
|
289
|
+
type: devicesObject[s.id]?.common?.type,
|
|
290
|
+
states: devicesObject[s.id]?.common?.states,
|
|
291
|
+
unit: devicesObject[s.id]?.common?.unit,
|
|
292
|
+
role: devicesObject[s.id]?.common?.role,
|
|
293
|
+
name: devicesObject[s.id]?.common?.name,
|
|
294
|
+
icon: devicesObject[s.id]?.common?.icon,
|
|
295
|
+
color: devicesObject[s.id]?.common?.color,
|
|
296
|
+
};
|
|
297
|
+
});
|
|
298
|
+
devicesObject[id].common.smartName = smartName;
|
|
299
|
+
control.object = {
|
|
300
|
+
id,
|
|
301
|
+
type: devicesObject[id].type,
|
|
302
|
+
common: devicesObject[id].common,
|
|
303
|
+
autoDetected: false,
|
|
304
|
+
toggle: smartName?.toggle,
|
|
305
|
+
};
|
|
306
|
+
// remove id from the groups
|
|
307
|
+
let pos = list.indexOf(id);
|
|
308
|
+
if (pos !== -1) {
|
|
309
|
+
list.splice(pos, 1);
|
|
310
|
+
}
|
|
311
|
+
const channelId = getChannelId(id, devicesObject);
|
|
312
|
+
if (channelId) {
|
|
313
|
+
pos = list.indexOf(channelId);
|
|
314
|
+
if (pos !== -1) {
|
|
315
|
+
list.splice(pos, 1);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const name = smartName[lang] || smartName.en || smartName.de;
|
|
319
|
+
control.groupNames = name?.split(',').map(n => n.trim()) || [];
|
|
320
|
+
detectedControls.push(control);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
// initialize iobroker type detector
|
|
325
|
+
const usedIds = [];
|
|
326
|
+
const ignoreIndicators = ['UNREACH_STICKY']; // Ignore indicators by name
|
|
327
|
+
const excludedTypes = [type_detector_1.Types.info];
|
|
328
|
+
const detectOptions = {
|
|
329
|
+
objects: devicesObject,
|
|
330
|
+
_keysOptional: keys,
|
|
331
|
+
_usedIdsOptional: usedIds,
|
|
332
|
+
ignoreIndicators,
|
|
333
|
+
excludedTypes,
|
|
334
|
+
id: '', // this will be set for each id in the list
|
|
335
|
+
};
|
|
336
|
+
// go other the list of IDs to inspect and collect the detected controls
|
|
337
|
+
list.forEach(id => {
|
|
338
|
+
detectOptions.id = id;
|
|
339
|
+
const detected = detector.detect(detectOptions);
|
|
340
|
+
detected?.forEach(control => {
|
|
341
|
+
const iotControl = control;
|
|
342
|
+
// if any detected state has an ID, we can use this control
|
|
343
|
+
if (iotControl.states.find(state => state.id)) {
|
|
344
|
+
// remove all unassigned control register
|
|
345
|
+
iotControl.states = iotControl.states.filter(s => s.id);
|
|
346
|
+
// take all smartNames if any
|
|
347
|
+
iotControl.states.forEach(s => {
|
|
348
|
+
s.smartName = getSmartNameFromObj(devicesObject[s.id], adapter.namespace);
|
|
349
|
+
s.common = {
|
|
350
|
+
min: devicesObject[s.id]?.common?.min,
|
|
351
|
+
max: devicesObject[s.id]?.common?.max,
|
|
352
|
+
type: devicesObject[s.id]?.common?.type,
|
|
353
|
+
states: devicesObject[s.id]?.common?.states,
|
|
354
|
+
unit: devicesObject[s.id]?.common?.unit,
|
|
355
|
+
role: devicesObject[s.id]?.common?.role,
|
|
356
|
+
name: devicesObject[s.id]?.common?.name,
|
|
357
|
+
icon: devicesObject[s.id]?.common?.icon,
|
|
358
|
+
color: devicesObject[s.id]?.common?.color,
|
|
359
|
+
};
|
|
360
|
+
});
|
|
361
|
+
// find out the room the found control is in
|
|
362
|
+
const room = rooms.find(room => room?.common?.members?.includes(id));
|
|
363
|
+
// find out the functionality the found control assigned to
|
|
364
|
+
const functionality = functionalities.find(functionality => functionality?.common?.members?.includes(id));
|
|
365
|
+
const smartName = getSmartNameFromObj(devicesObject[id], adapter.namespace);
|
|
366
|
+
iotControl.object = {
|
|
367
|
+
id,
|
|
368
|
+
type: devicesObject[id].type,
|
|
369
|
+
common: {
|
|
370
|
+
min: devicesObject[id].common?.min,
|
|
371
|
+
max: devicesObject[id].common?.max,
|
|
372
|
+
type: devicesObject[id].common?.type,
|
|
373
|
+
states: devicesObject[id].common?.states,
|
|
374
|
+
role: devicesObject[id].common?.role,
|
|
375
|
+
name: devicesObject[id].common?.name,
|
|
376
|
+
icon: devicesObject[id].common?.icon,
|
|
377
|
+
color: devicesObject[id].common?.color,
|
|
378
|
+
smartName,
|
|
379
|
+
},
|
|
380
|
+
autoDetected: true,
|
|
381
|
+
toggle: smartName && typeof smartName === 'object' ? smartName.toggle : undefined,
|
|
382
|
+
};
|
|
383
|
+
iotControl.room = room
|
|
384
|
+
? {
|
|
385
|
+
id: room._id,
|
|
386
|
+
common: room.common,
|
|
387
|
+
}
|
|
388
|
+
: undefined;
|
|
389
|
+
iotControl.functionality = functionality
|
|
390
|
+
? {
|
|
391
|
+
id: functionality._id,
|
|
392
|
+
common: functionality.common,
|
|
393
|
+
}
|
|
394
|
+
: undefined;
|
|
395
|
+
detectedControls.push(iotControl);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
return detectedControls;
|
|
400
|
+
}
|
|
401
|
+
function getName(name, lang, id) {
|
|
402
|
+
if (typeof name === 'string') {
|
|
403
|
+
return name;
|
|
404
|
+
}
|
|
405
|
+
if (name) {
|
|
406
|
+
return name[lang] || name.en || Object.values(name)[0] || id.split('.').pop() || 'Unnamed';
|
|
407
|
+
}
|
|
408
|
+
return id?.split('.').pop() || 'Unnamed';
|
|
409
|
+
}
|
|
410
|
+
function getControlType(device, state) {
|
|
411
|
+
let smartType;
|
|
412
|
+
// Try to guess from Device Type
|
|
413
|
+
if (device.type === type_detector_1.Types.airCondition) {
|
|
414
|
+
if (state.name === 'SET') {
|
|
415
|
+
// set temperature
|
|
416
|
+
smartType = 'targetTemperature';
|
|
417
|
+
}
|
|
418
|
+
else if (state.name === 'ACTUAL') {
|
|
419
|
+
smartType = 'actualTemperature';
|
|
420
|
+
}
|
|
421
|
+
else if (state.name === 'SPEED') {
|
|
422
|
+
smartType = 'fanSpeed';
|
|
423
|
+
}
|
|
424
|
+
else if (state.name === 'POWER') {
|
|
425
|
+
smartType = 'power';
|
|
426
|
+
}
|
|
427
|
+
else if (state.name === 'HUMIDITY') {
|
|
428
|
+
smartType = 'humidity';
|
|
429
|
+
}
|
|
430
|
+
else if (state.name === 'BOOST') {
|
|
431
|
+
smartType = 'boostMode';
|
|
432
|
+
}
|
|
433
|
+
else if (state.name === 'SWING') {
|
|
434
|
+
if (state.common.type === 'boolean') {
|
|
435
|
+
smartType = 'swingOnOff';
|
|
436
|
+
}
|
|
437
|
+
else if (state.common.type === 'number') {
|
|
438
|
+
smartType = 'swingPosition';
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
else if (device.type === type_detector_1.Types.blind) {
|
|
443
|
+
if (state.name === 'SET') {
|
|
444
|
+
smartType = 'blindPosition';
|
|
445
|
+
}
|
|
446
|
+
else if (state.name === 'STOP') {
|
|
447
|
+
smartType = 'stop';
|
|
448
|
+
}
|
|
449
|
+
else if (state.name === 'OPEN') {
|
|
450
|
+
smartType = 'open';
|
|
451
|
+
}
|
|
452
|
+
else if (state.name === 'CLOSE') {
|
|
453
|
+
smartType = 'close';
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
else if (device.type === type_detector_1.Types.cie) {
|
|
457
|
+
if (state.name === 'CIE') {
|
|
458
|
+
// set temperature
|
|
459
|
+
smartType = 'color';
|
|
460
|
+
}
|
|
461
|
+
else if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
462
|
+
smartType = 'dimmer';
|
|
463
|
+
}
|
|
464
|
+
else if (state.name === 'TEMPERATURE') {
|
|
465
|
+
smartType = 'colorTemperature';
|
|
466
|
+
}
|
|
467
|
+
else if (state.name === 'ON') {
|
|
468
|
+
smartType = 'power';
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
else if (device.type === type_detector_1.Types.ct) {
|
|
472
|
+
if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
473
|
+
smartType = 'dimmer';
|
|
474
|
+
}
|
|
475
|
+
else if (state.name === 'TEMPERATURE') {
|
|
476
|
+
smartType = 'colorTemperature';
|
|
477
|
+
}
|
|
478
|
+
else if (state.name === 'ON') {
|
|
479
|
+
smartType = 'power';
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
else if (device.type === type_detector_1.Types.dimmer) {
|
|
483
|
+
if (state.name === 'SET') {
|
|
484
|
+
smartType = 'dimmer';
|
|
485
|
+
}
|
|
486
|
+
else if (state.name === 'ON') {
|
|
487
|
+
smartType = 'power';
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
else if (device.type === type_detector_1.Types.door) {
|
|
491
|
+
if (state.name === 'ACTUAL') {
|
|
492
|
+
smartType = 'openedClosed';
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
else if (device.type === type_detector_1.Types.fireAlarm) {
|
|
496
|
+
if (state.name === 'ACTUAL') {
|
|
497
|
+
smartType = 'alarm';
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (device.type === type_detector_1.Types.floodAlarm) {
|
|
501
|
+
if (state.name === 'ACTUAL') {
|
|
502
|
+
smartType = 'alarm';
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
else if (device.type === type_detector_1.Types.gate) {
|
|
506
|
+
if (state.name === 'SET') {
|
|
507
|
+
smartType = 'openClose';
|
|
508
|
+
}
|
|
509
|
+
else if (state.name === 'STOP') {
|
|
510
|
+
smartType = 'stop';
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
else if (device.type === type_detector_1.Types.hue) {
|
|
514
|
+
if (state.name === 'HUE') {
|
|
515
|
+
smartType = 'color';
|
|
516
|
+
}
|
|
517
|
+
else if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
518
|
+
smartType = 'dimmer';
|
|
519
|
+
}
|
|
520
|
+
else if (state.name === 'TEMPERATURE') {
|
|
521
|
+
smartType = 'colorTemperature';
|
|
522
|
+
}
|
|
523
|
+
else if (state.name === 'SATURATION') {
|
|
524
|
+
smartType = 'saturation';
|
|
525
|
+
}
|
|
526
|
+
else if (state.name === 'ON') {
|
|
527
|
+
smartType = 'power';
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
else if (device.type === type_detector_1.Types.humidity) {
|
|
531
|
+
if (state.name === 'ACTUAL') {
|
|
532
|
+
smartType = 'humidity';
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
else if (device.type === type_detector_1.Types.illuminance) {
|
|
536
|
+
if (state.name === 'ACTUAL') {
|
|
537
|
+
smartType = 'illuminance';
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
else if (device.type === type_detector_1.Types.slider) {
|
|
541
|
+
if (state.name === 'SET') {
|
|
542
|
+
smartType = 'level';
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
else if (device.type === type_detector_1.Types.light) {
|
|
546
|
+
if (state.name === 'SET') {
|
|
547
|
+
smartType = 'power';
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
else if (device.type === type_detector_1.Types.lock) {
|
|
551
|
+
if (state.name === 'SET') {
|
|
552
|
+
smartType = 'lock';
|
|
553
|
+
}
|
|
554
|
+
else if (state.name === 'OPEN') {
|
|
555
|
+
smartType = 'open';
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
else if (device.type === type_detector_1.Types.motion) {
|
|
559
|
+
if (state.name === 'ACTUAL') {
|
|
560
|
+
smartType = 'alarm';
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
else if (device.type === type_detector_1.Types.rgb) {
|
|
564
|
+
if (state.name === 'RED') {
|
|
565
|
+
smartType = 'colorRed';
|
|
566
|
+
}
|
|
567
|
+
else if (state.name === 'BLUE') {
|
|
568
|
+
smartType = 'colorBlue';
|
|
569
|
+
}
|
|
570
|
+
else if (state.name === 'GREEN') {
|
|
571
|
+
smartType = 'colorGreen';
|
|
572
|
+
}
|
|
573
|
+
else if (state.name === 'WHITE') {
|
|
574
|
+
smartType = 'colorWhite';
|
|
575
|
+
}
|
|
576
|
+
else if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
577
|
+
smartType = 'dimmer';
|
|
578
|
+
}
|
|
579
|
+
else if (state.name === 'TEMPERATURE') {
|
|
580
|
+
smartType = 'colorTemperature';
|
|
581
|
+
}
|
|
582
|
+
else if (state.name === 'ON') {
|
|
583
|
+
smartType = 'power';
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
else if (device.type === type_detector_1.Types.rgbSingle) {
|
|
587
|
+
if (state.name === 'RGB') {
|
|
588
|
+
smartType = 'color';
|
|
589
|
+
}
|
|
590
|
+
else if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
591
|
+
smartType = 'dimmer';
|
|
592
|
+
}
|
|
593
|
+
else if (state.name === 'TEMPERATURE') {
|
|
594
|
+
smartType = 'colorTemperature';
|
|
595
|
+
}
|
|
596
|
+
else if (state.name === 'ON') {
|
|
597
|
+
smartType = 'power';
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
else if (device.type === type_detector_1.Types.rgbwSingle) {
|
|
601
|
+
if (state.name === 'RGBW') {
|
|
602
|
+
smartType = 'color';
|
|
603
|
+
}
|
|
604
|
+
else if (state.name === 'DIMMER' || state.name === 'BRIGHTNESS') {
|
|
605
|
+
smartType = 'dimmer';
|
|
606
|
+
}
|
|
607
|
+
else if (state.name === 'TEMPERATURE') {
|
|
608
|
+
smartType = 'colorTemperature';
|
|
609
|
+
}
|
|
610
|
+
else if (state.name === 'ON') {
|
|
611
|
+
smartType = 'power';
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
else if (device.type === type_detector_1.Types.socket) {
|
|
615
|
+
if (state.name === 'SET') {
|
|
616
|
+
smartType = 'power';
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
else if (device.type === type_detector_1.Types.temperature) {
|
|
620
|
+
if (state.name === 'ACTUAL') {
|
|
621
|
+
smartType = 'actualTemperature';
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
else if (device.type === type_detector_1.Types.thermostat) {
|
|
625
|
+
if (state.name === 'ACTUAL') {
|
|
626
|
+
smartType = 'actualTemperature';
|
|
627
|
+
}
|
|
628
|
+
else if (state.name === 'SET') {
|
|
629
|
+
smartType = 'targetTemperature';
|
|
630
|
+
}
|
|
631
|
+
else if (state.name === 'HUMIDITY') {
|
|
632
|
+
smartType = 'humidity';
|
|
633
|
+
}
|
|
634
|
+
else if (state.name === 'BOOST') {
|
|
635
|
+
smartType = 'boostMode';
|
|
636
|
+
}
|
|
637
|
+
else if (state.name === 'POWER') {
|
|
638
|
+
smartType = 'power';
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
else if (device.type === type_detector_1.Types.vacuumCleaner) {
|
|
642
|
+
if (state.name === 'POWER') {
|
|
643
|
+
smartType = 'power';
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
else if (device.type === type_detector_1.Types.volume) {
|
|
647
|
+
if (state.name === 'SET') {
|
|
648
|
+
smartType = 'volume';
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
else if (device.type === type_detector_1.Types.volumeGroup) {
|
|
652
|
+
if (state.name === 'SET') {
|
|
653
|
+
smartType = 'volume';
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
else if (device.type === type_detector_1.Types.window) {
|
|
657
|
+
if (state.name === 'ACTUAL') {
|
|
658
|
+
smartType = 'openedClosed';
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
else if (device.type === type_detector_1.Types.windowTilt) {
|
|
662
|
+
if (state.name === 'ACTUAL') {
|
|
663
|
+
smartType = 'openedClosed';
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return smartType || state.name;
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Build an AI-friendly structure of rooms -> devices -> named controls.
|
|
670
|
+
*
|
|
671
|
+
* @param adapter The adapter instance
|
|
672
|
+
* @param lang language
|
|
673
|
+
* @param options read options (ACL user)
|
|
674
|
+
*/
|
|
675
|
+
async function getAiFriendlyStructure(adapter, lang, options) {
|
|
676
|
+
const devices = await controls(adapter, lang, options);
|
|
677
|
+
// Reformat the data
|
|
678
|
+
const rooms = [];
|
|
679
|
+
devices.forEach(device => {
|
|
680
|
+
let roomName;
|
|
681
|
+
let roomObj;
|
|
682
|
+
if (!device.room) {
|
|
683
|
+
// Create "No room" object
|
|
684
|
+
const rObj = rooms.find(r => r.roomName === 'No room');
|
|
685
|
+
if (rObj) {
|
|
686
|
+
roomObj = rObj;
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
roomObj = {
|
|
690
|
+
roomName: 'No room',
|
|
691
|
+
devicesInRoom: [],
|
|
692
|
+
};
|
|
693
|
+
rooms.push(roomObj);
|
|
694
|
+
}
|
|
695
|
+
roomName = 'No room';
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
roomName = getName(device.room.common.name, lang, device.room.id);
|
|
699
|
+
const rObj = rooms.find(r => r.roomName === roomName);
|
|
700
|
+
if (rObj) {
|
|
701
|
+
roomObj = rObj;
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
roomObj = {
|
|
705
|
+
roomName,
|
|
706
|
+
devicesInRoom: [],
|
|
707
|
+
};
|
|
708
|
+
rooms.push(roomObj);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const functionName = device.functionality
|
|
712
|
+
? getName(device.functionality.common.name, lang, device.functionality.id)
|
|
713
|
+
: undefined;
|
|
714
|
+
const dev = {
|
|
715
|
+
deviceName: getName(device.object?.common?.name, lang, device.object?.id || ''),
|
|
716
|
+
deviceType: device.type,
|
|
717
|
+
friendlyDeviceNames: device.groupNames,
|
|
718
|
+
controls: {},
|
|
719
|
+
};
|
|
720
|
+
if (roomName) {
|
|
721
|
+
dev.room = roomName;
|
|
722
|
+
}
|
|
723
|
+
if (functionName) {
|
|
724
|
+
dev.functionality = functionName;
|
|
725
|
+
}
|
|
726
|
+
// Fill controls
|
|
727
|
+
device.states.forEach(state => {
|
|
728
|
+
const control = {
|
|
729
|
+
stateId: state.id,
|
|
730
|
+
controlType: state.id === device.object?.id ? 'power' : state.role || 'power',
|
|
731
|
+
role: state.defaultRole,
|
|
732
|
+
writable: state.write !== false,
|
|
733
|
+
readable: state.read !== false,
|
|
734
|
+
unit: state.common?.unit || state.defaultUnit,
|
|
735
|
+
min: typeof state.min === 'number' ? state.min : undefined,
|
|
736
|
+
max: typeof state.max === 'number' ? state.max : undefined,
|
|
737
|
+
ioBrokerValueType: state.common?.type || 'boolean',
|
|
738
|
+
};
|
|
739
|
+
let smartType = state.smartName?.smartType;
|
|
740
|
+
if (!smartType) {
|
|
741
|
+
// Try to guess from Device Type
|
|
742
|
+
smartType = getControlType(device, state);
|
|
743
|
+
}
|
|
744
|
+
if (smartType) {
|
|
745
|
+
dev.controls[smartType] = control;
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
roomObj.devicesInRoom.push(dev);
|
|
749
|
+
});
|
|
750
|
+
return rooms;
|
|
751
|
+
}
|
|
752
|
+
//# sourceMappingURL=devices.js.map
|