iobroker.smartfriends 1.2.0 → 1.3.0-alpha.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/README.md +5 -0
- package/io-package.json +14 -14
- package/lib/devices/DeviceCapabilityRegistry.js +57 -6
- package/lib/devices/DeviceKindCapabilities.js +65 -36
- package/lib/devices/EnumKindResolver.js +37 -0
- package/lib/devices/SchellenbergDevice.js +36 -15
- package/lib/devices/SchellenbergMasterDevice.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,11 @@ The adapter establishes a direct connection to the gateway to control and query
|
|
|
33
33
|
Placeholder for the next version (at the beginning of the line):
|
|
34
34
|
### __WORK IN PROGRESS__
|
|
35
35
|
-->
|
|
36
|
+
### 1.3.0-alpha.0 (2026-01-10)
|
|
37
|
+
|
|
38
|
+
- (Black-Thunder) Support for further device types was added
|
|
39
|
+
- (Black-Thunder) Umlauts in device names are now correctly parsed
|
|
40
|
+
|
|
36
41
|
### 1.2.0 (2026-01-09)
|
|
37
42
|
|
|
38
43
|
- (Black-Thunder) Timeout for initial device request was increased
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "smartfriends",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.3.0-alpha.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.3.0-alpha.0": {
|
|
7
|
+
"en": "Support for further device types was added\nUmlauts in device names are now correctly parsed",
|
|
8
|
+
"de": "Unterstützung für weitere Gerätetypen wurde hinzugefügt\nUmlaute in Gerätenamen werden nun korrekt dargestellt",
|
|
9
|
+
"ru": "Добавлена поддержка дополнительных типов устройств\nУмлауты в названиях устройств теперь правильно разобраны",
|
|
10
|
+
"pt": "Foi adicionado suporte para outros tipos de dispositivos\nUmlauts em nomes de dispositivos agora são corretamente analisados",
|
|
11
|
+
"nl": "Ondersteuning voor andere apparaattypes is toegevoegd\nUmlauts in apparaatnamen zijn nu correct ontleed",
|
|
12
|
+
"fr": "Un soutien pour d'autres types d'appareils a été ajouté\nUmlauts dans les noms de périphériques sont maintenant correctement analysés",
|
|
13
|
+
"it": "È stato aggiunto il supporto per ulteriori tipi di dispositivo\nI nomi dei dispositivi sono ora correttamente analizzati",
|
|
14
|
+
"es": "Se agregó soporte para nuevos tipos de dispositivos\nUmlauts en los nombres de los dispositivos ahora se analizan correctamente",
|
|
15
|
+
"pl": "Dodano wsparcie dla innych typów urządzeń\nKlauty w nazwach urządzeń są teraz poprawnie przefiltrowane",
|
|
16
|
+
"uk": "Додана підтримка подальших типів пристроїв\nУмлаути в назвах пристроїв тепер правильно припаровані",
|
|
17
|
+
"zh-cn": "添加了对更多设备类型的支持\n设备名称中的 Umlaut 现已正确解析"
|
|
18
|
+
},
|
|
6
19
|
"1.2.0": {
|
|
7
20
|
"en": "Timeout for initial device request was increased\nDevices without defined device type are ignored\nRefactored device handling and added support for further device types",
|
|
8
21
|
"de": "Timeout für erste Geräteanfrage wurde erhöht\nGeräte ohne definierten Gerätetyp werden ignoriert\nRefactored Device Handling und zusätzliche Unterstützung für weitere Gerätetypen",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "Przekształcona obsługa urządzenia: stany dynamiczne, usunięty biały typ, zgrupowane urządzenia pod master ID",
|
|
81
94
|
"uk": "Рефакторний пристрій обробки: динамічні стани, видалений тип білий список, вбудовані пристрої під магістр ID",
|
|
82
95
|
"zh-cn": "重构设备处理: 动态状态, 删除类型白名单, 主 ID 下分组设备"
|
|
83
|
-
},
|
|
84
|
-
"1.0.1": {
|
|
85
|
-
"en": "Increased robustness when communicating with the gateway\nAdded new option to ignore certificate errors",
|
|
86
|
-
"de": "Erhöhte Robustheit bei der Kommunikation mit dem Gateway\nNeue Option hinzugefügt, um Zertifikatsfehler zu ignorieren",
|
|
87
|
-
"ru": "Повышенная надежность при общении с шлюзом\nДобавлена новая возможность игнорировать ошибки сертификата",
|
|
88
|
-
"pt": "Maior robustez ao se comunicar com o gateway\nAdicionada nova opção para ignorar erros de certificado",
|
|
89
|
-
"nl": "Verhoogde robuustheid bij het communiceren met de gateway\nNieuwe optie toegevoegd om certificaatfouten te negeren",
|
|
90
|
-
"fr": "Une robustesse accrue lors de la communication avec la passerelle\nAjout d'une nouvelle option pour ignorer les erreurs de certificat",
|
|
91
|
-
"it": "Maggiore robustezza quando si comunica con il gateway\nAggiunta nuova opzione per ignorare gli errori del certificato",
|
|
92
|
-
"es": "Mayor robustez al comunicarse con la puerta de entrada\nNueva opción para ignorar errores de certificado",
|
|
93
|
-
"pl": "Większa odporność podczas komunikacji z bramą\nDodano nową opcję do ignorowania błędów certyfikatu",
|
|
94
|
-
"uk": "Підвищена надійність при спілкуванні з шлюзом\nДодано новий варіант ігнорувати помилки сертифіката",
|
|
95
|
-
"zh-cn": "与网关沟通时的强度提高\n添加新选项以忽略证书错误"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -29,13 +29,21 @@ const LevelKinds = {
|
|
|
29
29
|
*/
|
|
30
30
|
const SensorKinds = {
|
|
31
31
|
thermometer: {
|
|
32
|
-
role: "
|
|
32
|
+
role: "value.temperature",
|
|
33
33
|
desc: "Measured temperature",
|
|
34
34
|
unit: "°C",
|
|
35
35
|
defaultMin: -90,
|
|
36
36
|
defaultMax: 60,
|
|
37
37
|
defaultStep: 0.5,
|
|
38
38
|
},
|
|
39
|
+
luminanceDetector: {
|
|
40
|
+
role: "value.brightness ",
|
|
41
|
+
desc: "Measured brightness",
|
|
42
|
+
unit: "lux",
|
|
43
|
+
defaultMin: 0,
|
|
44
|
+
defaultMax: 150000,
|
|
45
|
+
defaultStep: 1,
|
|
46
|
+
},
|
|
39
47
|
volume: {
|
|
40
48
|
role: "value.rain",
|
|
41
49
|
desc: "Measured rain volume",
|
|
@@ -44,8 +52,18 @@ const SensorKinds = {
|
|
|
44
52
|
defaultMax: 350,
|
|
45
53
|
defaultStep: 1,
|
|
46
54
|
},
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
batteryLevel: {
|
|
56
|
+
role: "value.battery",
|
|
57
|
+
desc: "Battery level",
|
|
58
|
+
unit: "%",
|
|
59
|
+
defaultMin: 0,
|
|
60
|
+
defaultMax: 100,
|
|
61
|
+
defaultStep: 1,
|
|
62
|
+
},
|
|
63
|
+
// some devices are defined as "kind": "default", so this is a fallback
|
|
64
|
+
// generic sensor kind for different types of sensors (e.g. atmospheric pressure, wind speed, etc.)
|
|
65
|
+
genericSensor: {
|
|
66
|
+
kind: "measuredValue",
|
|
49
67
|
role: "value",
|
|
50
68
|
desc: "Measured value",
|
|
51
69
|
unit: "",
|
|
@@ -54,17 +72,50 @@ const SensorKinds = {
|
|
|
54
72
|
|
|
55
73
|
/**
|
|
56
74
|
* Declarative registry for device kinds that provide
|
|
57
|
-
* an
|
|
75
|
+
* an enumerated information
|
|
58
76
|
*/
|
|
59
|
-
const
|
|
77
|
+
const EnumStateKinds = {
|
|
60
78
|
failureStatus: {
|
|
61
79
|
role: "value",
|
|
62
80
|
desc: "Error code of the device",
|
|
63
81
|
},
|
|
82
|
+
smokeDetector: {
|
|
83
|
+
role: "sensor.alarm.fire",
|
|
84
|
+
desc: "Smoke detector state",
|
|
85
|
+
},
|
|
86
|
+
signal: {
|
|
87
|
+
kind: "rssi", // rename to make the purpose of the state clearer
|
|
88
|
+
role: "value",
|
|
89
|
+
desc: "Signal strength (RSSI)",
|
|
90
|
+
},
|
|
91
|
+
floodDetector: {
|
|
92
|
+
role: "sensor.alarm.flood",
|
|
93
|
+
desc: "Flood detector state",
|
|
94
|
+
},
|
|
95
|
+
genericEnum: {
|
|
96
|
+
role: "value",
|
|
97
|
+
desc: "Enumerated state",
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Declarative registry for device kinds that provide thermostat controls
|
|
103
|
+
*/
|
|
104
|
+
const ThermostatKinds = {
|
|
105
|
+
thermostat: {
|
|
106
|
+
kind: "targetTemperature", // rename to make the purpose of the state clearer
|
|
107
|
+
role: "level.temperature",
|
|
108
|
+
desc: "Target temperature",
|
|
109
|
+
unit: "°C",
|
|
110
|
+
defaultMin: 5,
|
|
111
|
+
defaultMax: 28,
|
|
112
|
+
defaultStep: 0.5,
|
|
113
|
+
},
|
|
64
114
|
};
|
|
65
115
|
|
|
66
116
|
module.exports = {
|
|
67
|
-
AlarmKinds,
|
|
68
117
|
LevelKinds,
|
|
69
118
|
SensorKinds,
|
|
119
|
+
EnumStateKinds,
|
|
120
|
+
ThermostatKinds,
|
|
70
121
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { resolveEnumKind } = require("./EnumKindResolver");
|
|
4
|
+
const { LevelKinds, SensorKinds, EnumStateKinds, ThermostatKinds } = require("./DeviceCapabilityRegistry");
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Resolves capabilities from a SmartFriends device definition
|
|
@@ -10,76 +11,104 @@ function getDeviceCapabilities(definition) {
|
|
|
10
11
|
return {
|
|
11
12
|
shouldBeCreated: false,
|
|
12
13
|
hasWritableStates: false,
|
|
13
|
-
hasSwitchingValues: false,
|
|
14
|
-
hasLevel: false,
|
|
15
|
-
hasSensor: false,
|
|
16
|
-
hasAlarm: false,
|
|
17
14
|
configObj: null,
|
|
18
15
|
};
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
const deviceType = definition
|
|
18
|
+
const deviceType = definition.deviceType;
|
|
22
19
|
const kind = deviceType.kind ?? "unknown";
|
|
23
|
-
const deviceDesignation = definition?.deviceDesignation?.replace(/\${|}/g, "") ?? kind;
|
|
24
20
|
const model = deviceType.model ?? "unknown";
|
|
21
|
+
const type = deviceType.type;
|
|
22
|
+
const name = (definition.deviceDesignation ?? kind).replace(/\${|}/g, "");
|
|
23
|
+
const configObj = { kind, name };
|
|
25
24
|
|
|
25
|
+
// SwitchingValues → always win
|
|
26
26
|
const switchingValues = Array.isArray(deviceType.switchingValues) ? deviceType.switchingValues : [];
|
|
27
|
-
|
|
28
27
|
const hasSwitchingValues = switchingValues.length > 0;
|
|
29
|
-
let configObj = {
|
|
30
|
-
kind,
|
|
31
|
-
name: deviceDesignation,
|
|
32
|
-
};
|
|
33
28
|
|
|
29
|
+
// Level actuators
|
|
34
30
|
const levelConfig = LevelKinds[kind] ?? null;
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
|
|
32
|
+
// Thermostat
|
|
33
|
+
const thermostatConfig = type === "actuator" && model === "analog" ? (ThermostatKinds[kind] ?? null) : null;
|
|
34
|
+
|
|
35
|
+
// Analog sensors
|
|
36
|
+
let sensorConfig = null;
|
|
37
|
+
if (type === "sensor" && model === "analog") {
|
|
38
|
+
if (SensorKinds[kind]) {
|
|
39
|
+
// Known sensor kind
|
|
40
|
+
sensorConfig = SensorKinds[kind];
|
|
41
|
+
} else if (kind === "default") {
|
|
42
|
+
// Generic fallback fo default kind
|
|
43
|
+
sensorConfig = SensorKinds.genericSensor;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Enum sensors (textOptions)
|
|
48
|
+
let enumStateConfig = null;
|
|
49
|
+
if (
|
|
50
|
+
type === "sensor" &&
|
|
51
|
+
model === "text" &&
|
|
52
|
+
Array.isArray(deviceType.textOptions) &&
|
|
53
|
+
deviceType.textOptions.some(opt => opt && typeof opt === "object" && "name" in opt)
|
|
54
|
+
) {
|
|
55
|
+
const enumKind = resolveEnumKind(definition, deviceType);
|
|
56
|
+
enumStateConfig = EnumStateKinds[enumKind] ?? EnumStateKinds.genericEnum;
|
|
57
|
+
}
|
|
37
58
|
|
|
38
59
|
if (levelConfig) {
|
|
39
|
-
configObj
|
|
40
|
-
|
|
60
|
+
Object.assign(configObj, {
|
|
61
|
+
kind: levelConfig.kind ?? configObj.kind,
|
|
41
62
|
role: levelConfig.role,
|
|
42
63
|
desc: levelConfig.desc,
|
|
43
64
|
unit: levelConfig.unit,
|
|
44
65
|
min: deviceType.min ?? levelConfig.defaultMin,
|
|
45
66
|
max: deviceType.max ?? levelConfig.defaultMax,
|
|
46
67
|
step: deviceType.step ?? levelConfig.defaultStep,
|
|
47
|
-
};
|
|
68
|
+
});
|
|
69
|
+
} else if (thermostatConfig) {
|
|
70
|
+
Object.assign(configObj, {
|
|
71
|
+
kind: thermostatConfig.kind ?? configObj.kind,
|
|
72
|
+
role: thermostatConfig.role,
|
|
73
|
+
desc: thermostatConfig.desc,
|
|
74
|
+
unit: thermostatConfig.unit,
|
|
75
|
+
min: deviceType.min ?? thermostatConfig.defaultMin,
|
|
76
|
+
max: deviceType.max ?? thermostatConfig.defaultMax,
|
|
77
|
+
step: deviceType.step ?? thermostatConfig.defaultStep,
|
|
78
|
+
});
|
|
48
79
|
} else if (sensorConfig) {
|
|
49
|
-
configObj
|
|
50
|
-
|
|
80
|
+
Object.assign(configObj, {
|
|
81
|
+
kind: sensorConfig.kind ?? configObj.kind,
|
|
51
82
|
role: sensorConfig.role,
|
|
52
83
|
desc: sensorConfig.desc,
|
|
53
84
|
unit: sensorConfig.unit,
|
|
54
85
|
min: deviceType.min ?? sensorConfig.defaultMin,
|
|
55
86
|
max: deviceType.max ?? sensorConfig.defaultMax,
|
|
56
87
|
step: deviceType.step ?? sensorConfig.defaultStep,
|
|
57
|
-
};
|
|
58
|
-
} else if (
|
|
59
|
-
configObj
|
|
60
|
-
|
|
61
|
-
role:
|
|
62
|
-
desc:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// map "textOptions" (if present) into configObj as enumerated states
|
|
66
|
-
if (deviceType.textOptions && Array.isArray(deviceType.textOptions) && deviceType.textOptions.length > 0) {
|
|
67
|
-
configObj.states = deviceType.textOptions.reduce((acc, opt) => {
|
|
68
|
-
acc[opt.value] = `${opt.state} (${opt.name.replace(/\${|}/g, "")})`;
|
|
88
|
+
});
|
|
89
|
+
} else if (enumStateConfig) {
|
|
90
|
+
Object.assign(configObj, {
|
|
91
|
+
kind: enumStateConfig.kind ?? configObj.kind,
|
|
92
|
+
role: enumStateConfig.role,
|
|
93
|
+
desc: enumStateConfig.desc,
|
|
94
|
+
states: deviceType.textOptions.reduce((acc, opt) => {
|
|
95
|
+
acc[opt.value] = opt.name.replace(/\${|}/g, "");
|
|
69
96
|
return acc;
|
|
70
|
-
}, {})
|
|
71
|
-
}
|
|
97
|
+
}, {}),
|
|
98
|
+
});
|
|
72
99
|
}
|
|
73
100
|
|
|
74
101
|
return {
|
|
75
102
|
// state creation decision
|
|
76
|
-
shouldBeCreated:
|
|
77
|
-
|
|
103
|
+
shouldBeCreated:
|
|
104
|
+
hasSwitchingValues || !!levelConfig || !!thermostatConfig || !!sensorConfig || !!enumStateConfig,
|
|
105
|
+
hasWritableStates: hasSwitchingValues || !!levelConfig || !!thermostatConfig,
|
|
78
106
|
// metadata for builders
|
|
79
107
|
hasSwitchingValues,
|
|
80
108
|
hasLevel: !!levelConfig,
|
|
109
|
+
hasThermostat: !!thermostatConfig,
|
|
81
110
|
hasSensor: !!sensorConfig,
|
|
82
|
-
|
|
111
|
+
hasEnumState: !!enumStateConfig,
|
|
83
112
|
// config object for state creation
|
|
84
113
|
configObj: configObj,
|
|
85
114
|
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves semantic enum type for devices with
|
|
5
|
+
* model=text + textOptions
|
|
6
|
+
*/
|
|
7
|
+
function resolveEnumKind(definition, deviceType) {
|
|
8
|
+
const designation = definition.deviceDesignation ?? "";
|
|
9
|
+
const kind = definition.kind ?? "";
|
|
10
|
+
const options = deviceType.textOptions ?? [];
|
|
11
|
+
|
|
12
|
+
// RSSI / signal strength
|
|
13
|
+
if (designation.includes("Rssi")) {
|
|
14
|
+
return "signal";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Failure status
|
|
18
|
+
if (kind.includes("failureStatus")) {
|
|
19
|
+
return "failureStatus";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Smoke detector
|
|
23
|
+
if (options.some(o => /smoke/i.test(o.valueState ?? ""))) {
|
|
24
|
+
return "smokeDetector";
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Flood / water
|
|
28
|
+
if (options.some(o => /water|flood/i.test(o.valueState ?? ""))) {
|
|
29
|
+
return "floodDetector";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return "genericEnum";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
resolveEnumKind,
|
|
37
|
+
};
|
|
@@ -26,10 +26,12 @@ class SchellenbergDevice {
|
|
|
26
26
|
|
|
27
27
|
devicePrefix = devicePrefix.replace(this.adapter.FORBIDDEN_CHARS, "");
|
|
28
28
|
|
|
29
|
+
// Umlauts are Unicode-escaped and need to be parsed here
|
|
30
|
+
const rawName = this.name.replace(/\${|}/g, "");
|
|
29
31
|
await this.adapter.setObjectNotExistsAsync(devicePrefix, {
|
|
30
32
|
type: "channel",
|
|
31
33
|
common: {
|
|
32
|
-
name:
|
|
34
|
+
name: JSON.parse(`"${rawName.replace(/\\\\/g, "\\")}"`),
|
|
33
35
|
},
|
|
34
36
|
native: {},
|
|
35
37
|
});
|
|
@@ -92,8 +94,8 @@ class SchellenbergDevice {
|
|
|
92
94
|
await this.createSensorState(infoPrefix, capabilities.configObj);
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
if (capabilities.
|
|
96
|
-
await this.
|
|
97
|
+
if (capabilities.hasEnumState) {
|
|
98
|
+
await this.createEnumState(infoPrefix, capabilities.configObj);
|
|
97
99
|
}
|
|
98
100
|
//#endregion
|
|
99
101
|
|
|
@@ -118,6 +120,10 @@ class SchellenbergDevice {
|
|
|
118
120
|
if (capabilities.hasLevel) {
|
|
119
121
|
await this.createLevelState(controlPrefix, capabilities.configObj);
|
|
120
122
|
}
|
|
123
|
+
|
|
124
|
+
if (capabilities.hasThermostat) {
|
|
125
|
+
await this.createThermostatState(controlPrefix, capabilities.configObj);
|
|
126
|
+
}
|
|
121
127
|
}
|
|
122
128
|
//#endregion
|
|
123
129
|
|
|
@@ -168,6 +174,25 @@ class SchellenbergDevice {
|
|
|
168
174
|
});
|
|
169
175
|
}
|
|
170
176
|
|
|
177
|
+
async createThermostatState(statePrefix, thermostatConfigObj) {
|
|
178
|
+
await this.adapter.setObjectNotExistsAsync(`${statePrefix}${thermostatConfigObj.kind}`, {
|
|
179
|
+
type: "state",
|
|
180
|
+
common: {
|
|
181
|
+
name: thermostatConfigObj.kind,
|
|
182
|
+
desc: thermostatConfigObj.desc,
|
|
183
|
+
type: "number",
|
|
184
|
+
role: thermostatConfigObj.role,
|
|
185
|
+
read: true,
|
|
186
|
+
write: true,
|
|
187
|
+
min: thermostatConfigObj.min,
|
|
188
|
+
max: thermostatConfigObj.max,
|
|
189
|
+
step: thermostatConfigObj.step,
|
|
190
|
+
unit: thermostatConfigObj.unit,
|
|
191
|
+
},
|
|
192
|
+
native: {},
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
171
196
|
async createSensorState(statePrefix, sensorConfigObj) {
|
|
172
197
|
await this.adapter.setObjectNotExistsAsync(`${statePrefix}${sensorConfigObj.kind}`, {
|
|
173
198
|
type: "state",
|
|
@@ -188,17 +213,17 @@ class SchellenbergDevice {
|
|
|
188
213
|
});
|
|
189
214
|
}
|
|
190
215
|
|
|
191
|
-
async
|
|
192
|
-
await this.adapter.setObjectNotExistsAsync(`${statePrefix}${
|
|
216
|
+
async createEnumState(statePrefix, enumConfigObj) {
|
|
217
|
+
await this.adapter.setObjectNotExistsAsync(`${statePrefix}${enumConfigObj.kind}`, {
|
|
193
218
|
type: "state",
|
|
194
219
|
common: {
|
|
195
|
-
name:
|
|
196
|
-
desc:
|
|
220
|
+
name: enumConfigObj.kind,
|
|
221
|
+
desc: enumConfigObj.desc,
|
|
197
222
|
type: "number",
|
|
198
|
-
role:
|
|
223
|
+
role: enumConfigObj.role,
|
|
199
224
|
read: true,
|
|
200
225
|
write: false,
|
|
201
|
-
states:
|
|
226
|
+
states: enumConfigObj.states,
|
|
202
227
|
},
|
|
203
228
|
native: {},
|
|
204
229
|
});
|
|
@@ -253,15 +278,11 @@ class SchellenbergDevice {
|
|
|
253
278
|
return;
|
|
254
279
|
}
|
|
255
280
|
|
|
256
|
-
if (capabilities.hasLevel) {
|
|
281
|
+
if (capabilities.hasLevel || capabilities.hasThermostat) {
|
|
257
282
|
await this.setDeviceStateValue(controlPrefix, capabilities.configObj, value);
|
|
258
283
|
}
|
|
259
284
|
|
|
260
|
-
if (capabilities.hasSensor) {
|
|
261
|
-
await this.setDeviceStateValue(infoPrefix, capabilities.configObj, value);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (capabilities.hasAlarm) {
|
|
285
|
+
if (capabilities.hasSensor || capabilities.hasEnumState) {
|
|
265
286
|
await this.setDeviceStateValue(infoPrefix, capabilities.configObj, value);
|
|
266
287
|
}
|
|
267
288
|
}
|
|
@@ -10,9 +10,12 @@ class SchellenbergMasterDevice {
|
|
|
10
10
|
|
|
11
11
|
async createMasterFolder() {
|
|
12
12
|
const masterPrefix = `${commonDefines.AdapterDatapointIDs.Devices}.${this.id.replace(this.adapter.FORBIDDEN_CHARS, "")}`;
|
|
13
|
+
|
|
14
|
+
// Umlauts are Unicode-escaped and need to be parsed here
|
|
15
|
+
const rawName = this.name.replace(/\${|}/g, "");
|
|
13
16
|
await this.adapter.setObjectNotExistsAsync(masterPrefix, {
|
|
14
17
|
type: "channel",
|
|
15
|
-
common: { name:
|
|
18
|
+
common: { name: JSON.parse(`"${rawName.replace(/\\\\/g, "\\")}"`) },
|
|
16
19
|
native: {},
|
|
17
20
|
});
|
|
18
21
|
|