iobroker.utility-monitor 1.4.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 +384 -0
- package/admin/i18n/de.json +5 -0
- package/admin/i18n/en.json +5 -0
- package/admin/i18n/es.json +5 -0
- package/admin/i18n/fr.json +5 -0
- package/admin/i18n/it.json +5 -0
- package/admin/i18n/nl.json +5 -0
- package/admin/i18n/pl.json +5 -0
- package/admin/i18n/pt.json +5 -0
- package/admin/i18n/ru.json +5 -0
- package/admin/i18n/uk.json +5 -0
- package/admin/i18n/zh-cn.json +5 -0
- package/admin/jsonConfig.json +1542 -0
- package/admin/utility-monitor.png +0 -0
- package/io-package.json +188 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/billingManager.js +806 -0
- package/lib/calculator.js +254 -0
- package/lib/configParser.js +92 -0
- package/lib/consumptionManager.js +407 -0
- package/lib/messagingHandler.js +339 -0
- package/lib/multiMeterManager.js +749 -0
- package/lib/stateManager.js +1556 -0
- package/main.js +297 -0
- package/package.json +80 -0
|
@@ -0,0 +1,1556 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* State Manager module for nebenkosten-monitor
|
|
3
|
+
* Manages the creation and structure of all adapter states
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Safe wrapper for setObjectNotExistsAsync with error handling
|
|
8
|
+
*
|
|
9
|
+
* @param {object} adapter - Adapter instance
|
|
10
|
+
* @param {string} id - State ID
|
|
11
|
+
* @param {object} obj - State object
|
|
12
|
+
* @returns {Promise<void>}
|
|
13
|
+
*/
|
|
14
|
+
async function safeSetObjectNotExists(adapter, id, obj) {
|
|
15
|
+
try {
|
|
16
|
+
await adapter.setObjectNotExistsAsync(id, obj);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
adapter.log.warn(`Failed to create state ${id}: ${error.message}`);
|
|
19
|
+
// Re-throw critical errors
|
|
20
|
+
if (error.message && error.message.includes('EACCES')) {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* State role definitions for different state types
|
|
28
|
+
*/
|
|
29
|
+
const STATE_ROLES = {
|
|
30
|
+
consumption: 'value.power.consumption',
|
|
31
|
+
cost: 'value.money',
|
|
32
|
+
meterReading: 'value',
|
|
33
|
+
price: 'value.price',
|
|
34
|
+
timestamp: 'value.time',
|
|
35
|
+
indicator: 'indicator',
|
|
36
|
+
value: 'value',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates the complete state structure for a utility type (gas, water, electricity)
|
|
41
|
+
*
|
|
42
|
+
* @param {object} adapter - The adapter instance
|
|
43
|
+
* @param {string} type - Utility type: 'gas', 'water', or 'electricity'
|
|
44
|
+
* @param {object} _config - Configuration for this utility
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
async function createUtilityStateStructure(adapter, type, _config = {}) {
|
|
48
|
+
const isGas = type === 'gas';
|
|
49
|
+
|
|
50
|
+
const labels = {
|
|
51
|
+
gas: { name: 'Gas', unit: 'kWh', volumeUnit: 'm³' },
|
|
52
|
+
water: { name: 'Wasser', unit: 'm³', volumeUnit: 'm³' },
|
|
53
|
+
electricity: { name: 'Strom', unit: 'kWh', volumeUnit: 'kWh' },
|
|
54
|
+
pv: { name: 'PV', unit: 'kWh', volumeUnit: 'kWh', consumption: 'Einspeisung', cost: 'Vergütung' },
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const label = labels[type];
|
|
58
|
+
|
|
59
|
+
// Create main channel
|
|
60
|
+
await adapter.setObjectNotExistsAsync(type, {
|
|
61
|
+
type: 'channel',
|
|
62
|
+
common: {
|
|
63
|
+
name: `${label.name}-Überwachung`,
|
|
64
|
+
},
|
|
65
|
+
native: {},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// CONSUMPTION STATES
|
|
69
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption`, {
|
|
70
|
+
type: 'channel',
|
|
71
|
+
common: {
|
|
72
|
+
name: label.consumption || 'Verbrauch',
|
|
73
|
+
},
|
|
74
|
+
native: {},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// For gas: add volume states (m³) in addition to energy states (kWh)
|
|
78
|
+
// Water doesn't need volume states because it's already measured in m³
|
|
79
|
+
if (type === 'gas') {
|
|
80
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.dailyVolume`, {
|
|
81
|
+
type: 'state',
|
|
82
|
+
common: {
|
|
83
|
+
name: 'Täglicher Verbrauch (m³)',
|
|
84
|
+
type: 'number',
|
|
85
|
+
role: STATE_ROLES.consumption,
|
|
86
|
+
read: true,
|
|
87
|
+
write: false,
|
|
88
|
+
unit: 'm³',
|
|
89
|
+
def: 0,
|
|
90
|
+
},
|
|
91
|
+
native: {},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.monthlyVolume`, {
|
|
95
|
+
type: 'state',
|
|
96
|
+
common: {
|
|
97
|
+
name: 'Monatlicher Verbrauch (m³)',
|
|
98
|
+
type: 'number',
|
|
99
|
+
role: STATE_ROLES.consumption,
|
|
100
|
+
read: true,
|
|
101
|
+
write: false,
|
|
102
|
+
unit: 'm³',
|
|
103
|
+
def: 0,
|
|
104
|
+
},
|
|
105
|
+
native: {},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.yearlyVolume`, {
|
|
109
|
+
type: 'state',
|
|
110
|
+
common: {
|
|
111
|
+
name: 'Jährlicher Verbrauch (m³)',
|
|
112
|
+
type: 'number',
|
|
113
|
+
role: STATE_ROLES.consumption,
|
|
114
|
+
read: true,
|
|
115
|
+
write: false,
|
|
116
|
+
unit: 'm³',
|
|
117
|
+
def: 0,
|
|
118
|
+
},
|
|
119
|
+
native: {},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.daily`, {
|
|
124
|
+
type: 'state',
|
|
125
|
+
common: {
|
|
126
|
+
name: `Tages-${(label.consumption || 'Verbrauch').toLowerCase()} (${label.unit})`,
|
|
127
|
+
type: 'number',
|
|
128
|
+
role: STATE_ROLES.consumption,
|
|
129
|
+
read: true,
|
|
130
|
+
write: false,
|
|
131
|
+
unit: label.unit,
|
|
132
|
+
def: 0,
|
|
133
|
+
},
|
|
134
|
+
native: {},
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.monthly`, {
|
|
138
|
+
type: 'state',
|
|
139
|
+
common: {
|
|
140
|
+
name: `Monats-${(label.consumption || 'Verbrauch').toLowerCase()} (${label.unit})`,
|
|
141
|
+
type: 'number',
|
|
142
|
+
role: STATE_ROLES.consumption,
|
|
143
|
+
read: true,
|
|
144
|
+
write: false,
|
|
145
|
+
unit: label.unit,
|
|
146
|
+
def: 0,
|
|
147
|
+
},
|
|
148
|
+
native: {},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.yearly`, {
|
|
152
|
+
type: 'state',
|
|
153
|
+
common: {
|
|
154
|
+
name: `Jahres-${(label.consumption || 'Verbrauch').toLowerCase()} (${label.unit})`,
|
|
155
|
+
type: 'number',
|
|
156
|
+
role: STATE_ROLES.consumption,
|
|
157
|
+
read: true,
|
|
158
|
+
write: false,
|
|
159
|
+
unit: label.unit,
|
|
160
|
+
def: 0,
|
|
161
|
+
},
|
|
162
|
+
native: {},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Map internal type to config type (electricity -> strom, water -> wasser, gas -> gas)
|
|
166
|
+
const configTypeMap = {
|
|
167
|
+
electricity: 'strom',
|
|
168
|
+
water: 'wasser',
|
|
169
|
+
gas: 'gas',
|
|
170
|
+
pv: 'pv',
|
|
171
|
+
};
|
|
172
|
+
const configType = configTypeMap[type] || type;
|
|
173
|
+
|
|
174
|
+
// HT/NT consumption states - only create if HT/NT tariff is enabled
|
|
175
|
+
// Note: Water typically doesn't have HT/NT, but logic remains generic if config exists
|
|
176
|
+
const htNtEnabledKey = `${configType}HtNtEnabled`;
|
|
177
|
+
if (_config[htNtEnabledKey]) {
|
|
178
|
+
const htNtStates = ['dailyHT', 'dailyNT', 'monthlyHT', 'monthlyNT', 'yearlyHT', 'yearlyNT'];
|
|
179
|
+
const htNtLabels = {
|
|
180
|
+
dailyHT: 'Tagesverbrauch Haupttarif (HT)',
|
|
181
|
+
dailyNT: 'Tagesverbrauch Nebentarif (NT)',
|
|
182
|
+
monthlyHT: 'Monatsverbrauch Haupttarif (HT)',
|
|
183
|
+
monthlyNT: 'Monatsverbrauch Nebentarif (NT)',
|
|
184
|
+
yearlyHT: 'Jahresverbrauch Haupttarif (HT)',
|
|
185
|
+
yearlyNT: 'Jahresverbrauch Nebentarif (NT)',
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
for (const state of htNtStates) {
|
|
189
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.${state}`, {
|
|
190
|
+
type: 'state',
|
|
191
|
+
common: {
|
|
192
|
+
name: `${htNtLabels[state]} (${label.unit})`,
|
|
193
|
+
type: 'number',
|
|
194
|
+
role: STATE_ROLES.consumption,
|
|
195
|
+
read: true,
|
|
196
|
+
write: false,
|
|
197
|
+
unit: label.unit,
|
|
198
|
+
def: 0,
|
|
199
|
+
},
|
|
200
|
+
native: {},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
await adapter.setObjectNotExistsAsync(`${type}.consumption.lastUpdate`, {
|
|
206
|
+
type: 'state',
|
|
207
|
+
common: {
|
|
208
|
+
name: 'Letzte Aktualisierung',
|
|
209
|
+
type: 'number',
|
|
210
|
+
role: STATE_ROLES.timestamp,
|
|
211
|
+
read: true,
|
|
212
|
+
write: false,
|
|
213
|
+
},
|
|
214
|
+
native: {},
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// COST STATES
|
|
218
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs`, {
|
|
219
|
+
type: 'channel',
|
|
220
|
+
common: {
|
|
221
|
+
name: label.cost || 'Kosten',
|
|
222
|
+
},
|
|
223
|
+
native: {},
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.daily`, {
|
|
227
|
+
type: 'state',
|
|
228
|
+
common: {
|
|
229
|
+
name: `Tages-${(label.cost || 'Kosten').toLowerCase()} (€)`,
|
|
230
|
+
type: 'number',
|
|
231
|
+
role: STATE_ROLES.cost,
|
|
232
|
+
read: true,
|
|
233
|
+
write: false,
|
|
234
|
+
unit: '€',
|
|
235
|
+
def: 0,
|
|
236
|
+
},
|
|
237
|
+
native: {},
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.monthly`, {
|
|
241
|
+
type: 'state',
|
|
242
|
+
common: {
|
|
243
|
+
name: `Monats-${(label.cost || 'Kosten').toLowerCase()} (€)`,
|
|
244
|
+
type: 'number',
|
|
245
|
+
role: STATE_ROLES.cost,
|
|
246
|
+
read: true,
|
|
247
|
+
write: false,
|
|
248
|
+
unit: '€',
|
|
249
|
+
def: 0,
|
|
250
|
+
},
|
|
251
|
+
native: {},
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.yearly`, {
|
|
255
|
+
type: 'state',
|
|
256
|
+
common: {
|
|
257
|
+
name: `Jahres-${(label.cost || 'Kosten').toLowerCase()} (€)`,
|
|
258
|
+
type: 'number',
|
|
259
|
+
role: STATE_ROLES.cost,
|
|
260
|
+
read: true,
|
|
261
|
+
write: false,
|
|
262
|
+
unit: '€',
|
|
263
|
+
def: 0,
|
|
264
|
+
},
|
|
265
|
+
native: {},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// HT/NT states - only create if HT/NT tariff is enabled
|
|
269
|
+
// Note: htNtEnabledKey already calculated above for consumption section
|
|
270
|
+
if (_config[htNtEnabledKey]) {
|
|
271
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.yearlyHT`, {
|
|
272
|
+
type: 'state',
|
|
273
|
+
common: {
|
|
274
|
+
name: 'Jahreskosten Haupttarif (HT) (€)',
|
|
275
|
+
type: 'number',
|
|
276
|
+
role: STATE_ROLES.cost,
|
|
277
|
+
read: true,
|
|
278
|
+
write: false,
|
|
279
|
+
unit: '€',
|
|
280
|
+
def: 0,
|
|
281
|
+
},
|
|
282
|
+
native: {},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.yearlyNT`, {
|
|
286
|
+
type: 'state',
|
|
287
|
+
common: {
|
|
288
|
+
name: 'Jahreskosten Nebentarif (NT) (€)',
|
|
289
|
+
type: 'number',
|
|
290
|
+
role: STATE_ROLES.cost,
|
|
291
|
+
read: true,
|
|
292
|
+
write: false,
|
|
293
|
+
unit: '€',
|
|
294
|
+
def: 0,
|
|
295
|
+
},
|
|
296
|
+
native: {},
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.monthlyHT`, {
|
|
300
|
+
type: 'state',
|
|
301
|
+
common: {
|
|
302
|
+
name: 'Monatskosten Haupttarif (HT) (€)',
|
|
303
|
+
type: 'number',
|
|
304
|
+
role: STATE_ROLES.cost,
|
|
305
|
+
read: true,
|
|
306
|
+
write: false,
|
|
307
|
+
unit: '€',
|
|
308
|
+
def: 0,
|
|
309
|
+
},
|
|
310
|
+
native: {},
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.monthlyNT`, {
|
|
314
|
+
type: 'state',
|
|
315
|
+
common: {
|
|
316
|
+
name: 'Monatskosten Nebentarif (NT) (€)',
|
|
317
|
+
type: 'number',
|
|
318
|
+
role: STATE_ROLES.cost,
|
|
319
|
+
read: true,
|
|
320
|
+
write: false,
|
|
321
|
+
unit: '€',
|
|
322
|
+
def: 0,
|
|
323
|
+
},
|
|
324
|
+
native: {},
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.dailyHT`, {
|
|
328
|
+
type: 'state',
|
|
329
|
+
common: {
|
|
330
|
+
name: 'Tageskosten Haupttarif (HT) (€)',
|
|
331
|
+
type: 'number',
|
|
332
|
+
role: STATE_ROLES.cost,
|
|
333
|
+
read: true,
|
|
334
|
+
write: false,
|
|
335
|
+
unit: '€',
|
|
336
|
+
def: 0,
|
|
337
|
+
},
|
|
338
|
+
native: {},
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.dailyNT`, {
|
|
342
|
+
type: 'state',
|
|
343
|
+
common: {
|
|
344
|
+
name: 'Tageskosten Nebentarif (NT) (€)',
|
|
345
|
+
type: 'number',
|
|
346
|
+
role: STATE_ROLES.cost,
|
|
347
|
+
read: true,
|
|
348
|
+
write: false,
|
|
349
|
+
unit: '€',
|
|
350
|
+
def: 0,
|
|
351
|
+
},
|
|
352
|
+
native: {},
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.totalYearly`, {
|
|
357
|
+
type: 'state',
|
|
358
|
+
common: {
|
|
359
|
+
name: `Gesamt-${(label.cost || 'Kosten').toLowerCase()} Jahr (Verbrauch + Grundgebühr) (€)`,
|
|
360
|
+
type: 'number',
|
|
361
|
+
role: STATE_ROLES.cost,
|
|
362
|
+
read: true,
|
|
363
|
+
write: false,
|
|
364
|
+
unit: '€',
|
|
365
|
+
def: 0,
|
|
366
|
+
},
|
|
367
|
+
native: {},
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.annualFee`, {
|
|
371
|
+
type: 'state',
|
|
372
|
+
common: {
|
|
373
|
+
name: 'Jahresgebühr akkumuliert (€)',
|
|
374
|
+
type: 'number',
|
|
375
|
+
role: STATE_ROLES.cost,
|
|
376
|
+
read: true,
|
|
377
|
+
write: false,
|
|
378
|
+
unit: '€',
|
|
379
|
+
def: 0,
|
|
380
|
+
},
|
|
381
|
+
native: {},
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.basicCharge`, {
|
|
385
|
+
type: 'state',
|
|
386
|
+
common: {
|
|
387
|
+
name: 'Grundgebühr (€/Monat)',
|
|
388
|
+
type: 'number',
|
|
389
|
+
role: STATE_ROLES.cost,
|
|
390
|
+
read: true,
|
|
391
|
+
write: false,
|
|
392
|
+
unit: '€',
|
|
393
|
+
def: 0,
|
|
394
|
+
},
|
|
395
|
+
native: {},
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.paidTotal`, {
|
|
399
|
+
type: 'state',
|
|
400
|
+
common: {
|
|
401
|
+
name: 'Bezahlt gesamt (Abschlag × Monate)',
|
|
402
|
+
type: 'number',
|
|
403
|
+
role: STATE_ROLES.cost,
|
|
404
|
+
read: true,
|
|
405
|
+
write: false,
|
|
406
|
+
unit: '€',
|
|
407
|
+
def: 0,
|
|
408
|
+
},
|
|
409
|
+
native: {},
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
await adapter.setObjectNotExistsAsync(`${type}.costs.balance`, {
|
|
413
|
+
type: 'state',
|
|
414
|
+
common: {
|
|
415
|
+
name: 'Saldo (Bezahlt - Verbraucht)',
|
|
416
|
+
type: 'number',
|
|
417
|
+
role: STATE_ROLES.cost,
|
|
418
|
+
read: true,
|
|
419
|
+
write: false,
|
|
420
|
+
unit: '€',
|
|
421
|
+
def: 0,
|
|
422
|
+
},
|
|
423
|
+
native: {},
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// BILLING STATES (Abrechnungszeitraum-Management)
|
|
427
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing`, {
|
|
428
|
+
type: 'channel',
|
|
429
|
+
common: {
|
|
430
|
+
name: 'Abrechnungszeitraum',
|
|
431
|
+
},
|
|
432
|
+
native: {},
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.endReading`, {
|
|
436
|
+
type: 'state',
|
|
437
|
+
common: {
|
|
438
|
+
name: 'Endzählerstand (manuell eintragen)',
|
|
439
|
+
type: 'number',
|
|
440
|
+
role: STATE_ROLES.meterReading,
|
|
441
|
+
read: true,
|
|
442
|
+
write: true,
|
|
443
|
+
unit: label.volumeUnit,
|
|
444
|
+
def: 0,
|
|
445
|
+
},
|
|
446
|
+
native: {},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.closePeriod`, {
|
|
450
|
+
type: 'state',
|
|
451
|
+
common: {
|
|
452
|
+
name: 'Zeitraum jetzt abschließen (Button)',
|
|
453
|
+
type: 'boolean',
|
|
454
|
+
role: 'button',
|
|
455
|
+
read: true,
|
|
456
|
+
write: true,
|
|
457
|
+
def: false,
|
|
458
|
+
},
|
|
459
|
+
native: {},
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.periodEnd`, {
|
|
463
|
+
type: 'state',
|
|
464
|
+
common: {
|
|
465
|
+
name: 'Abrechnungszeitraum endet am',
|
|
466
|
+
type: 'string',
|
|
467
|
+
role: 'text',
|
|
468
|
+
read: true,
|
|
469
|
+
write: false,
|
|
470
|
+
def: '',
|
|
471
|
+
},
|
|
472
|
+
native: {},
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.daysRemaining`, {
|
|
476
|
+
type: 'state',
|
|
477
|
+
common: {
|
|
478
|
+
name: 'Tage bis Abrechnungsende',
|
|
479
|
+
type: 'number',
|
|
480
|
+
role: 'value',
|
|
481
|
+
read: true,
|
|
482
|
+
write: false,
|
|
483
|
+
unit: 'Tage',
|
|
484
|
+
def: 0,
|
|
485
|
+
},
|
|
486
|
+
native: {},
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.newInitialReading`, {
|
|
490
|
+
type: 'state',
|
|
491
|
+
common: {
|
|
492
|
+
name: 'Neuer Startwert (für Config übernehmen!)',
|
|
493
|
+
type: 'number',
|
|
494
|
+
role: STATE_ROLES.meterReading,
|
|
495
|
+
read: true,
|
|
496
|
+
write: false,
|
|
497
|
+
unit: label.volumeUnit,
|
|
498
|
+
def: 0,
|
|
499
|
+
},
|
|
500
|
+
native: {},
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.notificationSent`, {
|
|
504
|
+
type: 'state',
|
|
505
|
+
common: {
|
|
506
|
+
name: 'Benachrichtigung Zählerstand versendet',
|
|
507
|
+
type: 'boolean',
|
|
508
|
+
role: 'indicator',
|
|
509
|
+
read: true,
|
|
510
|
+
write: false,
|
|
511
|
+
def: false,
|
|
512
|
+
},
|
|
513
|
+
native: {},
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
await adapter.setObjectNotExistsAsync(`${type}.billing.notificationChangeSent`, {
|
|
517
|
+
type: 'state',
|
|
518
|
+
common: {
|
|
519
|
+
name: 'Benachrichtigung Vertragswechsel versendet',
|
|
520
|
+
type: 'boolean',
|
|
521
|
+
role: 'indicator',
|
|
522
|
+
read: true,
|
|
523
|
+
write: false,
|
|
524
|
+
def: false,
|
|
525
|
+
},
|
|
526
|
+
native: {},
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// ADJUSTMENT STATES (Manuelle Anpassung)
|
|
530
|
+
await adapter.setObjectNotExistsAsync(`${type}.adjustment`, {
|
|
531
|
+
type: 'channel',
|
|
532
|
+
common: {
|
|
533
|
+
name: 'Manuelle Anpassung',
|
|
534
|
+
},
|
|
535
|
+
native: {},
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
await adapter.setObjectNotExistsAsync(`${type}.adjustment.value`, {
|
|
539
|
+
type: 'state',
|
|
540
|
+
common: {
|
|
541
|
+
name: 'Korrekturwert (Differenz zum echten Zähler)',
|
|
542
|
+
type: 'number',
|
|
543
|
+
role: STATE_ROLES.value,
|
|
544
|
+
read: true,
|
|
545
|
+
write: true,
|
|
546
|
+
unit: label.volumeUnit,
|
|
547
|
+
def: 0,
|
|
548
|
+
},
|
|
549
|
+
native: {},
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
await adapter.setObjectNotExistsAsync(`${type}.adjustment.note`, {
|
|
553
|
+
type: 'state',
|
|
554
|
+
common: {
|
|
555
|
+
name: 'Notiz/Grund für Anpassung',
|
|
556
|
+
type: 'string',
|
|
557
|
+
role: 'text',
|
|
558
|
+
read: true,
|
|
559
|
+
write: true,
|
|
560
|
+
def: '',
|
|
561
|
+
},
|
|
562
|
+
native: {},
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
await adapter.setObjectNotExistsAsync(`${type}.adjustment.applied`, {
|
|
566
|
+
type: 'state',
|
|
567
|
+
common: {
|
|
568
|
+
name: 'Zeitstempel der letzten Anwendung',
|
|
569
|
+
type: 'number',
|
|
570
|
+
role: 'value.time',
|
|
571
|
+
read: true,
|
|
572
|
+
write: false,
|
|
573
|
+
def: 0,
|
|
574
|
+
},
|
|
575
|
+
native: {},
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
// INFO STATES
|
|
579
|
+
await adapter.setObjectNotExistsAsync(`${type}.info`, {
|
|
580
|
+
type: 'channel',
|
|
581
|
+
common: {
|
|
582
|
+
name: 'Informationen',
|
|
583
|
+
},
|
|
584
|
+
native: {},
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// For gas, store volume in m³ separate from energy in kWh
|
|
588
|
+
if (isGas) {
|
|
589
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.meterReadingVolume`, {
|
|
590
|
+
type: 'state',
|
|
591
|
+
common: {
|
|
592
|
+
name: `Zählerstand Volumen (${label.volumeUnit})`,
|
|
593
|
+
type: 'number',
|
|
594
|
+
role: STATE_ROLES.meterReading,
|
|
595
|
+
read: true,
|
|
596
|
+
write: false,
|
|
597
|
+
unit: label.volumeUnit,
|
|
598
|
+
def: 0,
|
|
599
|
+
},
|
|
600
|
+
native: {},
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.meterReading`, {
|
|
605
|
+
type: 'state',
|
|
606
|
+
common: {
|
|
607
|
+
name: `Zählerstand (${label.unit})`,
|
|
608
|
+
type: 'number',
|
|
609
|
+
role: STATE_ROLES.meterReading,
|
|
610
|
+
read: true,
|
|
611
|
+
write: false,
|
|
612
|
+
unit: label.unit,
|
|
613
|
+
def: 0,
|
|
614
|
+
},
|
|
615
|
+
native: {},
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.currentPrice`, {
|
|
619
|
+
type: 'state',
|
|
620
|
+
common: {
|
|
621
|
+
name: `Aktueller Preis (€/${label.unit})`,
|
|
622
|
+
type: 'number',
|
|
623
|
+
role: STATE_ROLES.price,
|
|
624
|
+
read: true,
|
|
625
|
+
write: false,
|
|
626
|
+
unit: `€/${label.unit}`,
|
|
627
|
+
def: 0,
|
|
628
|
+
},
|
|
629
|
+
native: {},
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.lastSync`, {
|
|
633
|
+
type: 'state',
|
|
634
|
+
common: {
|
|
635
|
+
name: 'Letzte Synchronisation',
|
|
636
|
+
type: 'number',
|
|
637
|
+
role: STATE_ROLES.timestamp,
|
|
638
|
+
read: true,
|
|
639
|
+
write: false,
|
|
640
|
+
},
|
|
641
|
+
native: {},
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.sensorActive`, {
|
|
645
|
+
type: 'state',
|
|
646
|
+
common: {
|
|
647
|
+
name: 'Sensor aktiv',
|
|
648
|
+
type: 'boolean',
|
|
649
|
+
role: STATE_ROLES.indicator,
|
|
650
|
+
read: true,
|
|
651
|
+
write: false,
|
|
652
|
+
def: false,
|
|
653
|
+
},
|
|
654
|
+
native: {},
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
await adapter.setObjectNotExistsAsync(`${type}.info.currentTariff`, {
|
|
658
|
+
type: 'state',
|
|
659
|
+
common: {
|
|
660
|
+
name: 'Aktueller Tarif (HT/NT)',
|
|
661
|
+
type: 'string',
|
|
662
|
+
role: 'text',
|
|
663
|
+
read: true,
|
|
664
|
+
write: false,
|
|
665
|
+
def: 'Standard',
|
|
666
|
+
},
|
|
667
|
+
native: {},
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
// STATISTICS STATES
|
|
671
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics`, {
|
|
672
|
+
type: 'channel',
|
|
673
|
+
common: {
|
|
674
|
+
name: 'Statistiken',
|
|
675
|
+
},
|
|
676
|
+
native: {},
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.averageDaily`, {
|
|
680
|
+
type: 'state',
|
|
681
|
+
common: {
|
|
682
|
+
name: `Durchschnitt pro Tag (${label.unit})`,
|
|
683
|
+
type: 'number',
|
|
684
|
+
role: STATE_ROLES.consumption,
|
|
685
|
+
read: true,
|
|
686
|
+
write: false,
|
|
687
|
+
unit: label.unit,
|
|
688
|
+
def: 0,
|
|
689
|
+
},
|
|
690
|
+
native: {},
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.averageMonthly`, {
|
|
694
|
+
type: 'state',
|
|
695
|
+
common: {
|
|
696
|
+
name: `Durchschnitt pro Monat (${label.unit})`,
|
|
697
|
+
type: 'number',
|
|
698
|
+
role: STATE_ROLES.consumption,
|
|
699
|
+
read: true,
|
|
700
|
+
write: false,
|
|
701
|
+
unit: label.unit,
|
|
702
|
+
def: 0,
|
|
703
|
+
},
|
|
704
|
+
native: {},
|
|
705
|
+
});
|
|
706
|
+
|
|
707
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDay`, {
|
|
708
|
+
type: 'state',
|
|
709
|
+
common: {
|
|
710
|
+
name: `Verbrauch gestern (${label.unit})`,
|
|
711
|
+
type: 'number',
|
|
712
|
+
role: STATE_ROLES.consumption,
|
|
713
|
+
read: true,
|
|
714
|
+
write: false,
|
|
715
|
+
unit: label.unit,
|
|
716
|
+
def: 0,
|
|
717
|
+
},
|
|
718
|
+
native: {},
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
if (type === 'gas') {
|
|
722
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDayVolume`, {
|
|
723
|
+
type: 'state',
|
|
724
|
+
common: {
|
|
725
|
+
name: `Verbrauch gestern (${label.volumeUnit})`,
|
|
726
|
+
type: 'number',
|
|
727
|
+
role: STATE_ROLES.consumption,
|
|
728
|
+
read: true,
|
|
729
|
+
write: false,
|
|
730
|
+
unit: label.volumeUnit,
|
|
731
|
+
def: 0,
|
|
732
|
+
},
|
|
733
|
+
native: {},
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastDayStart`, {
|
|
738
|
+
type: 'state',
|
|
739
|
+
common: {
|
|
740
|
+
name: 'Tageszähler zurückgesetzt am',
|
|
741
|
+
type: 'number',
|
|
742
|
+
role: STATE_ROLES.timestamp,
|
|
743
|
+
read: true,
|
|
744
|
+
write: false,
|
|
745
|
+
},
|
|
746
|
+
native: {},
|
|
747
|
+
});
|
|
748
|
+
|
|
749
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastMonthStart`, {
|
|
750
|
+
type: 'state',
|
|
751
|
+
common: {
|
|
752
|
+
name: 'Monatszähler zurückgesetzt am',
|
|
753
|
+
type: 'number',
|
|
754
|
+
role: STATE_ROLES.timestamp,
|
|
755
|
+
read: true,
|
|
756
|
+
write: false,
|
|
757
|
+
},
|
|
758
|
+
native: {},
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
await adapter.setObjectNotExistsAsync(`${type}.statistics.lastYearStart`, {
|
|
762
|
+
type: 'state',
|
|
763
|
+
common: {
|
|
764
|
+
name: 'Jahreszähler zurückgesetzt am',
|
|
765
|
+
type: 'number',
|
|
766
|
+
role: STATE_ROLES.timestamp,
|
|
767
|
+
read: true,
|
|
768
|
+
write: false,
|
|
769
|
+
},
|
|
770
|
+
native: {},
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
adapter.log.debug(`State structure created for ${type}`);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Creates the state structure for a meter (main or additional)
|
|
778
|
+
* Can be used for main meter or any custom-named additional meter
|
|
779
|
+
*
|
|
780
|
+
* @param {object} adapter - The adapter instance
|
|
781
|
+
* @param {string} type - Utility type: 'gas', 'water', or 'electricity'
|
|
782
|
+
* @param {string} meterName - Meter name: 'main' or custom name (e.g., 'erdgeschoss')
|
|
783
|
+
* @param {object} _config - Configuration for this meter
|
|
784
|
+
* @returns {Promise<void>}
|
|
785
|
+
*/
|
|
786
|
+
async function createMeterStructure(adapter, type, meterName, _config = {}) {
|
|
787
|
+
const isGas = type === 'gas';
|
|
788
|
+
|
|
789
|
+
const labels = {
|
|
790
|
+
gas: { name: meterName === 'main' ? 'Gas' : `Gas (${meterName})`, unit: 'kWh', volumeUnit: 'm³' },
|
|
791
|
+
water: { name: meterName === 'main' ? 'Wasser' : `Wasser (${meterName})`, unit: 'm³', volumeUnit: 'm³' },
|
|
792
|
+
electricity: { name: meterName === 'main' ? 'Strom' : `Strom (${meterName})`, unit: 'kWh', volumeUnit: 'kWh' },
|
|
793
|
+
pv: { name: meterName === 'main' ? 'PV' : `PV (${meterName})`, unit: 'kWh', volumeUnit: 'kWh' },
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
const label = labels[type];
|
|
797
|
+
if (!label) {
|
|
798
|
+
adapter.log.error(
|
|
799
|
+
`MISSING LABEL for type "${type}" in createMeterStructure! Meter: ${meterName}. Valid types: ${Object.keys(labels).join(', ')}`,
|
|
800
|
+
);
|
|
801
|
+
// Fallback to prevent crash
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
const basePath = meterName === 'main' ? type : `${type}.${meterName}`;
|
|
805
|
+
|
|
806
|
+
// Create main channel
|
|
807
|
+
await adapter.setObjectNotExistsAsync(basePath, {
|
|
808
|
+
type: 'channel',
|
|
809
|
+
common: {
|
|
810
|
+
name: `${label.name}-Überwachung`,
|
|
811
|
+
},
|
|
812
|
+
native: {},
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
// CONSUMPTION STATES
|
|
816
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption`, {
|
|
817
|
+
type: 'channel',
|
|
818
|
+
common: {
|
|
819
|
+
name: 'Verbrauch',
|
|
820
|
+
},
|
|
821
|
+
native: {},
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// For gas: add volume states (m³)
|
|
825
|
+
if (type === 'gas') {
|
|
826
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.dailyVolume`, {
|
|
827
|
+
type: 'state',
|
|
828
|
+
common: {
|
|
829
|
+
name: 'Täglicher Verbrauch (m³)',
|
|
830
|
+
type: 'number',
|
|
831
|
+
role: STATE_ROLES.consumption,
|
|
832
|
+
read: true,
|
|
833
|
+
write: false,
|
|
834
|
+
unit: 'm³',
|
|
835
|
+
def: 0,
|
|
836
|
+
},
|
|
837
|
+
native: {},
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.monthlyVolume`, {
|
|
841
|
+
type: 'state',
|
|
842
|
+
common: {
|
|
843
|
+
name: 'Monatlicher Verbrauch (m³)',
|
|
844
|
+
type: 'number',
|
|
845
|
+
role: STATE_ROLES.consumption,
|
|
846
|
+
read: true,
|
|
847
|
+
write: false,
|
|
848
|
+
unit: 'm³',
|
|
849
|
+
def: 0,
|
|
850
|
+
},
|
|
851
|
+
native: {},
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.yearlyVolume`, {
|
|
855
|
+
type: 'state',
|
|
856
|
+
common: {
|
|
857
|
+
name: 'Jährlicher Verbrauch (m³)',
|
|
858
|
+
type: 'number',
|
|
859
|
+
role: STATE_ROLES.consumption,
|
|
860
|
+
read: true,
|
|
861
|
+
write: false,
|
|
862
|
+
unit: 'm³',
|
|
863
|
+
def: 0,
|
|
864
|
+
},
|
|
865
|
+
native: {},
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.daily`, {
|
|
870
|
+
type: 'state',
|
|
871
|
+
common: {
|
|
872
|
+
name: `Tagesverbrauch (${label.unit})`,
|
|
873
|
+
type: 'number',
|
|
874
|
+
role: STATE_ROLES.consumption,
|
|
875
|
+
read: true,
|
|
876
|
+
write: false,
|
|
877
|
+
unit: label.unit,
|
|
878
|
+
def: 0,
|
|
879
|
+
},
|
|
880
|
+
native: {},
|
|
881
|
+
});
|
|
882
|
+
|
|
883
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.monthly`, {
|
|
884
|
+
type: 'state',
|
|
885
|
+
common: {
|
|
886
|
+
name: `Monatsverbrauch (${label.unit})`,
|
|
887
|
+
type: 'number',
|
|
888
|
+
role: STATE_ROLES.consumption,
|
|
889
|
+
read: true,
|
|
890
|
+
write: false,
|
|
891
|
+
unit: label.unit,
|
|
892
|
+
def: 0,
|
|
893
|
+
},
|
|
894
|
+
native: {},
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.yearly`, {
|
|
898
|
+
type: 'state',
|
|
899
|
+
common: {
|
|
900
|
+
name: `Jahresverbrauch (${label.unit})`,
|
|
901
|
+
type: 'number',
|
|
902
|
+
role: STATE_ROLES.consumption,
|
|
903
|
+
read: true,
|
|
904
|
+
write: false,
|
|
905
|
+
unit: label.unit,
|
|
906
|
+
def: 0,
|
|
907
|
+
},
|
|
908
|
+
native: {},
|
|
909
|
+
});
|
|
910
|
+
|
|
911
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.lastUpdate`, {
|
|
912
|
+
type: 'state',
|
|
913
|
+
common: {
|
|
914
|
+
name: 'Letzte Aktualisierung',
|
|
915
|
+
type: 'number',
|
|
916
|
+
role: STATE_ROLES.timestamp,
|
|
917
|
+
read: true,
|
|
918
|
+
write: false,
|
|
919
|
+
},
|
|
920
|
+
native: {},
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// COST STATES
|
|
924
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs`, {
|
|
925
|
+
type: 'channel',
|
|
926
|
+
common: {
|
|
927
|
+
name: 'Kosten',
|
|
928
|
+
},
|
|
929
|
+
native: {},
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.daily`, {
|
|
933
|
+
type: 'state',
|
|
934
|
+
common: {
|
|
935
|
+
name: 'Tageskosten (€)',
|
|
936
|
+
type: 'number',
|
|
937
|
+
role: STATE_ROLES.cost,
|
|
938
|
+
read: true,
|
|
939
|
+
write: false,
|
|
940
|
+
unit: '€',
|
|
941
|
+
def: 0,
|
|
942
|
+
},
|
|
943
|
+
native: {},
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.monthly`, {
|
|
947
|
+
type: 'state',
|
|
948
|
+
common: {
|
|
949
|
+
name: 'Monatskosten (€)',
|
|
950
|
+
type: 'number',
|
|
951
|
+
role: STATE_ROLES.cost,
|
|
952
|
+
read: true,
|
|
953
|
+
write: false,
|
|
954
|
+
unit: '€',
|
|
955
|
+
def: 0,
|
|
956
|
+
},
|
|
957
|
+
native: {},
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.yearly`, {
|
|
961
|
+
type: 'state',
|
|
962
|
+
common: {
|
|
963
|
+
name: 'Jahreskosten (€)',
|
|
964
|
+
type: 'number',
|
|
965
|
+
role: STATE_ROLES.cost,
|
|
966
|
+
read: true,
|
|
967
|
+
write: false,
|
|
968
|
+
unit: '€',
|
|
969
|
+
def: 0,
|
|
970
|
+
},
|
|
971
|
+
native: {},
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.totalYearly`, {
|
|
975
|
+
type: 'state',
|
|
976
|
+
common: {
|
|
977
|
+
name: 'Gesamtkosten Jahr (Verbrauch + Grundgebühr) (€)',
|
|
978
|
+
type: 'number',
|
|
979
|
+
role: STATE_ROLES.cost,
|
|
980
|
+
read: true,
|
|
981
|
+
write: false,
|
|
982
|
+
unit: '€',
|
|
983
|
+
def: 0,
|
|
984
|
+
},
|
|
985
|
+
native: {},
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.annualFee`, {
|
|
989
|
+
type: 'state',
|
|
990
|
+
common: {
|
|
991
|
+
name: 'Jahresgebühr akkumuliert (€)',
|
|
992
|
+
type: 'number',
|
|
993
|
+
role: STATE_ROLES.cost,
|
|
994
|
+
read: true,
|
|
995
|
+
write: false,
|
|
996
|
+
unit: '€',
|
|
997
|
+
def: 0,
|
|
998
|
+
},
|
|
999
|
+
native: {},
|
|
1000
|
+
});
|
|
1001
|
+
|
|
1002
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.basicCharge`, {
|
|
1003
|
+
type: 'state',
|
|
1004
|
+
common: {
|
|
1005
|
+
name: 'Grundgebühr (€/Monat)',
|
|
1006
|
+
type: 'number',
|
|
1007
|
+
role: STATE_ROLES.cost,
|
|
1008
|
+
read: true,
|
|
1009
|
+
write: false,
|
|
1010
|
+
unit: '€',
|
|
1011
|
+
def: 0,
|
|
1012
|
+
},
|
|
1013
|
+
native: {},
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.paidTotal`, {
|
|
1017
|
+
type: 'state',
|
|
1018
|
+
common: {
|
|
1019
|
+
name: 'Bezahlt gesamt (Abschlag × Monate)',
|
|
1020
|
+
type: 'number',
|
|
1021
|
+
role: STATE_ROLES.cost,
|
|
1022
|
+
read: true,
|
|
1023
|
+
write: false,
|
|
1024
|
+
unit: '€',
|
|
1025
|
+
def: 0,
|
|
1026
|
+
},
|
|
1027
|
+
native: {},
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.balance`, {
|
|
1031
|
+
type: 'state',
|
|
1032
|
+
common: {
|
|
1033
|
+
name: 'Saldo (Bezahlt - Verbraucht)',
|
|
1034
|
+
type: 'number',
|
|
1035
|
+
role: STATE_ROLES.cost,
|
|
1036
|
+
read: true,
|
|
1037
|
+
write: false,
|
|
1038
|
+
unit: '€',
|
|
1039
|
+
def: 0,
|
|
1040
|
+
},
|
|
1041
|
+
native: {},
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
// BILLING STATES
|
|
1045
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing`, {
|
|
1046
|
+
type: 'channel',
|
|
1047
|
+
common: {
|
|
1048
|
+
name: 'Abrechnungszeitraum',
|
|
1049
|
+
},
|
|
1050
|
+
native: {},
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.endReading`, {
|
|
1054
|
+
type: 'state',
|
|
1055
|
+
common: {
|
|
1056
|
+
name: 'Endzählerstand (manuell eintragen)',
|
|
1057
|
+
type: 'number',
|
|
1058
|
+
role: STATE_ROLES.meterReading,
|
|
1059
|
+
read: true,
|
|
1060
|
+
write: true,
|
|
1061
|
+
unit: label.volumeUnit,
|
|
1062
|
+
def: 0,
|
|
1063
|
+
},
|
|
1064
|
+
native: {},
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.closePeriod`, {
|
|
1068
|
+
type: 'state',
|
|
1069
|
+
common: {
|
|
1070
|
+
name: 'Zeitraum jetzt abschließen (Button)',
|
|
1071
|
+
type: 'boolean',
|
|
1072
|
+
role: 'button',
|
|
1073
|
+
read: true,
|
|
1074
|
+
write: true,
|
|
1075
|
+
def: false,
|
|
1076
|
+
},
|
|
1077
|
+
native: {},
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.periodEnd`, {
|
|
1081
|
+
type: 'state',
|
|
1082
|
+
common: {
|
|
1083
|
+
name: 'Abrechnungszeitraum endet am',
|
|
1084
|
+
type: 'string',
|
|
1085
|
+
role: 'text',
|
|
1086
|
+
read: true,
|
|
1087
|
+
write: false,
|
|
1088
|
+
def: '',
|
|
1089
|
+
},
|
|
1090
|
+
native: {},
|
|
1091
|
+
});
|
|
1092
|
+
|
|
1093
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.daysRemaining`, {
|
|
1094
|
+
type: 'state',
|
|
1095
|
+
common: {
|
|
1096
|
+
name: 'Tage bis Abrechnungsende',
|
|
1097
|
+
type: 'number',
|
|
1098
|
+
role: 'value',
|
|
1099
|
+
read: true,
|
|
1100
|
+
write: false,
|
|
1101
|
+
unit: 'Tage',
|
|
1102
|
+
def: 0,
|
|
1103
|
+
},
|
|
1104
|
+
native: {},
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.newInitialReading`, {
|
|
1108
|
+
type: 'state',
|
|
1109
|
+
common: {
|
|
1110
|
+
name: 'Neuer Startwert (für Config übernehmen!)',
|
|
1111
|
+
type: 'number',
|
|
1112
|
+
role: STATE_ROLES.meterReading,
|
|
1113
|
+
read: true,
|
|
1114
|
+
write: false,
|
|
1115
|
+
unit: label.volumeUnit,
|
|
1116
|
+
def: 0,
|
|
1117
|
+
},
|
|
1118
|
+
native: {},
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.notificationSent`, {
|
|
1122
|
+
type: 'state',
|
|
1123
|
+
common: {
|
|
1124
|
+
name: 'Benachrichtigung Zählerstand versendet',
|
|
1125
|
+
type: 'boolean',
|
|
1126
|
+
role: 'indicator',
|
|
1127
|
+
read: true,
|
|
1128
|
+
write: false,
|
|
1129
|
+
def: false,
|
|
1130
|
+
},
|
|
1131
|
+
native: {},
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.billing.notificationChangeSent`, {
|
|
1135
|
+
type: 'state',
|
|
1136
|
+
common: {
|
|
1137
|
+
name: 'Benachrichtigung Vertragswechsel versendet',
|
|
1138
|
+
type: 'boolean',
|
|
1139
|
+
role: 'indicator',
|
|
1140
|
+
read: true,
|
|
1141
|
+
write: false,
|
|
1142
|
+
def: false,
|
|
1143
|
+
},
|
|
1144
|
+
native: {},
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
// ADJUSTMENT STATES
|
|
1148
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.adjustment`, {
|
|
1149
|
+
type: 'channel',
|
|
1150
|
+
common: {
|
|
1151
|
+
name: 'Manuelle Anpassung',
|
|
1152
|
+
},
|
|
1153
|
+
native: {},
|
|
1154
|
+
});
|
|
1155
|
+
|
|
1156
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.adjustment.value`, {
|
|
1157
|
+
type: 'state',
|
|
1158
|
+
common: {
|
|
1159
|
+
name: 'Korrekturwert (Differenz zum echten Zähler)',
|
|
1160
|
+
type: 'number',
|
|
1161
|
+
role: STATE_ROLES.value,
|
|
1162
|
+
read: true,
|
|
1163
|
+
write: true,
|
|
1164
|
+
unit: label.volumeUnit,
|
|
1165
|
+
def: 0,
|
|
1166
|
+
},
|
|
1167
|
+
native: {},
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.adjustment.note`, {
|
|
1171
|
+
type: 'state',
|
|
1172
|
+
common: {
|
|
1173
|
+
name: 'Notiz/Grund für Anpassung',
|
|
1174
|
+
type: 'string',
|
|
1175
|
+
role: 'text',
|
|
1176
|
+
read: true,
|
|
1177
|
+
write: true,
|
|
1178
|
+
def: '',
|
|
1179
|
+
},
|
|
1180
|
+
native: {},
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.adjustment.applied`, {
|
|
1184
|
+
type: 'state',
|
|
1185
|
+
common: {
|
|
1186
|
+
name: 'Zeitstempel der letzten Anwendung',
|
|
1187
|
+
type: 'number',
|
|
1188
|
+
role: 'value.time',
|
|
1189
|
+
read: true,
|
|
1190
|
+
write: false,
|
|
1191
|
+
def: 0,
|
|
1192
|
+
},
|
|
1193
|
+
native: {},
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
// INFO STATES
|
|
1197
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info`, {
|
|
1198
|
+
type: 'channel',
|
|
1199
|
+
common: {
|
|
1200
|
+
name: 'Informationen',
|
|
1201
|
+
},
|
|
1202
|
+
native: {},
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1205
|
+
// For gas, store volume in m³ separate from energy in kWh
|
|
1206
|
+
if (isGas) {
|
|
1207
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.meterReadingVolume`, {
|
|
1208
|
+
type: 'state',
|
|
1209
|
+
common: {
|
|
1210
|
+
name: `Zählerstand Volumen (${label.volumeUnit})`,
|
|
1211
|
+
type: 'number',
|
|
1212
|
+
role: STATE_ROLES.meterReading,
|
|
1213
|
+
read: true,
|
|
1214
|
+
write: false,
|
|
1215
|
+
unit: label.volumeUnit,
|
|
1216
|
+
def: 0,
|
|
1217
|
+
},
|
|
1218
|
+
native: {},
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.meterReading`, {
|
|
1223
|
+
type: 'state',
|
|
1224
|
+
common: {
|
|
1225
|
+
name: `Zählerstand (${label.unit})`,
|
|
1226
|
+
type: 'number',
|
|
1227
|
+
role: STATE_ROLES.meterReading,
|
|
1228
|
+
read: true,
|
|
1229
|
+
write: false,
|
|
1230
|
+
unit: label.unit,
|
|
1231
|
+
def: 0,
|
|
1232
|
+
},
|
|
1233
|
+
native: {},
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.currentPrice`, {
|
|
1237
|
+
type: 'state',
|
|
1238
|
+
common: {
|
|
1239
|
+
name: `Aktueller Preis (€/${label.unit})`,
|
|
1240
|
+
type: 'number',
|
|
1241
|
+
role: STATE_ROLES.price,
|
|
1242
|
+
read: true,
|
|
1243
|
+
write: false,
|
|
1244
|
+
unit: `€/${label.unit}`,
|
|
1245
|
+
def: 0,
|
|
1246
|
+
},
|
|
1247
|
+
native: {},
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.lastSync`, {
|
|
1251
|
+
type: 'state',
|
|
1252
|
+
common: {
|
|
1253
|
+
name: 'Letzte Synchronisation',
|
|
1254
|
+
type: 'number',
|
|
1255
|
+
role: STATE_ROLES.timestamp,
|
|
1256
|
+
read: true,
|
|
1257
|
+
write: false,
|
|
1258
|
+
},
|
|
1259
|
+
native: {},
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.sensorActive`, {
|
|
1263
|
+
type: 'state',
|
|
1264
|
+
common: {
|
|
1265
|
+
name: 'Sensor aktiv',
|
|
1266
|
+
type: 'boolean',
|
|
1267
|
+
role: STATE_ROLES.indicator,
|
|
1268
|
+
read: true,
|
|
1269
|
+
write: false,
|
|
1270
|
+
def: false,
|
|
1271
|
+
},
|
|
1272
|
+
native: {},
|
|
1273
|
+
});
|
|
1274
|
+
|
|
1275
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.info.currentTariff`, {
|
|
1276
|
+
type: 'state',
|
|
1277
|
+
common: {
|
|
1278
|
+
name: 'Aktueller Tarif',
|
|
1279
|
+
type: 'string',
|
|
1280
|
+
role: 'text',
|
|
1281
|
+
read: true,
|
|
1282
|
+
write: false,
|
|
1283
|
+
def: 'Standard',
|
|
1284
|
+
},
|
|
1285
|
+
native: {},
|
|
1286
|
+
});
|
|
1287
|
+
|
|
1288
|
+
// STATISTICS STATES
|
|
1289
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics`, {
|
|
1290
|
+
type: 'channel',
|
|
1291
|
+
common: {
|
|
1292
|
+
name: 'Statistiken',
|
|
1293
|
+
},
|
|
1294
|
+
native: {},
|
|
1295
|
+
});
|
|
1296
|
+
|
|
1297
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.averageDaily`, {
|
|
1298
|
+
type: 'state',
|
|
1299
|
+
common: {
|
|
1300
|
+
name: `Durchschnitt pro Tag (${label.unit})`,
|
|
1301
|
+
type: 'number',
|
|
1302
|
+
role: STATE_ROLES.consumption,
|
|
1303
|
+
read: true,
|
|
1304
|
+
write: false,
|
|
1305
|
+
unit: label.unit,
|
|
1306
|
+
def: 0,
|
|
1307
|
+
},
|
|
1308
|
+
native: {},
|
|
1309
|
+
});
|
|
1310
|
+
|
|
1311
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.averageMonthly`, {
|
|
1312
|
+
type: 'state',
|
|
1313
|
+
common: {
|
|
1314
|
+
name: `Durchschnitt pro Monat (${label.unit})`,
|
|
1315
|
+
type: 'number',
|
|
1316
|
+
role: STATE_ROLES.consumption,
|
|
1317
|
+
read: true,
|
|
1318
|
+
write: false,
|
|
1319
|
+
unit: label.unit,
|
|
1320
|
+
def: 0,
|
|
1321
|
+
},
|
|
1322
|
+
native: {},
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.lastDay`, {
|
|
1326
|
+
type: 'state',
|
|
1327
|
+
common: {
|
|
1328
|
+
name: `Verbrauch gestern (${label.unit})`,
|
|
1329
|
+
type: 'number',
|
|
1330
|
+
role: STATE_ROLES.consumption,
|
|
1331
|
+
read: true,
|
|
1332
|
+
write: false,
|
|
1333
|
+
unit: label.unit,
|
|
1334
|
+
def: 0,
|
|
1335
|
+
},
|
|
1336
|
+
native: {},
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
if (type === 'gas') {
|
|
1340
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.lastDayVolume`, {
|
|
1341
|
+
type: 'state',
|
|
1342
|
+
common: {
|
|
1343
|
+
name: `Verbrauch gestern (${label.volumeUnit})`,
|
|
1344
|
+
type: 'number',
|
|
1345
|
+
role: STATE_ROLES.consumption,
|
|
1346
|
+
read: true,
|
|
1347
|
+
write: false,
|
|
1348
|
+
unit: label.volumeUnit,
|
|
1349
|
+
def: 0,
|
|
1350
|
+
},
|
|
1351
|
+
native: {},
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.lastDayStart`, {
|
|
1356
|
+
type: 'state',
|
|
1357
|
+
common: {
|
|
1358
|
+
name: 'Tageszähler zurückgesetzt am',
|
|
1359
|
+
type: 'number',
|
|
1360
|
+
role: STATE_ROLES.timestamp,
|
|
1361
|
+
read: true,
|
|
1362
|
+
write: false,
|
|
1363
|
+
},
|
|
1364
|
+
native: {},
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.lastMonthStart`, {
|
|
1368
|
+
type: 'state',
|
|
1369
|
+
common: {
|
|
1370
|
+
name: 'Monatszähler zurückgesetzt am',
|
|
1371
|
+
type: 'number',
|
|
1372
|
+
role: STATE_ROLES.timestamp,
|
|
1373
|
+
read: true,
|
|
1374
|
+
write: false,
|
|
1375
|
+
},
|
|
1376
|
+
native: {},
|
|
1377
|
+
});
|
|
1378
|
+
|
|
1379
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.statistics.lastYearStart`, {
|
|
1380
|
+
type: 'state',
|
|
1381
|
+
common: {
|
|
1382
|
+
name: 'Jahreszähler zurückgesetzt am',
|
|
1383
|
+
type: 'number',
|
|
1384
|
+
role: STATE_ROLES.timestamp,
|
|
1385
|
+
read: true,
|
|
1386
|
+
write: false,
|
|
1387
|
+
},
|
|
1388
|
+
native: {},
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
adapter.log.debug(`Meter state structure created for ${type}.${meterName}`);
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* Deletes all states for a utility type
|
|
1396
|
+
*
|
|
1397
|
+
* @param {object} adapter - The adapter instance
|
|
1398
|
+
* @param {string} type - Utility type: 'gas', 'water', or 'electricity'
|
|
1399
|
+
* @returns {Promise<void>}
|
|
1400
|
+
*/
|
|
1401
|
+
async function deleteUtilityStateStructure(adapter, type) {
|
|
1402
|
+
try {
|
|
1403
|
+
await adapter.delObjectAsync(type, { recursive: true });
|
|
1404
|
+
adapter.log.debug(`State structure deleted for ${type}`);
|
|
1405
|
+
} catch (error) {
|
|
1406
|
+
adapter.log.warn(`Could not delete state structure for ${type}: ${error.message}`);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Creates the totals state structure for a utility type
|
|
1412
|
+
* Totals show the sum of all meters (main + additional)
|
|
1413
|
+
*
|
|
1414
|
+
* @param {object} adapter - The adapter instance
|
|
1415
|
+
* @param {string} type - Utility type: 'gas', 'water', or 'electricity'
|
|
1416
|
+
* @returns {Promise<void>}
|
|
1417
|
+
*/
|
|
1418
|
+
async function createTotalsStructure(adapter, type) {
|
|
1419
|
+
const labels = {
|
|
1420
|
+
gas: { name: 'Gas (Gesamt)', unit: 'kWh' },
|
|
1421
|
+
water: { name: 'Wasser (Gesamt)', unit: 'm³' },
|
|
1422
|
+
electricity: { name: 'Strom (Gesamt)', unit: 'kWh' },
|
|
1423
|
+
pv: { name: 'PV (Gesamt)', unit: 'kWh' },
|
|
1424
|
+
};
|
|
1425
|
+
|
|
1426
|
+
const label = labels[type];
|
|
1427
|
+
if (!label) {
|
|
1428
|
+
adapter.log.error(
|
|
1429
|
+
`MISSING LABEL for type "${type}" in createTotalsStructure! Valid types: ${Object.keys(labels).join(', ')}`,
|
|
1430
|
+
);
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
const basePath = `${type}.totals`;
|
|
1434
|
+
|
|
1435
|
+
// Create main channel
|
|
1436
|
+
await adapter.setObjectNotExistsAsync(basePath, {
|
|
1437
|
+
type: 'channel',
|
|
1438
|
+
common: {
|
|
1439
|
+
name: `${label.name} - Summe aller Zähler`,
|
|
1440
|
+
},
|
|
1441
|
+
native: {},
|
|
1442
|
+
});
|
|
1443
|
+
|
|
1444
|
+
// CONSUMPTION STATES (totals)
|
|
1445
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption`, {
|
|
1446
|
+
type: 'channel',
|
|
1447
|
+
common: {
|
|
1448
|
+
name: 'Gesamtverbrauch',
|
|
1449
|
+
},
|
|
1450
|
+
native: {},
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.daily`, {
|
|
1454
|
+
type: 'state',
|
|
1455
|
+
common: {
|
|
1456
|
+
name: `Tagesverbrauch Gesamt (${label.unit})`,
|
|
1457
|
+
type: 'number',
|
|
1458
|
+
role: STATE_ROLES.consumption,
|
|
1459
|
+
read: true,
|
|
1460
|
+
write: false,
|
|
1461
|
+
unit: label.unit,
|
|
1462
|
+
def: 0,
|
|
1463
|
+
},
|
|
1464
|
+
native: {},
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.monthly`, {
|
|
1468
|
+
type: 'state',
|
|
1469
|
+
common: {
|
|
1470
|
+
name: `Monatsverbrauch Gesamt (${label.unit})`,
|
|
1471
|
+
type: 'number',
|
|
1472
|
+
role: STATE_ROLES.consumption,
|
|
1473
|
+
read: true,
|
|
1474
|
+
write: false,
|
|
1475
|
+
unit: label.unit,
|
|
1476
|
+
def: 0,
|
|
1477
|
+
},
|
|
1478
|
+
native: {},
|
|
1479
|
+
});
|
|
1480
|
+
|
|
1481
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.consumption.yearly`, {
|
|
1482
|
+
type: 'state',
|
|
1483
|
+
common: {
|
|
1484
|
+
name: `Jahresverbrauch Gesamt (${label.unit})`,
|
|
1485
|
+
type: 'number',
|
|
1486
|
+
role: STATE_ROLES.consumption,
|
|
1487
|
+
read: true,
|
|
1488
|
+
write: false,
|
|
1489
|
+
unit: label.unit,
|
|
1490
|
+
def: 0,
|
|
1491
|
+
},
|
|
1492
|
+
native: {},
|
|
1493
|
+
});
|
|
1494
|
+
|
|
1495
|
+
// COST STATES (totals)
|
|
1496
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs`, {
|
|
1497
|
+
type: 'channel',
|
|
1498
|
+
common: {
|
|
1499
|
+
name: 'Gesamtkosten',
|
|
1500
|
+
},
|
|
1501
|
+
native: {},
|
|
1502
|
+
});
|
|
1503
|
+
|
|
1504
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.daily`, {
|
|
1505
|
+
type: 'state',
|
|
1506
|
+
common: {
|
|
1507
|
+
name: 'Tageskosten Gesamt (€)',
|
|
1508
|
+
type: 'number',
|
|
1509
|
+
role: STATE_ROLES.cost,
|
|
1510
|
+
read: true,
|
|
1511
|
+
write: false,
|
|
1512
|
+
unit: '€',
|
|
1513
|
+
def: 0,
|
|
1514
|
+
},
|
|
1515
|
+
native: {},
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.monthly`, {
|
|
1519
|
+
type: 'state',
|
|
1520
|
+
common: {
|
|
1521
|
+
name: 'Monatskosten Gesamt (€)',
|
|
1522
|
+
type: 'number',
|
|
1523
|
+
role: STATE_ROLES.cost,
|
|
1524
|
+
read: true,
|
|
1525
|
+
write: false,
|
|
1526
|
+
unit: '€',
|
|
1527
|
+
def: 0,
|
|
1528
|
+
},
|
|
1529
|
+
native: {},
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
await adapter.setObjectNotExistsAsync(`${basePath}.costs.totalYearly`, {
|
|
1533
|
+
type: 'state',
|
|
1534
|
+
common: {
|
|
1535
|
+
name: 'Jahreskosten Gesamt (€)',
|
|
1536
|
+
type: 'number',
|
|
1537
|
+
role: STATE_ROLES.cost,
|
|
1538
|
+
read: true,
|
|
1539
|
+
write: false,
|
|
1540
|
+
unit: '€',
|
|
1541
|
+
def: 0,
|
|
1542
|
+
},
|
|
1543
|
+
native: {},
|
|
1544
|
+
});
|
|
1545
|
+
|
|
1546
|
+
adapter.log.debug(`Totals state structure created for ${type}`);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
module.exports = {
|
|
1550
|
+
createUtilityStateStructure,
|
|
1551
|
+
createMeterStructure,
|
|
1552
|
+
createTotalsStructure,
|
|
1553
|
+
deleteUtilityStateStructure,
|
|
1554
|
+
safeSetObjectNotExists,
|
|
1555
|
+
STATE_ROLES,
|
|
1556
|
+
};
|