homebridge-smartsystem 6.3.2 → 6.3.4

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 CHANGED
@@ -277,9 +277,10 @@ Homebridge UI version
277
277
  - 6: power: 5% instead of 10% for power rules
278
278
 
279
279
  ### v6.3.x - 23-09-2022 - Shelly PM release
280
- - 1: first test 1 PM
280
+ - 1: first test Shelly PM - allow address or addresses, example: "192.168.0.95,102.168.0.96"
281
281
  - 2: logging now more according to debug true/false in the config file
282
-
282
+ - 3: power bindings now when: 5% change < 1000W, 2% change > 1000W
283
+ - 4: added if in set-plug if smappee not (yet) connected.
283
284
 
284
285
  ## Hardware
285
286
  A Raspberry Pi that connects to a Duotecno IP Node
package/config.json CHANGED
@@ -8,138 +8,104 @@
8
8
  "type": "sun",
9
9
  "channel": "0",
10
10
  "low": 30,
11
- "high": 900,
11
+ "high": 3000,
12
12
  "actions": [
13
13
  {
14
- "name": "Mood A",
14
+ "name": "Lamp-Bottom",
15
15
  "value": false,
16
16
  "masterAddress": "192.168.0.97",
17
17
  "masterPort": 5001,
18
- "logicalAddress": 10,
19
- "logicalNodeAddress": 252
18
+ "logicalAddress": 34,
19
+ "logicalNodeAddress": 3
20
20
  },
21
21
  {
22
- "name": "Mood A",
23
- "value": 50,
22
+ "name": "Lamp-Bottom",
23
+ "value": false,
24
24
  "masterAddress": "192.168.0.97",
25
25
  "masterPort": 5001,
26
- "logicalAddress": 10,
27
- "logicalNodeAddress": 252
26
+ "logicalAddress": 34,
27
+ "logicalNodeAddress": 3
28
28
  },
29
29
  {
30
- "name": "Mood A",
30
+ "name": "Lamp-Bottom",
31
31
  "value": true,
32
32
  "masterAddress": "192.168.0.97",
33
33
  "masterPort": 5001,
34
- "logicalAddress": 10,
35
- "logicalNodeAddress": 252
34
+ "logicalAddress": 34,
35
+ "logicalNodeAddress": 3
36
36
  }
37
37
  ],
38
- "power": 3263,
39
- "current": 2
38
+ "power": 146,
39
+ "current": 1
40
40
  },
41
41
  {
42
42
  "type": "power",
43
- "channel": "4",
44
- "low": 10,
45
- "high": 20,
43
+ "channel": "7+8+9",
44
+ "low": 100,
45
+ "high": 10000,
46
46
  "actions": [
47
47
  {
48
- "name": "Mood B",
48
+ "name": "",
49
49
  "value": false,
50
50
  "masterAddress": "192.168.0.97",
51
51
  "masterPort": 5001,
52
- "logicalAddress": 11,
53
- "logicalNodeAddress": 252
52
+ "logicalAddress": 30,
53
+ "logicalNodeAddress": 3
54
54
  },
55
55
  {
56
- "name": "Mood B",
57
- "value": 50,
56
+ "name": "",
57
+ "value": true,
58
58
  "masterAddress": "192.168.0.97",
59
59
  "masterPort": 5001,
60
- "logicalAddress": 11,
61
- "logicalNodeAddress": 252
60
+ "logicalAddress": 30,
61
+ "logicalNodeAddress": 3
62
62
  },
63
63
  {
64
- "name": "Mood B",
64
+ "name": "0;0",
65
65
  "value": true,
66
66
  "masterAddress": "192.168.0.97",
67
67
  "masterPort": 5001,
68
- "logicalAddress": 11,
69
- "logicalNodeAddress": 252
68
+ "logicalAddress": 0,
69
+ "logicalNodeAddress": 0
70
70
  }
71
71
  ],
72
- "power": 1,
73
- "current": 0
72
+ "power": 446,
73
+ "current": 1
74
74
  },
