iobroker.absolutehumidity 0.0.1
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 +138 -0
- package/admin/TabConfig.json +16 -0
- package/admin/absolutehumidity.svg +27 -0
- package/admin/i18n/de.json +23 -0
- package/admin/i18n/en.json +23 -0
- package/admin/i18n/es.json +23 -0
- package/admin/i18n/fr.json +23 -0
- package/admin/i18n/it.json +23 -0
- package/admin/i18n/nl.json +23 -0
- package/admin/i18n/pl.json +23 -0
- package/admin/i18n/pt.json +23 -0
- package/admin/i18n/ru.json +23 -0
- package/admin/i18n/uk.json +23 -0
- package/admin/i18n/zh-cn.json +23 -0
- package/admin/jsonConfig.json +50 -0
- package/io-package.json +109 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/modules/calculation.js +44 -0
- package/lib/modules/constants.js +19 -0
- package/lib/modules/deviceManager.js +312 -0
- package/lib/modules/i18n.js +209 -0
- package/lib/modules/idUtils.js +82 -0
- package/main.js +462 -0
- package/package.json +70 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// This file extends the AdapterConfig type from "@iobroker/types"
|
|
2
|
+
// using the actual properties present in io-package.json
|
|
3
|
+
// in order to provide typings for adapter.config properties
|
|
4
|
+
|
|
5
|
+
import { native } from '../io-package.json';
|
|
6
|
+
|
|
7
|
+
type _AdapterConfig = typeof native;
|
|
8
|
+
|
|
9
|
+
// Augment the globally declared type ioBroker.AdapterConfig
|
|
10
|
+
declare global {
|
|
11
|
+
namespace ioBroker {
|
|
12
|
+
interface AdapterConfig extends _AdapterConfig {
|
|
13
|
+
// Do not enter anything here!
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// this is required so the above AdapterConfig is found by TypeScript / type checking
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-param-description */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {number | null} temperature
|
|
6
|
+
* @param {number | null} relativeHumidity
|
|
7
|
+
*/
|
|
8
|
+
function calculateAbsoluteHumidity(temperature, relativeHumidity) {
|
|
9
|
+
if (temperature === null || relativeHumidity === null || relativeHumidity < 0 || relativeHumidity > 100) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const saturationVaporPressure = 6.112 * Math.exp((17.67 * temperature) / (temperature + 243.5));
|
|
14
|
+
const vaporPressure = (relativeHumidity / 100) * saturationVaporPressure;
|
|
15
|
+
|
|
16
|
+
return round((216.7 * vaporPressure) / (273.15 + temperature));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {number | null} temperature
|
|
21
|
+
* @param {number | null} relativeHumidity
|
|
22
|
+
*/
|
|
23
|
+
function calculateDewPointTemperature(temperature, relativeHumidity) {
|
|
24
|
+
if (temperature === null || relativeHumidity === null || relativeHumidity <= 0 || relativeHumidity > 100) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const alpha = Math.log(relativeHumidity / 100) + (17.62 * temperature) / (243.12 + temperature);
|
|
29
|
+
|
|
30
|
+
return round((243.12 * alpha) / (17.62 - alpha));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {number} value
|
|
35
|
+
*/
|
|
36
|
+
function round(value) {
|
|
37
|
+
return Math.round(value * 100) / 100;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
calculateAbsoluteHumidity,
|
|
42
|
+
calculateDewPointTemperature,
|
|
43
|
+
round,
|
|
44
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const DEVICE_ROOT = 'devices';
|
|
4
|
+
const STATE_TEMPERATURE = 'temperature';
|
|
5
|
+
const STATE_RELATIVE_HUMIDITY = 'relativeHumidity';
|
|
6
|
+
const STATE_ABSOLUTE_HUMIDITY = 'absoluteHumidity';
|
|
7
|
+
const STATE_DEW_POINT_TEMPERATURE = 'dewPointTemperature';
|
|
8
|
+
const CARD_HEADER_BACKGROUND = '#0f4c81';
|
|
9
|
+
const ADAPTER_ICON = 'adapter/absolutehumidity/absolutehumidity.svg';
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
ADAPTER_ICON,
|
|
13
|
+
CARD_HEADER_BACKGROUND,
|
|
14
|
+
DEVICE_ROOT,
|
|
15
|
+
STATE_ABSOLUTE_HUMIDITY,
|
|
16
|
+
STATE_DEW_POINT_TEMPERATURE,
|
|
17
|
+
STATE_RELATIVE_HUMIDITY,
|
|
18
|
+
STATE_TEMPERATURE,
|
|
19
|
+
};
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-jsdoc, jsdoc/require-param-description, jsdoc/reject-any-type */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { DeviceManagement } = require('@iobroker/dm-utils');
|
|
5
|
+
const {
|
|
6
|
+
ADAPTER_ICON,
|
|
7
|
+
CARD_HEADER_BACKGROUND,
|
|
8
|
+
STATE_ABSOLUTE_HUMIDITY,
|
|
9
|
+
STATE_DEW_POINT_TEMPERATURE,
|
|
10
|
+
STATE_RELATIVE_HUMIDITY,
|
|
11
|
+
STATE_TEMPERATURE,
|
|
12
|
+
} = require('./constants');
|
|
13
|
+
const { translate } = require('./i18n');
|
|
14
|
+
|
|
15
|
+
class AbsoluteHumidityDeviceManagement extends DeviceManagement {
|
|
16
|
+
/**
|
|
17
|
+
* @param {import('../../main')} adapter
|
|
18
|
+
*/
|
|
19
|
+
constructor(adapter) {
|
|
20
|
+
super(adapter, true);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
getInstanceInfo() {
|
|
24
|
+
return {
|
|
25
|
+
apiVersion: 'v3',
|
|
26
|
+
communicationStateId: 'info.deviceManager',
|
|
27
|
+
actions: [
|
|
28
|
+
{
|
|
29
|
+
id: 'addDevice',
|
|
30
|
+
icon: 'add',
|
|
31
|
+
title: {
|
|
32
|
+
en: '+ Add device',
|
|
33
|
+
de: '+ Gerät hinzufügen',
|
|
34
|
+
ru: '+ Добавить устройство',
|
|
35
|
+
pt: '+ Adicionar dispositivo',
|
|
36
|
+
nl: '+ Apparaat toevoegen',
|
|
37
|
+
fr: '+ Ajouter un appareil',
|
|
38
|
+
it: '+ Aggiungi dispositivo',
|
|
39
|
+
es: '+ Añadir dispositivo',
|
|
40
|
+
pl: '+ Dodaj urządzenie',
|
|
41
|
+
uk: '+ Додати пристрій',
|
|
42
|
+
'zh-cn': '+ 添加设备',
|
|
43
|
+
},
|
|
44
|
+
description: translate('Add a temperature and humidity device'),
|
|
45
|
+
color: CARD_HEADER_BACKGROUND,
|
|
46
|
+
backgroundColor: CARD_HEADER_BACKGROUND,
|
|
47
|
+
variant: 'contained',
|
|
48
|
+
style: {
|
|
49
|
+
backgroundColor: CARD_HEADER_BACKGROUND,
|
|
50
|
+
color: '#ffffff',
|
|
51
|
+
},
|
|
52
|
+
handler: async context => {
|
|
53
|
+
const data = await showDeviceForm(context, undefined);
|
|
54
|
+
|
|
55
|
+
if (!data) {
|
|
56
|
+
return { refresh: false };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
await this.adapter.addDevice(data);
|
|
60
|
+
return { refresh: true };
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {import('@iobroker/dm-utils').DeviceLoadContext<string>} context
|
|
69
|
+
*/
|
|
70
|
+
loadDevices(context) {
|
|
71
|
+
const devices = this.adapter.getConfiguredDevices();
|
|
72
|
+
|
|
73
|
+
context.setTotalDevices(devices.length);
|
|
74
|
+
|
|
75
|
+
for (const device of devices) {
|
|
76
|
+
context.addDevice(createDeviceInfo(this.adapter, device));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* @param {import('../../main')} adapter
|
|
83
|
+
* @param {Record<string, any>} device
|
|
84
|
+
*/
|
|
85
|
+
function createDeviceInfo(adapter, device) {
|
|
86
|
+
return {
|
|
87
|
+
id: device.id,
|
|
88
|
+
name: device.name,
|
|
89
|
+
icon: ADAPTER_ICON,
|
|
90
|
+
backgroundColor: CARD_HEADER_BACKGROUND,
|
|
91
|
+
status: 'connected',
|
|
92
|
+
actions: [
|
|
93
|
+
{
|
|
94
|
+
id: 'editDevice',
|
|
95
|
+
icon: 'edit',
|
|
96
|
+
description: translate('Edit device'),
|
|
97
|
+
handler: async (deviceId, context) => {
|
|
98
|
+
const existingDevice = adapter.getDeviceById(deviceId);
|
|
99
|
+
|
|
100
|
+
if (!existingDevice) {
|
|
101
|
+
await context.showMessage(translate('Device not found'));
|
|
102
|
+
return { refresh: 'none' };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const data = await showDeviceForm(context, existingDevice);
|
|
106
|
+
|
|
107
|
+
if (!data) {
|
|
108
|
+
return { refresh: 'none' };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
await adapter.updateDevice(deviceId, data);
|
|
112
|
+
return { refresh: 'devices' };
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'deleteDevice',
|
|
117
|
+
icon: 'delete',
|
|
118
|
+
description: translate('Delete device'),
|
|
119
|
+
color: 'secondary',
|
|
120
|
+
confirmation: translate('Delete this device?'),
|
|
121
|
+
handler: async deviceId => {
|
|
122
|
+
await adapter.deleteDevice(deviceId);
|
|
123
|
+
return { refresh: 'devices' };
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
customInfo: createDeviceCustomInfo(adapter, device),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {import('../../main')} adapter
|
|
133
|
+
* @param {Record<string, any>} device
|
|
134
|
+
*/
|
|
135
|
+
function createDeviceCustomInfo(adapter, device) {
|
|
136
|
+
return {
|
|
137
|
+
id: device.id,
|
|
138
|
+
schema: {
|
|
139
|
+
type: 'panel',
|
|
140
|
+
innerStyle: {
|
|
141
|
+
marginTop: 0,
|
|
142
|
+
paddingTop: 0,
|
|
143
|
+
},
|
|
144
|
+
items: {
|
|
145
|
+
temperature: createStateInfoItem(
|
|
146
|
+
translate('Temperature'),
|
|
147
|
+
device.createTemperatureState
|
|
148
|
+
? `${adapter.getDeviceObjectId(device.id)}.${STATE_TEMPERATURE}`
|
|
149
|
+
: device.temperatureStateId,
|
|
150
|
+
'°C',
|
|
151
|
+
!device.createTemperatureState,
|
|
152
|
+
),
|
|
153
|
+
relativeHumidity: createStateInfoItem(
|
|
154
|
+
translate('Relative humidity'),
|
|
155
|
+
device.createRelativeHumidityState
|
|
156
|
+
? `${adapter.getDeviceObjectId(device.id)}.${STATE_RELATIVE_HUMIDITY}`
|
|
157
|
+
: device.relativeHumidityStateId,
|
|
158
|
+
'%',
|
|
159
|
+
!device.createRelativeHumidityState,
|
|
160
|
+
),
|
|
161
|
+
absoluteHumidity: createStateInfoItem(
|
|
162
|
+
translate('Absolute humidity'),
|
|
163
|
+
`${adapter.getDeviceObjectId(device.id)}.${STATE_ABSOLUTE_HUMIDITY}`,
|
|
164
|
+
'g/m³',
|
|
165
|
+
false,
|
|
166
|
+
),
|
|
167
|
+
dewPointTemperature: createStateInfoItem(
|
|
168
|
+
translate('Dew point temperature'),
|
|
169
|
+
`${adapter.getDeviceObjectId(device.id)}.${STATE_DEW_POINT_TEMPERATURE}`,
|
|
170
|
+
'°C',
|
|
171
|
+
false,
|
|
172
|
+
),
|
|
173
|
+
spacer: {
|
|
174
|
+
type: 'staticText',
|
|
175
|
+
text: '',
|
|
176
|
+
newLine: true,
|
|
177
|
+
xs: 12,
|
|
178
|
+
sm: 12,
|
|
179
|
+
md: 12,
|
|
180
|
+
lg: 12,
|
|
181
|
+
xl: 12,
|
|
182
|
+
},
|
|
183
|
+
spacer2: {
|
|
184
|
+
type: 'staticText',
|
|
185
|
+
text: '',
|
|
186
|
+
newLine: true,
|
|
187
|
+
xs: 12,
|
|
188
|
+
sm: 12,
|
|
189
|
+
md: 12,
|
|
190
|
+
lg: 12,
|
|
191
|
+
xl: 12,
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {string} label
|
|
200
|
+
* @param {string} oid
|
|
201
|
+
* @param {string} unit
|
|
202
|
+
* @param {boolean} foreign
|
|
203
|
+
*/
|
|
204
|
+
function createStateInfoItem(label, oid, unit, foreign) {
|
|
205
|
+
return {
|
|
206
|
+
type: 'state',
|
|
207
|
+
label,
|
|
208
|
+
oid,
|
|
209
|
+
foreign,
|
|
210
|
+
control: 'text',
|
|
211
|
+
readOnly: true,
|
|
212
|
+
unit,
|
|
213
|
+
narrow: false,
|
|
214
|
+
addColon: true,
|
|
215
|
+
newLine: true,
|
|
216
|
+
xs: 12,
|
|
217
|
+
sm: 12,
|
|
218
|
+
md: 12,
|
|
219
|
+
lg: 12,
|
|
220
|
+
xl: 12,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @param {import('@iobroker/dm-utils').ActionContext} context
|
|
226
|
+
* @param {Record<string, any> | undefined} device
|
|
227
|
+
*/
|
|
228
|
+
async function showDeviceForm(context, device) {
|
|
229
|
+
return context.showForm(getDeviceFormSchema(), {
|
|
230
|
+
title: device ? translate('Edit device') : translate('Add device'),
|
|
231
|
+
data: device
|
|
232
|
+
? {
|
|
233
|
+
name: device.name,
|
|
234
|
+
temperatureStateId: device.temperatureStateId,
|
|
235
|
+
relativeHumidityStateId: device.relativeHumidityStateId,
|
|
236
|
+
createTemperatureState: device.createTemperatureState,
|
|
237
|
+
createRelativeHumidityState: device.createRelativeHumidityState,
|
|
238
|
+
}
|
|
239
|
+
: {
|
|
240
|
+
name: '',
|
|
241
|
+
temperatureStateId: '',
|
|
242
|
+
relativeHumidityStateId: '',
|
|
243
|
+
createTemperatureState: true,
|
|
244
|
+
createRelativeHumidityState: true,
|
|
245
|
+
},
|
|
246
|
+
buttons: ['apply', 'cancel'],
|
|
247
|
+
minWidth: 520,
|
|
248
|
+
applyDisabledRule: '!data.name || !data.temperatureStateId || !data.relativeHumidityStateId',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function getDeviceFormSchema() {
|
|
253
|
+
return {
|
|
254
|
+
type: 'panel',
|
|
255
|
+
items: {
|
|
256
|
+
name: {
|
|
257
|
+
type: 'text',
|
|
258
|
+
label: translate('Name'),
|
|
259
|
+
newLine: true,
|
|
260
|
+
xs: 12,
|
|
261
|
+
sm: 12,
|
|
262
|
+
},
|
|
263
|
+
temperatureStateId: {
|
|
264
|
+
type: 'objectId',
|
|
265
|
+
label: translate('Temperature state'),
|
|
266
|
+
newLine: true,
|
|
267
|
+
xs: 12,
|
|
268
|
+
sm: 12,
|
|
269
|
+
customFilter: {
|
|
270
|
+
type: 'state',
|
|
271
|
+
common: {
|
|
272
|
+
type: 'number',
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
createTemperatureState: {
|
|
277
|
+
type: 'checkbox',
|
|
278
|
+
label: translate('Create temperature state in adapter'),
|
|
279
|
+
newLine: true,
|
|
280
|
+
xs: 12,
|
|
281
|
+
sm: 12,
|
|
282
|
+
},
|
|
283
|
+
relativeHumidityStateId: {
|
|
284
|
+
type: 'objectId',
|
|
285
|
+
label: translate('Relative humidity state'),
|
|
286
|
+
newLine: true,
|
|
287
|
+
xs: 12,
|
|
288
|
+
sm: 12,
|
|
289
|
+
customFilter: {
|
|
290
|
+
type: 'state',
|
|
291
|
+
common: {
|
|
292
|
+
type: 'number',
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
createRelativeHumidityState: {
|
|
297
|
+
type: 'checkbox',
|
|
298
|
+
label: translate('Create relative humidity state in adapter'),
|
|
299
|
+
newLine: true,
|
|
300
|
+
xs: 12,
|
|
301
|
+
sm: 12,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
module.exports = {
|
|
308
|
+
AbsoluteHumidityDeviceManagement,
|
|
309
|
+
createDeviceInfo,
|
|
310
|
+
getDeviceFormSchema,
|
|
311
|
+
showDeviceForm,
|
|
312
|
+
};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-jsdoc */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const I18N = {
|
|
5
|
+
'Add device': {
|
|
6
|
+
en: 'Add device',
|
|
7
|
+
de: 'Gerät hinzufügen',
|
|
8
|
+
ru: 'Добавить устройство',
|
|
9
|
+
pt: 'Adicionar dispositivo',
|
|
10
|
+
nl: 'Apparaat toevoegen',
|
|
11
|
+
fr: 'Ajouter un appareil',
|
|
12
|
+
it: 'Aggiungi dispositivo',
|
|
13
|
+
es: 'Añadir dispositivo',
|
|
14
|
+
pl: 'Dodaj urządzenie',
|
|
15
|
+
uk: 'Додати пристрій',
|
|
16
|
+
'zh-cn': '添加设备',
|
|
17
|
+
},
|
|
18
|
+
'Add a temperature and humidity device': {
|
|
19
|
+
en: 'Add a temperature and humidity device',
|
|
20
|
+
de: 'Temperatur- und Luftfeuchte-Gerät hinzufügen',
|
|
21
|
+
ru: 'Добавить устройство температуры и влажности',
|
|
22
|
+
pt: 'Adicionar dispositivo de temperatura e umidade',
|
|
23
|
+
nl: 'Temperatuur- en vochtigheidsapparaat toevoegen',
|
|
24
|
+
fr: 'Ajouter un appareil de température et humidité',
|
|
25
|
+
it: 'Aggiungi dispositivo di temperatura e umidità',
|
|
26
|
+
es: 'Añadir dispositivo de temperatura y humedad',
|
|
27
|
+
pl: 'Dodaj urządzenie temperatury i wilgotności',
|
|
28
|
+
uk: 'Додати пристрій температури та вологості',
|
|
29
|
+
'zh-cn': '添加温湿度设备',
|
|
30
|
+
},
|
|
31
|
+
'Edit device': {
|
|
32
|
+
en: 'Edit device',
|
|
33
|
+
de: 'Gerät bearbeiten',
|
|
34
|
+
ru: 'Редактировать устройство',
|
|
35
|
+
pt: 'Editar dispositivo',
|
|
36
|
+
nl: 'Apparaat bewerken',
|
|
37
|
+
fr: "Modifier l'appareil",
|
|
38
|
+
it: 'Modifica dispositivo',
|
|
39
|
+
es: 'Editar dispositivo',
|
|
40
|
+
pl: 'Edytuj urządzenie',
|
|
41
|
+
uk: 'Редагувати пристрій',
|
|
42
|
+
'zh-cn': '编辑设备',
|
|
43
|
+
},
|
|
44
|
+
'Delete device': {
|
|
45
|
+
en: 'Delete device',
|
|
46
|
+
de: 'Gerät löschen',
|
|
47
|
+
ru: 'Удалить устройство',
|
|
48
|
+
pt: 'Excluir dispositivo',
|
|
49
|
+
nl: 'Apparaat verwijderen',
|
|
50
|
+
fr: "Supprimer l'appareil",
|
|
51
|
+
it: 'Elimina dispositivo',
|
|
52
|
+
es: 'Eliminar dispositivo',
|
|
53
|
+
pl: 'Usuń urządzenie',
|
|
54
|
+
uk: 'Видалити пристрій',
|
|
55
|
+
'zh-cn': '删除设备',
|
|
56
|
+
},
|
|
57
|
+
'Delete this device?': {
|
|
58
|
+
en: 'Delete this device?',
|
|
59
|
+
de: 'Dieses Gerät löschen?',
|
|
60
|
+
ru: 'Удалить это устройство?',
|
|
61
|
+
pt: 'Excluir este dispositivo?',
|
|
62
|
+
nl: 'Dit apparaat verwijderen?',
|
|
63
|
+
fr: 'Supprimer cet appareil ?',
|
|
64
|
+
it: 'Eliminare questo dispositivo?',
|
|
65
|
+
es: '¿Eliminar este dispositivo?',
|
|
66
|
+
pl: 'Usunąć to urządzenie?',
|
|
67
|
+
uk: 'Видалити цей пристрій?',
|
|
68
|
+
'zh-cn': '删除此设备?',
|
|
69
|
+
},
|
|
70
|
+
'Device not found': {
|
|
71
|
+
en: 'Device not found',
|
|
72
|
+
de: 'Gerät nicht gefunden',
|
|
73
|
+
ru: 'Устройство не найдено',
|
|
74
|
+
pt: 'Dispositivo não encontrado',
|
|
75
|
+
nl: 'Apparaat niet gevonden',
|
|
76
|
+
fr: 'Appareil introuvable',
|
|
77
|
+
it: 'Dispositivo non trovato',
|
|
78
|
+
es: 'Dispositivo no encontrado',
|
|
79
|
+
pl: 'Nie znaleziono urządzenia',
|
|
80
|
+
uk: 'Пристрій не знайдено',
|
|
81
|
+
'zh-cn': '未找到设备',
|
|
82
|
+
},
|
|
83
|
+
Name: {
|
|
84
|
+
en: 'Name',
|
|
85
|
+
de: 'Name',
|
|
86
|
+
ru: 'Имя',
|
|
87
|
+
pt: 'Nome',
|
|
88
|
+
nl: 'Naam',
|
|
89
|
+
fr: 'Nom',
|
|
90
|
+
it: 'Nome',
|
|
91
|
+
es: 'Nombre',
|
|
92
|
+
pl: 'Nazwa',
|
|
93
|
+
uk: "Ім'я",
|
|
94
|
+
'zh-cn': '名称',
|
|
95
|
+
},
|
|
96
|
+
Temperature: {
|
|
97
|
+
en: 'Temperature',
|
|
98
|
+
de: 'Temperatur',
|
|
99
|
+
ru: 'Температура',
|
|
100
|
+
pt: 'Temperatura',
|
|
101
|
+
nl: 'Temperatuur',
|
|
102
|
+
fr: 'Température',
|
|
103
|
+
it: 'Temperatura',
|
|
104
|
+
es: 'Temperatura',
|
|
105
|
+
pl: 'Temperatura',
|
|
106
|
+
uk: 'Температура',
|
|
107
|
+
'zh-cn': '温度',
|
|
108
|
+
},
|
|
109
|
+
'Temperature state': {
|
|
110
|
+
en: 'Temperature state',
|
|
111
|
+
de: 'Temperatur-State',
|
|
112
|
+
ru: 'Состояние температуры',
|
|
113
|
+
pt: 'Estado de temperatura',
|
|
114
|
+
nl: 'Temperatuurstate',
|
|
115
|
+
fr: 'État de température',
|
|
116
|
+
it: 'Stato temperatura',
|
|
117
|
+
es: 'Estado de temperatura',
|
|
118
|
+
pl: 'Stan temperatury',
|
|
119
|
+
uk: 'Стан температури',
|
|
120
|
+
'zh-cn': '温度状态',
|
|
121
|
+
},
|
|
122
|
+
'Create temperature state in adapter': {
|
|
123
|
+
en: 'Create temperature state in adapter',
|
|
124
|
+
de: 'Temperatur-State im Adapter anlegen',
|
|
125
|
+
ru: 'Создать состояние температуры в адаптере',
|
|
126
|
+
pt: 'Criar estado de temperatura no adaptador',
|
|
127
|
+
nl: 'Temperatuurstate in adapter aanmaken',
|
|
128
|
+
fr: "Créer l'état de température dans l'adaptateur",
|
|
129
|
+
it: "Crea stato temperatura nell'adattatore",
|
|
130
|
+
es: 'Crear estado de temperatura en el adaptador',
|
|
131
|
+
pl: 'Utwórz stan temperatury w adapterze',
|
|
132
|
+
uk: 'Створити стан температури в адаптері',
|
|
133
|
+
'zh-cn': '在适配器中创建温度状态',
|
|
134
|
+
},
|
|
135
|
+
'Relative humidity': {
|
|
136
|
+
en: 'Relative humidity',
|
|
137
|
+
de: 'Relative Luftfeuchte',
|
|
138
|
+
ru: 'Относительная влажность',
|
|
139
|
+
pt: 'Umidade relativa',
|
|
140
|
+
nl: 'Relatieve luchtvochtigheid',
|
|
141
|
+
fr: 'Humidité relative',
|
|
142
|
+
it: 'Umidità relativa',
|
|
143
|
+
es: 'Humedad relativa',
|
|
144
|
+
pl: 'Wilgotność względna',
|
|
145
|
+
uk: 'Відносна вологість',
|
|
146
|
+
'zh-cn': '相对湿度',
|
|
147
|
+
},
|
|
148
|
+
'Relative humidity state': {
|
|
149
|
+
en: 'Relative humidity state',
|
|
150
|
+
de: 'State für relative Luftfeuchte',
|
|
151
|
+
ru: 'Состояние относительной влажности',
|
|
152
|
+
pt: 'Estado de umidade relativa',
|
|
153
|
+
nl: 'Relatieve-luchtvochtigheidstate',
|
|
154
|
+
fr: "État d'humidité relative",
|
|
155
|
+
it: 'Stato umidità relativa',
|
|
156
|
+
es: 'Estado de humedad relativa',
|
|
157
|
+
pl: 'Stan wilgotności względnej',
|
|
158
|
+
uk: 'Стан відносної вологості',
|
|
159
|
+
'zh-cn': '相对湿度状态',
|
|
160
|
+
},
|
|
161
|
+
'Create relative humidity state in adapter': {
|
|
162
|
+
en: 'Create relative humidity state in adapter',
|
|
163
|
+
de: 'State für relative Luftfeuchte im Adapter anlegen',
|
|
164
|
+
ru: 'Создать состояние относительной влажности в адаптере',
|
|
165
|
+
pt: 'Criar estado de umidade relativa no adaptador',
|
|
166
|
+
nl: 'Relatieve-luchtvochtigheidstate in adapter aanmaken',
|
|
167
|
+
fr: "Créer l'état d'humidité relative dans l'adaptateur",
|
|
168
|
+
it: "Crea stato umidità relativa nell'adattatore",
|
|
169
|
+
es: 'Crear estado de humedad relativa en el adaptador',
|
|
170
|
+
pl: 'Utwórz stan wilgotności względnej w adapterze',
|
|
171
|
+
uk: 'Створити стан відносної вологості в адаптері',
|
|
172
|
+
'zh-cn': '在适配器中创建相对湿度状态',
|
|
173
|
+
},
|
|
174
|
+
'Absolute humidity': {
|
|
175
|
+
en: 'Absolute humidity',
|
|
176
|
+
de: 'Absolute Luftfeuchte',
|
|
177
|
+
ru: 'Абсолютная влажность',
|
|
178
|
+
pt: 'Umidade absoluta',
|
|
179
|
+
nl: 'Absolute luchtvochtigheid',
|
|
180
|
+
fr: 'Humidité absolue',
|
|
181
|
+
it: 'Umidità assoluta',
|
|
182
|
+
es: 'Humedad absoluta',
|
|
183
|
+
pl: 'Wilgotność bezwzględna',
|
|
184
|
+
uk: 'Абсолютна вологість',
|
|
185
|
+
'zh-cn': '绝对湿度',
|
|
186
|
+
},
|
|
187
|
+
'Dew point temperature': {
|
|
188
|
+
en: 'Dew point temperature',
|
|
189
|
+
de: 'Taupunkttemperatur',
|
|
190
|
+
ru: 'Температура точки росы',
|
|
191
|
+
pt: 'Temperatura do ponto de orvalho',
|
|
192
|
+
nl: 'Dauwpunttemperatuur',
|
|
193
|
+
fr: 'Température du point de rosée',
|
|
194
|
+
it: 'Temperatura del punto di rugiada',
|
|
195
|
+
es: 'Temperatura del punto de rocío',
|
|
196
|
+
pl: 'Temperatura punktu rosy',
|
|
197
|
+
uk: 'Температура точки роси',
|
|
198
|
+
'zh-cn': '露点温度',
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
function translate(text) {
|
|
203
|
+
return I18N[text] || text;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
I18N,
|
|
208
|
+
translate,
|
|
209
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* eslint-disable jsdoc/require-param-description, jsdoc/reject-any-type */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} name
|
|
6
|
+
* @param {Record<string, any>[]} devices
|
|
7
|
+
*/
|
|
8
|
+
function createUniqueDeviceId(name, devices) {
|
|
9
|
+
const usedIds = new Set(devices.map(device => device.id));
|
|
10
|
+
const baseId = sanitizeId(name || 'device');
|
|
11
|
+
const id = createUniqueIdFromBase(baseId, usedIds);
|
|
12
|
+
|
|
13
|
+
usedIds.add(id);
|
|
14
|
+
|
|
15
|
+
return id;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} baseId
|
|
20
|
+
* @param {Set<string>} usedIds
|
|
21
|
+
*/
|
|
22
|
+
function createUniqueIdFromBase(baseId, usedIds) {
|
|
23
|
+
let id = baseId;
|
|
24
|
+
let index = 2;
|
|
25
|
+
|
|
26
|
+
while (usedIds.has(id)) {
|
|
27
|
+
id = `${baseId}_${index}`;
|
|
28
|
+
index++;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return id;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} value
|
|
36
|
+
*/
|
|
37
|
+
function sanitizeId(value) {
|
|
38
|
+
const id = replaceGermanUmlauts(String(value))
|
|
39
|
+
.normalize('NFKD')
|
|
40
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
41
|
+
.toLowerCase()
|
|
42
|
+
.trim()
|
|
43
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
44
|
+
.replace(/^_+|_+$/g, '');
|
|
45
|
+
|
|
46
|
+
return id || 'device';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {string} value
|
|
51
|
+
*/
|
|
52
|
+
function legacySanitizeId(value) {
|
|
53
|
+
const id = String(value)
|
|
54
|
+
.toLowerCase()
|
|
55
|
+
.trim()
|
|
56
|
+
.replace(/[^a-z0-9]+/g, '_')
|
|
57
|
+
.replace(/^_+|_+$/g, '');
|
|
58
|
+
|
|
59
|
+
return id || 'device';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {string} value
|
|
64
|
+
*/
|
|
65
|
+
function replaceGermanUmlauts(value) {
|
|
66
|
+
return value
|
|
67
|
+
.replace(/ä/g, 'ae')
|
|
68
|
+
.replace(/ö/g, 'oe')
|
|
69
|
+
.replace(/ü/g, 'ue')
|
|
70
|
+
.replace(/Ä/g, 'Ae')
|
|
71
|
+
.replace(/Ö/g, 'Oe')
|
|
72
|
+
.replace(/Ü/g, 'Ue')
|
|
73
|
+
.replace(/ß/g, 'ss');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
createUniqueDeviceId,
|
|
78
|
+
createUniqueIdFromBase,
|
|
79
|
+
legacySanitizeId,
|
|
80
|
+
replaceGermanUmlauts,
|
|
81
|
+
sanitizeId,
|
|
82
|
+
};
|