homebridge-smartsystem 6.3.2 → 6.3.3
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 +1 -0
- package/config.json +48 -0
- package/package.json +1 -1
- package/server/powerbase.js +31 -12
- package/server/powerbase.ts +46 -19
package/README.md
CHANGED
|
@@ -279,6 +279,7 @@ Homebridge UI version
|
|
|
279
279
|
### v6.3.x - 23-09-2022 - Shelly PM release
|
|
280
280
|
- 1: first test 1 PM
|
|
281
281
|
- 2: logging now more according to debug true/false in the config file
|
|
282
|
+
- 3: power bindings now when: 5% change < 1000W, 2% change > 1000W
|
|
282
283
|
|
|
283
284
|
|
|
284
285
|
## Hardware
|
package/config.json
CHANGED
|
@@ -380,6 +380,54 @@
|
|
|
380
380
|
}
|
|
381
381
|
],
|
|
382
382
|
"cunits": [
|
|
383
|
+
{
|
|
384
|
+
"logicalNodeAddress": 252,
|
|
385
|
+
"logicalAddress": 102,
|
|
386
|
+
"masterAddress": "192.168.0.97",
|
|
387
|
+
"masterPort": 5001,
|
|
388
|
+
"name": "<Solar Panels",
|
|
389
|
+
"displayName": "<Solar Panels",
|
|
390
|
+
"extendedType": 0,
|
|
391
|
+
"active": "N",
|
|
392
|
+
"used": "Y",
|
|
393
|
+
"group": 0
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"logicalNodeAddress": 252,
|
|
397
|
+
"logicalAddress": 103,
|
|
398
|
+
"masterAddress": "192.168.0.97",
|
|
399
|
+
"masterPort": 5001,
|
|
400
|
+
"name": ">Cars",
|
|
401
|
+
"displayName": ">Cars",
|
|
402
|
+
"extendedType": 0,
|
|
403
|
+
"active": "N",
|
|
404
|
+
"used": "Y",
|
|
405
|
+
"group": 0
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
"logicalNodeAddress": 252,
|
|
409
|
+
"logicalAddress": 100,
|
|
410
|
+
"masterAddress": "192.168.0.97",
|
|
411
|
+
"masterPort": 5001,
|
|
412
|
+
"name": ">Grid",
|
|
413
|
+
"displayName": ">Grid",
|
|
414
|
+
"extendedType": 0,
|
|
415
|
+
"active": "N",
|
|
416
|
+
"used": "Y",
|
|
417
|
+
"group": 0
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
"logicalNodeAddress": 252,
|
|
421
|
+
"logicalAddress": 101,
|
|
422
|
+
"masterAddress": "192.168.0.97",
|
|
423
|
+
"masterPort": 5001,
|
|
424
|
+
"name": ">Swimmingpool",
|
|
425
|
+
"displayName": ">Swimmingpool",
|
|
426
|
+
"extendedType": 0,
|
|
427
|
+
"active": "N",
|
|
428
|
+
"used": "Y",
|
|
429
|
+
"group": 0
|
|
430
|
+
},
|
|
383
431
|
{
|
|
384
432
|
"logicalNodeAddress": 3,
|
|
385
433
|
"logicalAddress": 4,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-smartsystem",
|
|
3
3
|
"displayname": "Duotecno Bridge",
|
|
4
|
-
"version": "6.3.
|
|
4
|
+
"version": "6.3.3",
|
|
5
5
|
"description": "SmartServer (Proxy Websockets to TCP sockets, Smappee MQTT, Duotecno IP Nodes, Homekit interface)",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"author": "Johan Coppieters",
|
package/server/powerbase.js
CHANGED
|
@@ -94,22 +94,40 @@ class PowerBase extends base_1.Base {
|
|
|
94
94
|
//////////////////////////////////////////////
|
|
95
95
|
// Bindings to Duotecno virtual temp sensor //
|
|
96
96
|
//////////////////////////////////////////////
|
|
97
|
+
significant(current, previous) {
|
|
98
|
+
// no values yet -> don't update
|
|
99
|
+
if (isNaN(current))
|
|
100
|
+
return false;
|
|
101
|
+
// no previous value -> always update
|
|
102
|
+
if (isNaN(previous))
|
|
103
|
+
return true;
|
|
104
|
+
// less than 1000W -> update on: difference > 5% previous
|
|
105
|
+
if (current < 1000)
|
|
106
|
+
return Math.abs(previous - current) > (previous * 0.05);
|
|
107
|
+
// more than 1000W -> update on: difference > 2% previous
|
|
108
|
+
if (current >= 1000)
|
|
109
|
+
return Math.abs(previous - current) > (previous * 0.02);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
97
112
|
applyBindings() {
|
|
98
113
|
if (this.realtimeCounter % 2 === 0) {
|
|
99
114
|
// for all bindings
|
|
100
115
|
this.bindings.forEach(b => {
|
|
101
116
|
const power = this.evalPower(b.channel);
|
|
102
|
-
if (
|
|
103
|
-
(0, logger_1.debug)("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
117
|
+
if (this.significant(power, b.power)) {
|
|
118
|
+
(0, logger_1.debug)("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
119
|
+
" (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) +
|
|
120
|
+
" > threshold: 5% =" + Math.abs(b.power * 0.05) + " > threshold: 2% =" + Math.abs(b.power * 0.02));
|
|
104
121
|
this.applyBinding(b, power)
|
|
105
122
|
.then(value => {
|
|
106
123
|
b.power = value;
|
|
107
|
-
// debug("
|
|
124
|
+
// debug("power", "set unit " + b.name + " to " + value);
|
|
108
125
|
})
|
|
109
126
|
.catch((e) => (0, logger_1.err)(this.type, e.message || e));
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
127
|
+
// } else {
|
|
128
|
+
// debug("power", "DONT to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
129
|
+
// " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) +
|
|
130
|
+
// " > threshold: 5% =" + Math.abs(b.power * 0.05) + " > threshold: 2% =" + Math.abs(b.power * 0.02));
|
|
113
131
|
}
|
|
114
132
|
});
|
|
115
133
|
}
|
|
@@ -122,8 +140,8 @@ class PowerBase extends base_1.Base {
|
|
|
122
140
|
yield unit.setSensorValue(Math.abs(value));
|
|
123
141
|
return value;
|
|
124
142
|
}
|
|
125
|
-
else {
|
|
126
|
-
throw new Error("***** UNIT NOT FOUND for binding
|
|
143
|
+
else if ((binding.logicalNodeAddress != 0) || (binding.logicalAddress != 0)) {
|
|
144
|
+
throw new Error("***** UNIT NOT FOUND for binding value " + value + " to " + binding.masterAddress + " - " + binding.logicalNodeAddress + ";" + binding.logicalAddress + " *****");
|
|
127
145
|
}
|
|
128
146
|
});
|
|
129
147
|
}
|
|
@@ -144,7 +162,6 @@ class PowerBase extends base_1.Base {
|
|
|
144
162
|
if (rule.type === "power") {
|
|
145
163
|
// add all channels this rule refers to
|
|
146
164
|
power = this.evalPower(rule.channel);
|
|
147
|
-
// power = rule.channel.split("+").reduce((acc, cur) => acc + this.channels[parseInt(cur)]?.power ?? 0, 0);
|
|
148
165
|
}
|
|
149
166
|
else if (rule.type === "sun") {
|
|
150
167
|
// calc fake power usage
|
|
@@ -191,10 +208,12 @@ class PowerBase extends base_1.Base {
|
|
|
191
208
|
applyCommand(action) {
|
|
192
209
|
return __awaiter(this, void 0, void 0, function* () {
|
|
193
210
|
const unit = this.system.findUnit(this.system.findMaster(action.masterAddress, action.masterPort), action.logicalNodeAddress, action.logicalAddress);
|
|
194
|
-
if (unit)
|
|
211
|
+
if (unit) {
|
|
195
212
|
yield unit.setState(action.value);
|
|
196
|
-
|
|
197
|
-
|
|
213
|
+
}
|
|
214
|
+
else if ((action.logicalNodeAddress != 0) || (action.logicalAddress != 0)) {
|
|
215
|
+
throw new Error("***** UNIT NOT FOUND for action for value " + action.value + " to " + action.masterAddress + " - " + action.logicalNodeAddress + ";" + action.logicalAddress + " *****");
|
|
216
|
+
}
|
|
198
217
|
});
|
|
199
218
|
}
|
|
200
219
|
//
|
package/server/powerbase.ts
CHANGED
|
@@ -111,36 +111,61 @@ export class PowerBase extends Base {
|
|
|
111
111
|
//////////////////////////////////////////////
|
|
112
112
|
// Bindings to Duotecno virtual temp sensor //
|
|
113
113
|
//////////////////////////////////////////////
|
|
114
|
+
significant(current: number, previous: number): boolean {
|
|
115
|
+
// no values yet -> don't update
|
|
116
|
+
if (isNaN(current))
|
|
117
|
+
return false;
|
|
118
|
+
|
|
119
|
+
// no previous value -> always update
|
|
120
|
+
if (isNaN(previous))
|
|
121
|
+
return true;
|
|
122
|
+
|
|
123
|
+
// less than 1000W -> update on: difference > 5% previous
|
|
124
|
+
if (current < 1000)
|
|
125
|
+
return Math.abs(previous - current) > (previous * 0.05);
|
|
126
|
+
|
|
127
|
+
// more than 1000W -> update on: difference > 2% previous
|
|
128
|
+
if (current >= 1000)
|
|
129
|
+
return Math.abs(previous - current) > (previous * 0.02);
|
|
130
|
+
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
|
|
114
134
|
applyBindings() {
|
|
115
135
|
if (this.realtimeCounter % 2 === 0) {
|
|
116
136
|
// for all bindings
|
|
117
137
|
this.bindings.forEach( b => {
|
|
118
138
|
const power = this.evalPower(b.channel);
|
|
119
|
-
if (
|
|
120
|
-
debug("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
139
|
+
if (this.significant(power, b.power)) {
|
|
140
|
+
debug("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
141
|
+
" (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) +
|
|
142
|
+
" > threshold: 5% =" + Math.abs(b.power * 0.05) + " > threshold: 2% =" + Math.abs(b.power * 0.02));
|
|
121
143
|
this.applyBinding(b, power)
|
|
122
144
|
.then(value => {
|
|
123
145
|
b.power = value;
|
|
124
|
-
// debug("
|
|
146
|
+
// debug("power", "set unit " + b.name + " to " + value);
|
|
125
147
|
})
|
|
126
148
|
.catch((e) => err(this.type, e.message || e));
|
|
127
149
|
|
|
128
|
-
} else {
|
|
129
|
-
debug("power", "DONT to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
150
|
+
// } else {
|
|
151
|
+
// debug("power", "DONT to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name +
|
|
152
|
+
// " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) +
|
|
153
|
+
// " > threshold: 5% =" + Math.abs(b.power * 0.05) + " > threshold: 2% =" + Math.abs(b.power * 0.02));
|
|
130
154
|
}
|
|
131
155
|
});
|
|
132
156
|
}
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
async applyBinding(binding: Binding, value: number): Promise<number> {
|
|
136
|
-
const unit = this.system.findUnit(this.system.findMaster(binding.masterAddress, binding.masterPort),
|
|
160
|
+
const unit = this.system.findUnit(this.system.findMaster(binding.masterAddress, binding.masterPort),
|
|
161
|
+
binding.logicalNodeAddress, binding.logicalAddress);
|
|
137
162
|
if (unit) {
|
|
138
163
|
if (!isNaN(value))
|
|
139
164
|
await unit.setSensorValue(Math.abs(value));
|
|
140
165
|
return value;
|
|
141
166
|
|
|
142
|
-
} else {
|
|
143
|
-
throw new Error("***** UNIT NOT FOUND for binding
|
|
167
|
+
} else if ((binding.logicalNodeAddress != 0) || (binding.logicalAddress != 0)) {
|
|
168
|
+
throw new Error("***** UNIT NOT FOUND for binding value " + value + " to " + binding.masterAddress + " - " + binding.logicalNodeAddress + ";" + binding.logicalAddress + " *****");
|
|
144
169
|
}
|
|
145
170
|
}
|
|
146
171
|
|
|
@@ -151,8 +176,8 @@ export class PowerBase extends Base {
|
|
|
151
176
|
applyRules() {
|
|
152
177
|
if (this.realtimeCounter % 60 === 0) {
|
|
153
178
|
log("power", this.type + " > RealTime totals: Power = " + this.realtime.totalPower +
|
|
154
|
-
|
|
155
|
-
|
|
179
|
+
", Export = " + this.realtime.totalExportEnergy +
|
|
180
|
+
", Import = " + this.realtime.totalImportEnergy);
|
|
156
181
|
}
|
|
157
182
|
|
|
158
183
|
if (this.realtimeCounter % 5 === 0) {
|
|
@@ -164,7 +189,6 @@ export class PowerBase extends Base {
|
|
|
164
189
|
if (rule.type === "power") {
|
|
165
190
|
// add all channels this rule refers to
|
|
166
191
|
power = this.evalPower(rule.channel);
|
|
167
|
-
// power = rule.channel.split("+").reduce((acc, cur) => acc + this.channels[parseInt(cur)]?.power ?? 0, 0);
|
|
168
192
|
|
|
169
193
|
} else if (rule.type === "sun") {
|
|
170
194
|
// calc fake power usage
|
|
@@ -201,11 +225,12 @@ export class PowerBase extends Base {
|
|
|
201
225
|
rule.current = newCurrent;
|
|
202
226
|
if (newCurrent < rule.actions.length) {
|
|
203
227
|
this.applyCommand(rule.actions[newCurrent])
|
|
204
|
-
.then((val) => {debug("power", "## sent command -> " + rule.type +
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
228
|
+
.then((val) => { debug("power", "## sent command -> " + rule.type +
|
|
229
|
+
", power = " + power + ", channel = " + rule.channel +
|
|
230
|
+
" -> current = " + newCurrent +
|
|
231
|
+
" (unit: " + rule.actions[newCurrent].name + ", value: " + rule.actions[newCurrent].value + ")");
|
|
232
|
+
rule.current = newCurrent;
|
|
233
|
+
})
|
|
209
234
|
.catch((e) => err(this.type, e.message));
|
|
210
235
|
}
|
|
211
236
|
}
|
|
@@ -213,10 +238,12 @@ export class PowerBase extends Base {
|
|
|
213
238
|
|
|
214
239
|
async applyCommand(action: Action) {
|
|
215
240
|
const unit = this.system.findUnit(this.system.findMaster(action.masterAddress, action.masterPort), action.logicalNodeAddress, action.logicalAddress);
|
|
216
|
-
if (unit)
|
|
241
|
+
if (unit) {
|
|
217
242
|
await unit.setState(action.value);
|
|
218
|
-
|
|
219
|
-
|
|
243
|
+
|
|
244
|
+
} else if ((action.logicalNodeAddress != 0) || (action.logicalAddress != 0)) {
|
|
245
|
+
throw new Error("***** UNIT NOT FOUND for action for value " + action.value + " to " + action.masterAddress + " - " + action.logicalNodeAddress + ";" + action.logicalAddress + " *****");
|
|
246
|
+
}
|
|
220
247
|
}
|
|
221
248
|
|
|
222
249
|
//
|