homebridge-smartsystem 6.2.6 → 6.3.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/server/p1.ts CHANGED
@@ -182,43 +182,45 @@ export class P1 extends PowerBase {
182
182
 
183
183
  consume(data: P1Data) {
184
184
  if (! data['32.7.0']) return;
185
-
186
- this.voltages = [data['32.7.0']?.value, data['52.7.0']?.value, data['72.7.0']?.value];
187
- this.realtime = { totalPower: data['1.7.0']?.value * 1000,
188
- totalReactivePower: data['2.7.0']?.value * 1000,
189
- totalExportEnergy: data['2.8.1']?.value + data['2.8.2']?.value,
190
- totalImportEnergy: data['1.8.1']?.value + data['1.8.2']?.value,
191
- monitorStatus: 0, utcTimeStamp: new Date().getTime() };
192
185
 
193
186
  this.channels = {
194
187
  0: {
195
- name: "Zonnepanelen L1", type: "CT", flow: "PRODUCTION",
188
+ name: "Zonnepanelen L1", type: "CT", flow: "PRODUCTION", voltage: data['32.7.0']?.value,
196
189
  power: data['22.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 0,
197
190
  current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
198
191
  1: {
199
- name: "Zonnepanelen L2", type: "CT", flow: "PRODUCTION",
192
+ name: "Zonnepanelen L2", type: "CT", flow: "PRODUCTION", voltage: data['52.7.0']?.value,
200
193
  power: data['42.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 1,
201
194
  current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
202
195
  2: {
203
- name: "Zonnepanelen L3", type: "CT", flow: "PRODUCTION",
196
+ name: "Zonnepanelen L3", type: "CT", flow: "PRODUCTION", voltage: data['72.7.0']?.value,
204
197
  power: data['62.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 2,
205
198
  current: 0, apparentPower: 0, cosPhi: 0, formula: ""},
206
199
  3: {
207
- name: "Grid L1", type: "CT", flow: "CONSUMPTION",
200
+ name: "Grid L1", type: "CT", flow: "CONSUMPTION", voltage: data['32.7.0']?.value,
208
201
  power: data['21.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 0,
209
202
  current: data['31.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""},
210
203
  4: {
211
- name: "Grid L2", type: "CT", flow: "CONSUMPTION",
204
+ name: "Grid L2", type: "CT", flow: "CONSUMPTION", voltage: data['52.7.0']?.value,
212
205
  power: data['41.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 1,
213
206
  current: data['51.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""},
214
207
  5: {
215
- name: "Grid L3", type: "CT", flow: "CONSUMPTION",
208
+ name: "Grid L3", type: "CT", flow: "CONSUMPTION", voltage: data['72.7.0']?.value,
216
209
  power: data['61.7.0']?.value * 1000, exportEnergy: 0, importEnergy: 0, phaseId: 2,
217
210
  current: data['71.7.0']?.value, apparentPower: 0, cosPhi: 0, formula: ""}
218
211
  };
219
212
  // console.log(data);
220
213
 
214
+ this.voltages = [data['32.7.0']?.value, data['52.7.0']?.value, data['72.7.0']?.value];
215
+ this.realtime = { totalPower: data['1.7.0']?.value * 1000,
216
+ totalReactivePower: data['2.7.0']?.value * 1000,
217
+ totalExportEnergy: data['2.8.1']?.value + data['2.8.2']?.value,
218
+ totalImportEnergy: data['1.8.1']?.value + data['1.8.2']?.value,
219
+ monitorStatus: 0, utcTimeStamp: new Date().getTime() };
220
+
221
221
  this.production = this.realtime.totalPower;
222
222
  this.consumption = this.realtime.totalReactivePower;
223
+
224
+
223
225
  }
224
226
  }
@@ -72,7 +72,8 @@ class PowerBase extends base_1.Base {
72
72
  //
73
73
  updateConfig(config) {
74
74
  return __awaiter(this, void 0, void 0, function* () {
75
- this.config.address = config.address;
75
+ if (config.address)
76
+ this.config.address = config.address;
76
77
  this.writeConfig();
77
78
  return this.init(false);
78
79
  });
@@ -105,7 +106,7 @@ class PowerBase extends base_1.Base {
105
106
  b.power = value;
106
107
  // debug("homebridge", "set unit " + b.name + " to " + value);
107
108
  })
108
- .catch((e) => (0, logger_1.err)(this.type, e));
109
+ .catch((e) => (0, logger_1.err)(this.type, e.message || e));
109
110
  }
110
111
  else {
111
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));
@@ -130,10 +131,10 @@ class PowerBase extends base_1.Base {
130
131
  // Rules execution //
131
132
  /////////////////////
132
133
  applyRules() {
133
- if (this.realtimeCounter % 30 === 0) {
134
- (0, logger_1.log)("power", this.type + " > processRealTime: totalPower = " + this.realtime.totalPower +
135
- ", export = " + this.realtime.totalExportEnergy +
136
- ", import = " + this.realtime.totalImportEnergy);
134
+ if (this.realtimeCounter % 60 === 0) {
135
+ (0, logger_1.log)("power", this.type + " > RealTime totals: Power = " + this.realtime.totalPower +
136
+ ", Export = " + this.realtime.totalExportEnergy +
137
+ ", Import = " + this.realtime.totalImportEnergy);
137
138
  }
138
139
  if (this.realtimeCounter % 5 === 0) {
139
140
  // for all rules
@@ -1,6 +1,6 @@
1
1
  import { System } from "../duotecno/system";
2
2
  import { PowerBaseConfig, Rule, Binding, Sanitizers, Boundaries, Action, kEmptyBinding, kEmptyRule } from "../duotecno/types";
3
- import { err, debug, log } from "../duotecno/logger";
3
+ import { err, debug, log, logSettings, LogLevel } from "../duotecno/logger";
4
4
  import { Base } from "./base";
5
5
  import { Context } from "./webapp";
6
6
 
@@ -28,7 +28,7 @@ export class PowerBase extends Base {
28
28
  totalExportEnergy: number, totalImportEnergy: number,
29
29
  monitorStatus: number, utcTimeStamp: number }
30
30
  channels: { [publishIndex: number]: {
31
- name: string, type: string, flow: string,
31
+ name: string, type: string, flow: string, voltage: number,
32
32
  power: number, exportEnergy: number, importEnergy: number, phaseId: number,
33
33
  current: number, apparentPower: number, cosPhi: number, formula: string} };
34
34
 
@@ -87,7 +87,9 @@ export class PowerBase extends Base {
87
87
  // config mgt
88
88
  //
89
89
  async updateConfig(config: any) {
90
- this.config.address = config.address;
90
+ if (config.address)
91
+ this.config.address = config.address;
92
+
91
93
  this.writeConfig();
92
94
 
93
95
  return this.init(false);
@@ -121,7 +123,7 @@ export class PowerBase extends Base {
121
123
  b.power = value;
122
124
  // debug("homebridge", "set unit " + b.name + " to " + value);
123
125
  })
124
- .catch((e) => err(this.type, e));
126
+ .catch((e) => err(this.type, e.message || e));
125
127
 
126
128
  } else {
127
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))
@@ -147,10 +149,10 @@ export class PowerBase extends Base {
147
149
  // Rules execution //
148
150
  /////////////////////
149
151
  applyRules() {
150
- if (this.realtimeCounter % 30 === 0) {
151
- log("power", this.type + " > processRealTime: totalPower = " + this.realtime.totalPower +
152
- ", export = " + this.realtime.totalExportEnergy +
153
- ", import = " + this.realtime.totalImportEnergy);
152
+ if (this.realtimeCounter % 60 === 0) {
153
+ log("power", this.type + " > RealTime totals: Power = " + this.realtime.totalPower +
154
+ ", Export = " + this.realtime.totalExportEnergy +
155
+ ", Import = " + this.realtime.totalImportEnergy);
154
156
  }
155
157
 
156
158
  if (this.realtimeCounter % 5 === 0) {
package/server/shelly.js CHANGED
@@ -15,10 +15,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Shelly = void 0;
16
16
  const logger_1 = require("../duotecno/logger");
17
17
  const powerbase_1 = require("./powerbase");
18
+ const api_1 = require("../duotecno/api");
19
+ const HTTPstatus = {
20
+ "wifi_sta": {
21
+ "connected": true,
22
+ "ssid": "Tele Coppieters",
23
+ "ip": "192.168.0.95",
24
+ "rssi": -73
25
+ },
26
+ "cloud": {
27
+ "enabled": true,
28
+ "connected": true
29
+ },
30
+ "mqtt": {
31
+ "connected": false
32
+ },
33
+ "time": "18:17",
34
+ "unixtime": 1663863464,
35
+ "serial": 7,
36
+ "has_update": true,
37
+ "mac": "C45BBE7928B9",
38
+ "cfg_changed_cnt": 1,
39
+ "actions_stats": { "skipped": 0 },
40
+ "relays": [{ "ison": true, "has_timer": false, "timer_started": 0, "timer_duration": 0, "timer_remaining": 0, "overpower": false, "is_valid": true, "source": "http" }],
41
+ "emeters": [
42
+ { "power": 10.66, "pf": 1.00, "current": 0.08, "voltage": 232.06, "is_valid": true, "total": 5.3, "total_returned": 0.0 },
43
+ { "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.06, "is_valid": true, "total": 0.0, "total_returned": 0.0 },
44
+ { "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.05, "is_valid": true, "total": 0.0, "total_returned": 0.0 }
45
+ ],
46
+ "total_power": 10.66,
47
+ "fs_mounted": true,
48
+ "update": { "status": "pending", "has_update": true, "new_version": "20220830-080542/v1.12-3EM-gcf4f7c2", "old_version": "20220209-094824/v1.11.8-g8c7bb8d" },
49
+ "ram_total": 49440,
50
+ "ram_free": 30960,
51
+ "fs_size": 233681,
52
+ "fs_free": 156875,
53
+ "uptime": 1364
54
+ };
55
+ const HttpEMeter0 = {
56
+ "power": 10.95,
57
+ "pf": 1.00,
58
+ "current": 0.08,
59
+ "voltage": 231.21,
60
+ "is_valid": true,
61
+ "total": 7.2,
62
+ "total_returned": 0.0
63
+ };
18
64
  class Shelly extends powerbase_1.PowerBase {
19
65
  constructor(system) {
20
- super("p1", system);
66
+ super("shelly", system);
21
67
  this.timer = null;
68
+ this.meters = [];
69
+ this.nrPhases = 0;
22
70
  // init is called by super
23
71
  }
24
72
  //
@@ -31,22 +79,43 @@ class Shelly extends powerbase_1.PowerBase {
31
79
  //
32
80
  // config mgt
33
81
  //
34
- // async updateConfig(config: any) {
35
- // // nothing special... for now
36
- // return super.updateConfig(config);
37
- // }
82
+ updateConfig(config) {
83
+ const _super = Object.create(null, {
84
+ updateConfig: { get: () => super.updateConfig }
85
+ });
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ this.config.addresses = config.addresses;
88
+ return _super.updateConfig.call(this, config);
89
+ });
90
+ }
38
91
  subscribe() {
39
92
  return __awaiter(this, void 0, void 0, function* () {
40
- (0, logger_1.log)("shelly", "connecting to Shelly: " + this.config.address);
93
+ const kInterval = 5;
41
94
  if (this.config.address) {
42
- this.timer = setInterval(() => {
43
- this.realtimeCounter++;
44
- // fetch data from API
45
- (0, logger_1.debug)("shelly", "call shelly API");
95
+ yield this.getDeviceConfig(this.config.address, true);
96
+ }
97
+ if (this.config.addresses) {
98
+ const list = this.config.addresses.split(",");
99
+ for (let inx in list) {
100
+ const phases = (this.config.address) ? false : (inx == "0");
101
+ yield this.getDeviceConfig(list[inx], phases);
102
+ }
103
+ }
104
+ (0, logger_1.debug)("shelly", "meters: " + JSON.stringify(this.meters));
105
+ if (this.meters.length) {
106
+ this.timer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
107
+ this.realtimeCounter += kInterval;
108
+ // fetch data
109
+ const ok = yield this.fetchData();
110
+ if (ok)
111
+ this.consume();
46
112
  // call process/bindings/rules
47
113
  this.applyBindings();
48
114
  this.applyRules();
49
- }, 5000);
115
+ }), kInterval * 1000);
116
+ }
117
+ else {
118
+ (0, logger_1.log)("shelly", "No Shelly PM devices configured");
50
119
  }
51
120
  });
52
121
  }
@@ -58,6 +127,70 @@ class Shelly extends powerbase_1.PowerBase {
58
127
  }
59
128
  });
60
129
  }
130
+ getDeviceConfig(address, phases) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ try {
133
+ // debug("shelly", "fetching from " + address + "/status");
134
+ const res = yield (0, api_1.get)(address, 80, "/status", undefined);
135
+ (0, logger_1.debug)("shelly", "received status from " + address + " -> " + res);
136
+ const status = JSON.parse(res);
137
+ // enrich meter with its address and index + add to the global meter list
138
+ status.emeters.forEach((m, inx) => {
139
+ m.index = inx; // index with this PM device
140
+ m.phase = phases;
141
+ if (phases) {
142
+ m.phaseNr = this.nrPhases;
143
+ this.nrPhases++;
144
+ }
145
+ else {
146
+ m.phaseNr = -1;
147
+ }
148
+ m.address = address;
149
+ this.meters.push(m);
150
+ });
151
+ }
152
+ catch (error) {
153
+ (0, logger_1.err)("shelly", error.message);
154
+ }
155
+ });
156
+ }
157
+ fetchData() {
158
+ return __awaiter(this, void 0, void 0, function* () {
159
+ try {
160
+ for (let meter in this.meters) {
161
+ // debug("shelly", "fetching from " + this.config.address + "/emeter/" + meter);
162
+ const res = yield (0, api_1.get)(this.meters[meter].address, 80, "/emeter/" + this.meters[meter].index, undefined);
163
+ (0, logger_1.debug)("shelly", "received meter: " + meter + " -> " + res);
164
+ this.meters[meter] = Object.assign(Object.assign({}, this.meters[meter]), JSON.parse(res));
165
+ }
166
+ ;
167
+ return true;
168
+ }
169
+ catch (error) {
170
+ (0, logger_1.err)("shelly", error.message || error);
171
+ return false;
172
+ }
173
+ });
174
+ }
175
+ consume() {
176
+ // copy this.meters into the powerbase structures
177
+ this.meters.forEach((meter, inx) => {
178
+ this.channels[inx] = {
179
+ name: "Meter " + (inx + 1), type: "CT", flow: "PRODUCTION",
180
+ power: meter.power, exportEnergy: meter.total_returned, importEnergy: meter.total, phaseId: meter.phaseNr,
181
+ current: meter.power / meter.voltage, apparentPower: 0, cosPhi: 0, formula: "", voltage: meter.voltage
182
+ };
183
+ });
184
+ this.voltages = [0, 0, 0];
185
+ this.meters.filter(m => m.phase).forEach(m => this.voltages[m.phaseNr] = m.voltage);
186
+ this.realtime = { totalPower: this.meters.reduce((prev, curr) => curr.power + prev, 0),
187
+ totalReactivePower: 0,
188
+ totalExportEnergy: this.meters.reduce((prev, curr) => curr.total_returned + prev, 0),
189
+ totalImportEnergy: this.meters.reduce((prev, curr) => curr.total + prev, 0),
190
+ monitorStatus: 0, utcTimeStamp: new Date().getTime() };
191
+ this.production = this.realtime.totalPower;
192
+ this.consumption = this.realtime.totalReactivePower;
193
+ }
61
194
  }
62
195
  exports.Shelly = Shelly;
63
196
  //# sourceMappingURL=shelly.js.map
package/server/shelly.ts CHANGED
@@ -3,21 +3,86 @@
3
3
  //
4
4
 
5
5
  import { System } from "../duotecno/system";
6
- import { P1Config } from "../duotecno/types";
7
- import { debug, log } from "../duotecno/logger";
6
+ import { ShellyConfig } from "../duotecno/types";
7
+ import { debug, err, log } from "../duotecno/logger";
8
8
  import { PowerBase } from "./powerbase";
9
+ import { get } from "../duotecno/api";
9
10
 
10
11
 
12
+ const HTTPstatus = {
13
+ "wifi_sta": {
14
+ "connected": true,
15
+ "ssid": "Tele Coppieters",
16
+ "ip": "192.168.0.95",
17
+ "rssi": -73
18
+ },
19
+ "cloud": {
20
+ "enabled": true,
21
+ "connected": true
22
+ },
23
+ "mqtt": {
24
+ "connected": false
25
+ },
26
+ "time": "18:17",
27
+ "unixtime": 1663863464,
28
+ "serial": 7,
29
+ "has_update": true,
30
+ "mac": "C45BBE7928B9",
31
+ "cfg_changed_cnt": 1,
32
+ "actions_stats": { "skipped": 0 },
33
+ "relays": [{ "ison": true, "has_timer": false, "timer_started": 0, "timer_duration": 0, "timer_remaining": 0, "overpower": false, "is_valid": true, "source": "http" }],
34
+ "emeters": [
35
+ { "power": 10.66, "pf": 1.00, "current": 0.08, "voltage": 232.06, "is_valid": true, "total": 5.3, "total_returned": 0.0 },
36
+ { "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.06, "is_valid": true, "total": 0.0, "total_returned": 0.0 },
37
+ { "power": 0.00, "pf": 0.00, "current": 0.01, "voltage": 232.05, "is_valid": true, "total": 0.0, "total_returned": 0.0 }
38
+ ],
39
+ "total_power": 10.66,
40
+ "fs_mounted": true,
41
+ "update": { "status": "pending", "has_update": true, "new_version": "20220830-080542/v1.12-3EM-gcf4f7c2", "old_version": "20220209-094824/v1.11.8-g8c7bb8d" },
42
+ "ram_total": 49440,
43
+ "ram_free": 30960,
44
+ "fs_size": 233681,
45
+ "fs_free": 156875,
46
+ "uptime": 1364
47
+ };
48
+
49
+ const HttpEMeter0 = {
50
+ "power":10.95,
51
+ "pf":1.00,
52
+ "current":0.08,
53
+ "voltage":231.21,
54
+ "is_valid":true,
55
+ "total":7.2,
56
+ "total_returned":0.0
57
+ };
58
+
59
+ interface Meter {
60
+ address: string;
61
+ index: number;
62
+ phase: boolean;
63
+ phaseNr: number;
64
+ power: number;
65
+ pf: number;
66
+ current: number;
67
+ voltage: number;
68
+ is_valid: boolean;
69
+ total: number;
70
+ total_returned: number;
71
+ }
11
72
 
12
73
  export class Shelly extends PowerBase {
13
- config: P1Config; // redefine
74
+ config: ShellyConfig; // redefine
14
75
  timer: NodeJS.Timer;
15
76
 
77
+ meters: Array<Meter>;
78
+ nrPhases: number;
16
79
 
17
80
  constructor(system: System) {
18
- super("p1", system);
81
+ super("shelly", system);
19
82
 
20
83
  this.timer = null;
84
+ this.meters = [];
85
+ this.nrPhases = 0;
21
86
  // init is called by super
22
87
  }
23
88
 
@@ -33,26 +98,43 @@ export class Shelly extends PowerBase {
33
98
  //
34
99
  // config mgt
35
100
  //
36
- // async updateConfig(config: any) {
37
- // // nothing special... for now
38
- // return super.updateConfig(config);
39
- // }
101
+ async updateConfig(config: any) {
102
+ this.config.addresses = config.addresses;
103
+ return super.updateConfig(config);
104
+ }
40
105
 
41
106
 
42
107
  async subscribe() {
43
- log("shelly", "connecting to Shelly: " + this.config.address);
44
-
108
+ const kInterval = 5;
109
+
45
110
  if (this.config.address) {
46
- this.timer = setInterval(() => {
47
- this.realtimeCounter++;
111
+ await this.getDeviceConfig(this.config.address, true);
112
+ }
113
+ if (this.config.addresses) {
114
+ const list = this.config.addresses.split(",");
115
+ for (let inx in list) {
116
+ const phases = (this.config.address) ? false : (inx == "0");
117
+ await this.getDeviceConfig(list[inx], phases);
118
+ }
119
+ }
120
+ debug("shelly", "meters: " + JSON.stringify(this.meters));
121
+
122
+ if (this.meters.length) {
123
+ this.timer = setInterval(async () => {
124
+ this.realtimeCounter += kInterval;
48
125
 
49
- // fetch data from API
50
- debug("shelly", "call shelly API");
126
+ // fetch data
127
+ const ok = await this.fetchData();
128
+ if (ok)
129
+ this.consume();
51
130
 
52
131
  // call process/bindings/rules
53
132
  this.applyBindings();
54
133
  this.applyRules();
55
- }, 5000);
134
+ }, kInterval * 1000);
135
+
136
+ } else {
137
+ log("shelly", "No Shelly PM devices configured");
56
138
  }
57
139
  }
58
140
 
@@ -63,4 +145,68 @@ export class Shelly extends PowerBase {
63
145
  }
64
146
  }
65
147
 
148
+ async getDeviceConfig(address: string, phases: boolean) {
149
+ try {
150
+ // debug("shelly", "fetching from " + address + "/status");
151
+ const res = await get(address, 80, "/status", undefined);
152
+ debug("shelly", "received status from " + address + " -> " + res);
153
+ const status = JSON.parse(res);
154
+
155
+ // enrich meter with its address and index + add to the global meter list
156
+ status.emeters.forEach((m, inx) => {
157
+ m.index = inx; // index with this PM device
158
+ m.phase = phases;
159
+ if (phases) {
160
+ m.phaseNr = this.nrPhases;
161
+ this.nrPhases++;
162
+ } else {
163
+ m.phaseNr = -1;
164
+ }
165
+ m.address = address;
166
+ this.meters.push(m);
167
+ });
168
+
169
+ } catch(error) {
170
+ err("shelly", error.message)
171
+ }
172
+ }
173
+
174
+ async fetchData(): Promise<boolean> {
175
+ try {
176
+ for (let meter in this.meters) {
177
+ // debug("shelly", "fetching from " + this.config.address + "/emeter/" + meter);
178
+ const res = await get(this.meters[meter].address, 80, "/emeter/"+this.meters[meter].index, undefined);
179
+ debug("shelly", "received meter: " + meter + " -> " + res);
180
+ this.meters[meter] = {... this.meters[meter], ...JSON.parse(res)};
181
+ };
182
+ return true;
183
+
184
+ } catch(error) {
185
+ err("shelly", error.message || error);
186
+ return false;
187
+ }
188
+ }
189
+
190
+ consume() {
191
+ // copy this.meters into the powerbase structures
192
+ this.meters.forEach((meter, inx) => {
193
+ this.channels[inx] = {
194
+ name: "Meter " + (inx+1), type: "CT", flow: "PRODUCTION",
195
+ power: meter.power, exportEnergy: meter.total_returned, importEnergy: meter.total, phaseId: meter.phaseNr,
196
+ current: meter.power / meter.voltage, apparentPower: 0, cosPhi: 0, formula: "", voltage: meter.voltage}
197
+ });
198
+
199
+ this.voltages = [0,0,0];
200
+ this.meters.filter(m => m.phase).forEach(m => this.voltages[m.phaseNr] = m.voltage);
201
+
202
+ this.realtime = { totalPower: this.meters.reduce((prev, curr) => curr.power + prev, 0),
203
+ totalReactivePower: 0,
204
+ totalExportEnergy: this.meters.reduce((prev, curr) => curr.total_returned + prev, 0),
205
+ totalImportEnergy: this.meters.reduce((prev, curr) => curr.total + prev, 0),
206
+ monitorStatus: 0, utcTimeStamp: new Date().getTime() };
207
+
208
+ this.production = this.realtime.totalPower;
209
+ this.consumption = this.realtime.totalReactivePower;
210
+ }
211
+
66
212
  }
package/server/smappee.js CHANGED
@@ -213,6 +213,9 @@ class Smappee extends powerbase_1.PowerBase {
213
213
  this.realtime = { totalPower: message.totalPower, totalReactivePower: message.totalReactivePower,
214
214
  totalExportEnergy: message.totalExportEnergy, totalImportEnergy: message.totalImportEnergy,
215
215
  monitorStatus: message.monitorStatus, utcTimeStamp: message.utcTimeStamp };
216
+ message.voltages.forEach(v => {
217
+ this.voltages[v.phaseId] = v.voltage;
218
+ });
216
219
  message.channelPowers.forEach(p => {
217
220
  const inx = p.publishIndex;
218
221
  if (!this.channels[inx]) {
@@ -223,14 +226,12 @@ class Smappee extends powerbase_1.PowerBase {
223
226
  this.channels[inx].exportEnergy = p.exportEnergy;
224
227
  this.channels[inx].importEnergy = p.importEnergy;
225
228
  this.channels[inx].phaseId = p.phaseId;
229
+ this.channels[inx].voltage = this.voltages[p.phaseId] || 0;
226
230
  this.channels[inx].current = p.current;
227
231
  this.channels[inx].apparentPower = p.apparentPower;
228
232
  this.channels[inx].cosPhi = p.cosPhi;
229
233
  this.channels[inx].formula = p.formula;
230
234
  });
231
- message.voltages.forEach(v => {
232
- this.voltages[v.phaseId] = v.voltage;
233
- });
234
235
  this.calcProducAndConsumption(message);
235
236
  }
236
237
  // check rules
package/server/smappee.ts CHANGED
@@ -215,6 +215,10 @@ export class Smappee extends PowerBase {
215
215
  totalExportEnergy: message.totalExportEnergy, totalImportEnergy: message.totalImportEnergy,
216
216
  monitorStatus: message.monitorStatus, utcTimeStamp: message.utcTimeStamp };
217
217
 
218
+ message.voltages.forEach(v => {
219
+ this.voltages[v.phaseId] = v.voltage;
220
+ });
221
+
218
222
  message.channelPowers.forEach(p => {
219
223
  const inx = p.publishIndex;
220
224
  if (! this.channels[inx]) {
@@ -225,14 +229,13 @@ export class Smappee extends PowerBase {
225
229
  this.channels[inx].exportEnergy = p.exportEnergy;
226
230
  this.channels[inx].importEnergy = p.importEnergy;
227
231
  this.channels[inx].phaseId = p.phaseId;
232
+ this.channels[inx].voltage = this.voltages[p.phaseId] || 0;
228
233
  this.channels[inx].current = p.current;
229
234
  this.channels[inx].apparentPower = p.apparentPower;
230
235
  this.channels[inx].cosPhi = p.cosPhi;
231
236
  this.channels[inx].formula = p.formula;
232
237
  });
233
- message.voltages.forEach(v => {
234
- this.voltages[v.phaseId] = v.voltage;
235
- });
238
+
236
239
 
237
240
  this.calcProducAndConsumption(message);
238
241
  }
@@ -30,6 +30,7 @@ const api_1 = require("../duotecno/api");
30
30
  const config_1 = require("../duotecno/config");
31
31
  const kMaster = { name: "master", type: "string", default: "0.0.0.0:5001" };
32
32
  const kAddress = { name: "address", type: "string", default: "0.0.0.0" };
33
+ const kAddresses = { name: "addresses", type: "string", default: "[0.0.0.0]" };
33
34
  const kAddressOld = { name: "addressX", type: "string", default: "0.0.0.0" };
34
35
  const kPort = { name: "port", type: "integer", default: 80 };
35
36
  const kPortOld = { name: "portX", type: "integer", default: 80 };
@@ -328,7 +329,7 @@ class SmartApp extends webapp_1.WebApp {
328
329
  power.updateRule(id, this.scrapeRule(context));
329
330
  }
330
331
  else if (context.action === "save") {
331
- power.updateConfig({ address: context.getParam(kAddress), uid: context.getParam(kUID) });
332
+ power.updateConfig({ address: context.getParam(kAddress), uid: context.getParam(kUID), addresses: context.getParam(kAddresses), });
332
333
  }
333
334
  else if (context.action === "badd") {
334
335
  const binding = power.newBinding();
@@ -818,7 +819,6 @@ class SmartApp extends webapp_1.WebApp {
818
819
  updateNodes(master, nodes, params) {
819
820
  return __awaiter(this, void 0, void 0, function* () {
820
821
  if (nodes) {
821
- // let nodeArr = nodes.split(",").map(s => parseInt(s));
822
822
  let nodeArr = nodes.map(s => parseInt(s));
823
823
  nodeArr.forEach(adr => {
824
824
  let node = this.system.findNode(master, adr);
@@ -875,7 +875,7 @@ class SmartApp extends webapp_1.WebApp {
875
875
  else { // context.action === "node"
876
876
  // reponding to /units/[master ip address:port]/[logical node address]
877
877
  const nodeLogicalAddress = parseInt(context.id);
878
- let response = yield this.getNodeInfo(master, nodeLogicalAddress);
878
+ let response = yield this.getNodeInfo(master, nodeLogicalAddress, true);
879
879
  let N = this.sortCopy(response.node, context);
880
880
  return this.ejs("nodeDetail", context, { message: response.message, node: N });
881
881
  }
@@ -908,7 +908,7 @@ class SmartApp extends webapp_1.WebApp {
908
908
  this.system.updateSystem(true);
909
909
  }
910
910
  }
911
- getNodeInfo(master, nodeLogicalAddress) {
911
+ getNodeInfo(master, nodeLogicalAddress, doFetch = false) {
912
912
  return __awaiter(this, void 0, void 0, function* () {
913
913
  let node = this.system.findNode(master, nodeLogicalAddress);
914
914
  if (!node) {
@@ -916,7 +916,7 @@ class SmartApp extends webapp_1.WebApp {
916
916
  return { node: new protocol_1.Node(this.system.masters[0], { name: "No node" }), message: "Node not found" };
917
917
  }
918
918
  else {
919
- if (node.nrUnits != node.units.length)
919
+ if ((node.nrUnits != node.units.length) || doFetch)
920
920
  yield master.fetchAllUnits(node);
921
921
  yield node.master.requestNodeStatus(node);
922
922
  return { node };