75
75
  {
76
76
  "type": "power",
77
77
  "channel": "7+8+9",
78
- "low": 30,
78
+ "low": 400,
79
79
  "high": 900,
80
80
  "actions": [
81
81
  {
82
- "name": "",
83
- "value": -1,
84
- "masterAddress": "192.168.0.97",
85
- "masterPort": 5001,
86
- "logicalAddress": 4,
87
- "logicalNodeAddress": 3
88
- },
89
- {
90
- "name": "",
91
- "value": -1,
82
+ "name": "Lamp-Top",
83
+ "value": false,
92
84
  "masterAddress": "192.168.0.97",
93
85
  "masterPort": 5001,
94
- "logicalAddress": 4,
86
+ "logicalAddress": 33,
95
87
  "logicalNodeAddress": 3
96
88
  },
97
89
  {
98
- "name": "",
99
- "value": -1,
90
+ "name": "Lamp-Top",
91
+ "value": true,
100
92
  "masterAddress": "192.168.0.97",
101
93
  "masterPort": 5001,
102
- "logicalAddress": 4,
94
+ "logicalAddress": 33,
103
95
  "logicalNodeAddress": 3
104
- }
105
- ]
106
- },
107
- {
108
- "type": "sun",
109
- "channel": "7",
110
- "low": 0,
111
- "high": 0,
112
- "actions": [
113
- {
114
- "name": "Mood C",
115
- "value": false,
116
- "masterAddress": "192.168.0.97",
117
- "masterPort": 5001,
118
- "logicalAddress": 12,
119
- "logicalNodeAddress": 252
120
- },
121
- {
122
- "name": "Mood C",
123
- "value": 50,
124
- "masterAddress": "192.168.0.97",
125
- "masterPort": 5001,
126
- "logicalAddress": 12,
127
- "logicalNodeAddress": 252
128
96
  },
129
97
  {
130
- "name": "Mood C",
98
+ "name": "--",
131
99
  "value": true,
132
100
  "masterAddress": "192.168.0.97",
133
101
  "masterPort": 5001,
134
- "logicalAddress": 12,
135
- "logicalNodeAddress": 252
102
+ "logicalAddress": 0,
103
+ "logicalNodeAddress": 0
136
104
  }
137
- ],
138
- "power": 3263,
139
- "current": 2
105
+ ]
140
106
  }
141
107
  ],
142
- "address": "192.168.0.186",
108
+ "address": "192.168.0.184",
143
109
  "uid": "57e3e0d8-bb05-4b04-8662-1a9871998f3f",
144
110
  "bindings": [
145
111
  {
@@ -190,40 +156,7 @@
190
156
  },
191
157
  "p1": {
192
158
  "debug": false,
193
- "rules": [
194
- {
195
- "type": "power",
196
- "channel": "3+4+5",
197
- "low": 30,
198
- "high": 1500,
199
- "actions": [
200
- {
201
- "name": "--",
202
- "value": false,
203
- "masterAddress": "192.168.0.97",
204
- "masterPort": 5001,
205
- "logicalAddress": 0,
206
- "logicalNodeAddress": 0
207
- },
208
- {
209
- "name": "--",
210
- "value": 50,
211
- "masterAddress": "192.168.0.97",
212
- "masterPort": 5001,
213
- "logicalAddress": 0,
214
- "logicalNodeAddress": 0
215
- },
216
- {
217
- "name": "Alles aan",
218
- "value": true,
219
- "masterAddress": "192.168.0.97",
220
- "masterPort": 5001,
221
- "logicalAddress": 5,
222
- "logicalNodeAddress": 3
223
- }
224
- ]
225
- }
226
- ],
159
+ "rules": [],
227
160
  "bindings": [
228
161
  {
229
162
  "logicalNodeAddress": 252,
@@ -380,6 +313,102 @@
380
313
  }
381
314
  ],
382
315
  "cunits": [
316
+ {
317
+ "logicalNodeAddress": 252,
318
+ "logicalAddress": 102,
319
+ "masterAddress": "192.168.0.97",
320
+ "masterPort": 5001,
321
+ "name": "<Solar Panels",
322
+ "displayName": "<Solar Panels",
323
+ "extendedType": 0,
324
+ "active": "N",
325
+ "used": "Y",
326
+ "group": 0
327
+ },
328
+ {
329
+ "logicalNodeAddress": 252,
330
+ "logicalAddress": 103,
331
+ "masterAddress": "192.168.0.97",
332
+ "masterPort": 5001,
333
+ "name": ">Cars",
334
+ "displayName": ">Cars",
335
+ "extendedType": 0,
336
+ "active": "N",
337
+ "used": "Y",
338
+ "group": 0
339
+ },
340
+ {
341
+ "logicalNodeAddress": 252,
342
+ "logicalAddress": 100,
343
+ "masterAddress": "192.168.0.97",
344
+ "masterPort": 5001,
345
+ "name": ">Grid",
346
+ "displayName": ">Grid",
347
+ "extendedType": 0,
348
+ "active": "N",
349
+ "used": "Y",
350
+ "group": 0
351
+ },
352
+ {
353
+ "logicalNodeAddress": 252,
354
+ "logicalAddress": 101,
355
+ "masterAddress": "192.168.0.97",
356
+ "masterPort": 5001,
357
+ "name": ">Swimmingpool",
358
+ "displayName": ">Swimmingpool",
359
+ "extendedType": 0,
360
+ "active": "N",
361
+ "used": "Y",
362
+ "group": 0
363
+ },
364
+ {
365
+ "logicalNodeAddress": 252,
366
+ "logicalAddress": 7,
367
+ "masterAddress": "192.168.0.97",
368
+ "masterPort": 5001,
369
+ "name": "Bottom-Left",
370
+ "displayName": "Bottom-Left",
371
+ "extendedType": 102,
372
+ "active": "Y",
373
+ "used": "Y",
374
+ "group": 0
375
+ },
376
+ {
377
+ "logicalNodeAddress": 3,
378
+ "logicalAddress": 30,
379
+ "masterAddress": "192.168.0.97",
380
+ "masterPort": 5001,
381
+ "name": "Blue LED",
382
+ "displayName": "Blue LED",
383
+ "extendedType": 1,
384
+ "active": "N",
385
+ "used": "Y",
386
+ "group": 0
387
+ },
388
+ {
389
+ "logicalNodeAddress": 3,
390
+ "logicalAddress": 34,
391
+ "masterAddress": "192.168.0.97",
392
+ "masterPort": 5001,
393
+ "name": "Lamp-Bottom",
394
+ "displayName": "Lamp-Bottom",
395
+ "extendedType": 2,
396
+ "active": "N",
397
+ "used": "Y",
398
+ "group": 0
399
+ },
400
+ {
401
+ "logicalNodeAddress": 3,
402
+ "logicalAddress": 33,
403
+ "masterAddress": "192.168.0.97",
404
+ "masterPort": 5001,
405
+ "name": "Lamp-Top",
406
+ "displayName": "Lamp-Top",
407
+ "extendedType": 2,
408
+ "active": "N",
409
+ "used": "Y",
410
+ "group": 0
411
+ },
383
412
  {
384
413
  "logicalNodeAddress": 3,
385
414
  "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.2",
4
+ "version": "6.3.4",
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",
@@ -9,7 +9,8 @@
9
9
  "license": "ISC",
10
10
  "scripts": {
11
11
  "start": "DEBUG=* homebridge -D -P '/Users/johan/Development/duotecno/smartsocket'",
12
- "watch": "npx tsc --build . --watch"
12
+ "watch": "npx tsc --build . --watch",
13
+ "publish": "npx tsc --build && npm i && npm publish"
13
14
  },
14
15
  "engines": {
15
16
  "node": ">=14.18.1",
@@ -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 ((!isNaN(power)) && (isNaN(b.power) || (Math.abs(b.power - power) > Math.abs(b.power * kPercentChange)))) {
103
- (0, logger_1.debug)("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name + " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) + " > threshold: " + Math.abs(b.power * kPercentChange));
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("homebridge", "set unit " + b.name + " to " + value);
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
- else {
112
- (0, logger_1.debug)("power", "DONT to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name + " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) + " > threshold: " + Math.abs(b.power * kPercentChange));
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 (" + value + ") " + binding.masterAddress + " - " + binding.logicalNodeAddress + ";" + binding.logicalAddress + " *****");
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
- else
197
- throw new Error("***** UNIT NOT FOUND for action (" + action.value + ") " + action.masterAddress + " - " + action.logicalNodeAddress + ";" + action.logicalAddress + " *****");
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
  //
@@ -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 ((!isNaN(power)) && (isNaN(b.power) || (Math.abs(b.power - power) > Math.abs(b.power * kPercentChange)))) {
120
- debug("power", "APPLY to " + b.channel + " = " + b.power + " -> " + power + " for " + b.name + " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) + " > threshold: " + Math.abs(b.power * kPercentChange))
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("homebridge", "set unit " + b.name + " to " + value);
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 + " (" + b.logicalNodeAddress + ";" + b.logicalAddress + "): difference: " + Math.abs(b.power - power) + " > threshold: " + Math.abs(b.power * kPercentChange))
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), binding.logicalNodeAddress, binding.logicalAddress);
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 (" + value + ") " + binding.masterAddress + " - " + binding.logicalNodeAddress + ";" + binding.logicalAddress + " *****");
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
- ", Export = " + this.realtime.totalExportEnergy +
155
- ", Import = " + this.realtime.totalImportEnergy);
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
- ", power = " + power + ", channel = " + rule.channel +
206
- " -> current = " + newCurrent +
207
- " (unit: " + rule.actions[newCurrent].name + ", value: " + rule.actions[newCurrent].value + ")");
208
- rule.current = newCurrent;})
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
- else
219
- throw new Error("***** UNIT NOT FOUND for action (" + action.value + ") " + action.masterAddress + " - " + action.logicalNodeAddress + ";" + action.logicalAddress + " *****");
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
  //
package/server/smappee.js CHANGED
@@ -280,9 +280,14 @@ class Smappee extends powerbase_1.PowerBase {
280
280
  if ((typeof currState === "boolean") && (state != currState)) {
281
281
  // do we need to do this? do we get an mqtt status message ??
282
282
  this.plugs[plugNr].value = currState;
283
- const topic = 'servicelocation/' + this.config.uid + '/plug/' + plugNr + '/setstate';
284
- const payload = '{"value": "' + ((state) ? "ON" : "OFF") + '", "since": "' + (new Date().getTime()) + '"}';
285
- this.client.publish(topic, payload);
283
+ if (this.client) {
284
+ const topic = 'servicelocation/' + this.config.uid + '/plug/' + plugNr + '/setstate';
285
+ const payload = '{"value": "' + ((state) ? "ON" : "OFF") + '", "since": "' + (new Date().getTime()) + '"}';
286
+ this.client.publish(topic, payload);
287
+ }
288
+ else {
289
+ (0, logger_1.err)("smappee", "no open connection (yet?) to " + this.config.uid + " on " + this.config.address);
290
+ }
286
291
  }
287
292
  }
288
293
  }
package/server/smappee.ts CHANGED
@@ -296,9 +296,13 @@ export class Smappee extends PowerBase {
296
296
  // do we need to do this? do we get an mqtt status message ??
297
297
  this.plugs[plugNr].value = currState;
298
298
 
299
- const topic = 'servicelocation/' + this.config.uid + '/plug/' + plugNr + '/setstate';
300
- const payload = '{"value": "' + ((state) ? "ON" : "OFF") + '", "since": "' + (new Date().getTime()) + '"}';
301
- this.client.publish(topic, payload);
299
+ if (this.client) {
300
+ const topic = 'servicelocation/' + this.config.uid + '/plug/' + plugNr + '/setstate';
301
+ const payload = '{"value": "' + ((state) ? "ON" : "OFF") + '", "since": "' + (new Date().getTime()) + '"}';
302
+ this.client.publish(topic, payload);
303
+ } else {
304
+ err("smappee", "no open connection (yet?) to " + this.config.uid + " on " + this.config.address);
305
+ }
302
306
  }
303
307
  }
304
308