@enyo-energy/energy-app-sdk 0.0.37 → 0.0.39

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.
Files changed (47) hide show
  1. package/dist/cjs/implementations/appliances/appliance-manager.cjs +399 -0
  2. package/dist/cjs/implementations/appliances/appliance-manager.d.cts +191 -0
  3. package/dist/cjs/implementations/appliances/identifier-strategies.cjs +180 -0
  4. package/dist/cjs/implementations/appliances/identifier-strategies.d.cts +140 -0
  5. package/dist/cjs/implementations/appliances/in-memory-appliance-manager.cjs +281 -0
  6. package/dist/cjs/implementations/appliances/in-memory-appliance-manager.d.cts +119 -0
  7. package/dist/cjs/implementations/data-bus/demo-data-bus.cjs +246 -0
  8. package/dist/cjs/implementations/data-bus/demo-data-bus.d.cts +111 -0
  9. package/dist/cjs/implementations/modbus/EnergyAppModbusDataTypeConverter.d.cts +2 -2
  10. package/dist/cjs/implementations/modbus/EnergyAppModbusFaultTolerantReader.cjs +76 -0
  11. package/dist/cjs/implementations/modbus/EnergyAppModbusFaultTolerantReader.d.cts +31 -1
  12. package/dist/cjs/implementations/modbus/EnergyAppModbusRegisterMapper.d.cts +2 -2
  13. package/dist/cjs/implementations/modbus/interfaces.d.cts +7 -93
  14. package/dist/cjs/implementations/modbus/sunspec/sunspec-devices.cjs +342 -0
  15. package/dist/cjs/implementations/modbus/sunspec/sunspec-devices.d.cts +95 -0
  16. package/dist/cjs/implementations/modbus/sunspec/sunspec-modbus-client.cjs +433 -0
  17. package/dist/cjs/implementations/modbus/sunspec/sunspec-modbus-client.d.cts +171 -0
  18. package/dist/cjs/index.cjs +2 -3
  19. package/dist/cjs/index.d.cts +2 -3
  20. package/dist/cjs/types/enyo-data-bus-value.d.cts +2 -1
  21. package/dist/cjs/version.cjs +1 -1
  22. package/dist/cjs/version.d.cts +1 -1
  23. package/dist/implementations/appliances/appliance-manager.d.ts +191 -0
  24. package/dist/implementations/appliances/appliance-manager.js +395 -0
  25. package/dist/implementations/appliances/demo-appliance-manager.d.ts +118 -0
  26. package/dist/implementations/appliances/demo-appliance-manager.js +277 -0
  27. package/dist/implementations/appliances/identifier-strategies.d.ts +140 -0
  28. package/dist/implementations/appliances/identifier-strategies.js +171 -0
  29. package/dist/implementations/appliances/in-memory-appliance-manager.d.ts +119 -0
  30. package/dist/implementations/appliances/in-memory-appliance-manager.js +277 -0
  31. package/dist/implementations/data-bus/demo-data-bus.d.ts +111 -0
  32. package/dist/implementations/data-bus/demo-data-bus.js +242 -0
  33. package/dist/implementations/modbus/EnergyAppModbusDataTypeConverter.d.ts +2 -2
  34. package/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.d.ts +31 -1
  35. package/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js +76 -0
  36. package/dist/implementations/modbus/EnergyAppModbusRegisterMapper.d.ts +2 -2
  37. package/dist/implementations/modbus/interfaces.d.ts +7 -93
  38. package/dist/implementations/modbus/sunspec/sunspec-devices.d.ts +95 -0
  39. package/dist/implementations/modbus/sunspec/sunspec-devices.js +335 -0
  40. package/dist/implementations/modbus/sunspec/sunspec-modbus-client.d.ts +171 -0
  41. package/dist/implementations/modbus/sunspec/sunspec-modbus-client.js +429 -0
  42. package/dist/index.d.ts +2 -3
  43. package/dist/index.js +2 -3
  44. package/dist/types/enyo-data-bus-value.d.ts +2 -1
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/package.json +1 -1
@@ -0,0 +1,433 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SunspecModbusClient = exports.SunspecModelId = void 0;
4
+ const EnergyAppModbusConnectionHealth_js_1 = require("../EnergyAppModbusConnectionHealth.cjs");
5
+ const EnergyAppModbusFaultTolerantReader_js_1 = require("../EnergyAppModbusFaultTolerantReader.cjs");
6
+ const EnergyAppModbusRegisterMapper_js_1 = require("../EnergyAppModbusRegisterMapper.cjs");
7
+ const EnergyAppModbusDataTypeConverter_js_1 = require("../EnergyAppModbusDataTypeConverter.cjs");
8
+ // Common Sunspec Model IDs
9
+ var SunspecModelId;
10
+ (function (SunspecModelId) {
11
+ SunspecModelId[SunspecModelId["Common"] = 1] = "Common";
12
+ SunspecModelId[SunspecModelId["Inverter3Phase"] = 103] = "Inverter3Phase";
13
+ SunspecModelId[SunspecModelId["InverterSinglePhase"] = 101] = "InverterSinglePhase";
14
+ SunspecModelId[SunspecModelId["MPPT"] = 160] = "MPPT";
15
+ SunspecModelId[SunspecModelId["Battery"] = 124] = "Battery";
16
+ SunspecModelId[SunspecModelId["BatteryBase"] = 802] = "BatteryBase";
17
+ SunspecModelId[SunspecModelId["BatteryControl"] = 803] = "BatteryControl";
18
+ SunspecModelId[SunspecModelId["MeterSinglePhase"] = 201] = "MeterSinglePhase";
19
+ SunspecModelId[SunspecModelId["Meter3Phase"] = 203] = "Meter3Phase";
20
+ SunspecModelId[SunspecModelId["MeterWye"] = 204] = "MeterWye";
21
+ SunspecModelId[SunspecModelId["Nameplate"] = 120] = "Nameplate";
22
+ SunspecModelId[SunspecModelId["Settings"] = 121] = "Settings";
23
+ SunspecModelId[SunspecModelId["Status"] = 122] = "Status";
24
+ SunspecModelId[SunspecModelId["Controls"] = 123] = "Controls";
25
+ SunspecModelId[SunspecModelId["EndMarker"] = 65535] = "EndMarker";
26
+ })(SunspecModelId || (exports.SunspecModelId = SunspecModelId = {}));
27
+ class SunspecModbusClient {
28
+ energyApp;
29
+ modbusClient = null;
30
+ discoveredModels = new Map();
31
+ scaleFactors = {};
32
+ connected = false;
33
+ baseAddress = 40001;
34
+ connectionHealth;
35
+ faultTolerantReader = null;
36
+ registerMapper;
37
+ dataTypeConverter;
38
+ constructor(energyApp) {
39
+ this.energyApp = energyApp;
40
+ this.connectionHealth = new EnergyAppModbusConnectionHealth_js_1.EnergyAppModbusConnectionHealth();
41
+ this.registerMapper = new EnergyAppModbusRegisterMapper_js_1.EnergyAppModbusRegisterMapper();
42
+ this.dataTypeConverter = new EnergyAppModbusDataTypeConverter_js_1.EnergyAppModbusDataTypeConverter();
43
+ }
44
+ /**
45
+ * Connect to Modbus device
46
+ */
47
+ async connect(host, port = 502, unitId = 1) {
48
+ if (this.connected) {
49
+ await this.disconnect();
50
+ }
51
+ this.modbusClient = await this.energyApp.useModbus().connect({
52
+ host,
53
+ port,
54
+ unitId,
55
+ timeout: 5000
56
+ });
57
+ // Create fault-tolerant reader with connection health monitoring
58
+ if (this.modbusClient) {
59
+ this.faultTolerantReader = new EnergyAppModbusFaultTolerantReader_js_1.EnergyAppModbusFaultTolerantReader(this.modbusClient, this.connectionHealth);
60
+ }
61
+ this.connected = true;
62
+ this.connectionHealth.recordSuccess();
63
+ console.log(`Connected to Sunspec device at ${host}:${port} unit ${unitId}`);
64
+ }
65
+ /**
66
+ * Disconnect from Modbus device
67
+ */
68
+ async disconnect() {
69
+ if (this.modbusClient && this.connected) {
70
+ await this.modbusClient.disconnect();
71
+ this.modbusClient = null;
72
+ this.faultTolerantReader = null;
73
+ this.connected = false;
74
+ this.discoveredModels.clear();
75
+ this.scaleFactors = {};
76
+ }
77
+ }
78
+ /**
79
+ * Discover all available Sunspec models
80
+ * Scans through the address space starting at 40001
81
+ */
82
+ async discoverModels() {
83
+ if (!this.connected) {
84
+ throw new Error('Not connected to Modbus device');
85
+ }
86
+ this.discoveredModels.clear();
87
+ let currentAddress = this.baseAddress;
88
+ const maxAddress = 50000; // Safety limit
89
+ console.log('Starting Sunspec model discovery...');
90
+ try {
91
+ // First, check for Sunspec identifier "SunS" at 40001
92
+ if (!this.modbusClient) {
93
+ throw new Error('Modbus client not initialized');
94
+ }
95
+ const sunspecId = await this.modbusClient.readRegisterStringValue(40001, 2);
96
+ if (!sunspecId.includes('SunS')) {
97
+ console.warn('Device may not be Sunspec compliant - missing SunS identifier');
98
+ }
99
+ // Start scanning after the SunS identifier
100
+ currentAddress = 40003;
101
+ while (currentAddress < maxAddress) {
102
+ // Read model ID and length
103
+ if (!this.modbusClient) {
104
+ throw new Error('Modbus client not initialized');
105
+ }
106
+ const buffer = await this.modbusClient.readHoldingRegisters(currentAddress, 2);
107
+ const modelData = [buffer.readUInt16BE(0), buffer.readUInt16BE(2)];
108
+ if (!modelData || modelData.length < 2) {
109
+ console.log(`No data at address ${currentAddress}, ending discovery`);
110
+ break;
111
+ }
112
+ const modelId = modelData[0];
113
+ const modelLength = modelData[1];
114
+ // Check for end marker
115
+ if (modelId === 0xFFFF || modelId === 65535) {
116
+ console.log(`Found end marker at address ${currentAddress}`);
117
+ break;
118
+ }
119
+ // Store discovered model
120
+ const model = {
121
+ id: modelId,
122
+ address: currentAddress,
123
+ length: modelLength
124
+ };
125
+ this.discoveredModels.set(modelId, model);
126
+ console.log(`Discovered Model ${modelId} at address ${currentAddress} with length ${modelLength}`);
127
+ // Jump to next model: current address + 2 (header) + model length
128
+ currentAddress = currentAddress + 2 + modelLength;
129
+ }
130
+ }
131
+ catch (error) {
132
+ console.error(`Error during model discovery at address ${currentAddress}: ${error}`);
133
+ }
134
+ console.log(`Discovery complete. Found ${this.discoveredModels.size} models`);
135
+ return this.discoveredModels;
136
+ }
137
+ /**
138
+ * Find a specific model by ID
139
+ */
140
+ findModel(modelId) {
141
+ return this.discoveredModels.get(modelId);
142
+ }
143
+ /**
144
+ * Read a register value and apply scale factor
145
+ */
146
+ async readRegisterWithScaleFactor(valueAddress, scaleFactorAddress, quantity = 1) {
147
+ if (!this.connected) {
148
+ throw new Error('Not connected to Modbus device');
149
+ }
150
+ // Read the raw value
151
+ if (!this.modbusClient) {
152
+ throw new Error('Modbus client not initialized');
153
+ }
154
+ const buffer = await this.modbusClient.readHoldingRegisters(valueAddress, quantity);
155
+ let value = buffer.readUInt16BE(0);
156
+ // Apply scale factor if provided
157
+ if (scaleFactorAddress) {
158
+ let scaleFactor = this.scaleFactors[`sf_${scaleFactorAddress}`];
159
+ if (scaleFactor === undefined) {
160
+ if (!this.modbusClient) {
161
+ throw new Error('Modbus client not initialized');
162
+ }
163
+ const sfBuffer = await this.modbusClient.readHoldingRegisters(scaleFactorAddress, 1);
164
+ // Scale factors are signed int16
165
+ scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
166
+ this.scaleFactors[`sf_${scaleFactorAddress}`] = scaleFactor;
167
+ }
168
+ // Apply scale factor: value * 10^scaleFactor
169
+ value = value * Math.pow(10, scaleFactor);
170
+ }
171
+ return value;
172
+ }
173
+ /**
174
+ * Convert unsigned 16-bit value to signed
175
+ */
176
+ convertToSigned16(value) {
177
+ if (value > 32767) {
178
+ return value - 65536;
179
+ }
180
+ return value;
181
+ }
182
+ /**
183
+ * Helper to read register value(s) using the modbus client with error handling
184
+ */
185
+ async readRegisterValue(address, quantity = 1) {
186
+ if (!this.modbusClient) {
187
+ throw new Error('Modbus client not initialized');
188
+ }
189
+ try {
190
+ const buffer = await this.modbusClient.readHoldingRegisters(address, quantity);
191
+ this.connectionHealth.recordSuccess();
192
+ if (quantity === 1) {
193
+ return buffer.readUInt16BE(0);
194
+ }
195
+ const values = [];
196
+ for (let i = 0; i < quantity; i++) {
197
+ values.push(buffer.readUInt16BE(i * 2));
198
+ }
199
+ return values;
200
+ }
201
+ catch (error) {
202
+ this.connectionHealth.recordFailure(error);
203
+ throw error;
204
+ }
205
+ }
206
+ /**
207
+ * Read inverter data from Model 103 (Three Phase)
208
+ */
209
+ async readInverterData() {
210
+ const model = this.findModel(SunspecModelId.Inverter3Phase);
211
+ if (!model) {
212
+ console.log('Inverter model 103 not found, trying single phase model 101');
213
+ const singlePhaseModel = this.findModel(SunspecModelId.InverterSinglePhase);
214
+ if (!singlePhaseModel) {
215
+ console.error('No inverter model found');
216
+ return null;
217
+ }
218
+ return this.readSinglePhaseInverterData(singlePhaseModel);
219
+ }
220
+ const baseAddr = model.address + 2; // Skip ID and Length
221
+ try {
222
+ // Read all scale factors first (more efficient)
223
+ const scaleFactors = await this.readInverterScaleFactors(baseAddr);
224
+ // Read values and apply scale factors
225
+ const data = {
226
+ acCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 2, 1), scaleFactors.A_SF),
227
+ phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1), scaleFactors.A_SF),
228
+ phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1), scaleFactors.A_SF),
229
+ phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1), scaleFactors.A_SF),
230
+ voltageAB: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1), scaleFactors.V_SF),
231
+ voltageBC: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1), scaleFactors.V_SF),
232
+ voltageCA: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1), scaleFactors.V_SF),
233
+ acPower: this.applyScaleFactor(this.convertToSigned16(await this.readRegisterValue(baseAddr + 14, 1)), scaleFactors.W_SF),
234
+ frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1), scaleFactors.Hz_SF),
235
+ dcPower: this.applyScaleFactor(this.convertToSigned16(await this.readRegisterValue(baseAddr + 30, 1)), scaleFactors.DCW_SF),
236
+ cabinetTemperature: this.applyScaleFactor(this.convertToSigned16(await this.readRegisterValue(baseAddr + 32, 1)), scaleFactors.Tmp_SF),
237
+ operatingState: await this.readRegisterValue(baseAddr + 37, 1)
238
+ };
239
+ // Read AC Energy (32-bit accumulator)
240
+ const energyRaw = await this.readRegisterValue(baseAddr + 24, 2);
241
+ data.acEnergy = BigInt((energyRaw[0] << 16) | energyRaw[1]) *
242
+ BigInt(Math.pow(10, scaleFactors.WH_SF));
243
+ return data;
244
+ }
245
+ catch (error) {
246
+ console.error(`Error reading inverter data: ${error}`);
247
+ return null;
248
+ }
249
+ }
250
+ /**
251
+ * Read single phase inverter data (Model 101)
252
+ */
253
+ async readSinglePhaseInverterData(model) {
254
+ // Similar to 3-phase but with fewer phase-specific values
255
+ // Implementation would be similar but simplified
256
+ const baseAddr = model.address + 2;
257
+ try {
258
+ // Simplified implementation for single phase
259
+ return {
260
+ acCurrent: await this.readRegisterWithScaleFactor(baseAddr + 2, baseAddr + 6),
261
+ acPower: await this.readRegisterWithScaleFactor(baseAddr + 9, baseAddr + 10),
262
+ frequency: await this.readRegisterWithScaleFactor(baseAddr + 11, baseAddr + 12),
263
+ dcPower: await this.readRegisterWithScaleFactor(baseAddr + 20, baseAddr + 21),
264
+ operatingState: await this.readRegisterValue(baseAddr + 24, 1)
265
+ };
266
+ }
267
+ catch (error) {
268
+ console.error(`Error reading single phase inverter data: ${error}`);
269
+ return null;
270
+ }
271
+ }
272
+ /**
273
+ * Read inverter scale factors
274
+ */
275
+ async readInverterScaleFactors(baseAddr) {
276
+ return {
277
+ A_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 6, 1)),
278
+ V_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 13, 1)),
279
+ W_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 15, 1)),
280
+ Hz_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 17, 1)),
281
+ VA_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 19, 1)),
282
+ VAr_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 21, 1)),
283
+ PF_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 23, 1)),
284
+ WH_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 26, 1)),
285
+ DCA_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 28, 1)),
286
+ DCV_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 29, 1)),
287
+ DCW_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 31, 1)),
288
+ Tmp_SF: this.convertToSigned16(await this.readRegisterValue(baseAddr + 36, 1))
289
+ };
290
+ }
291
+ /**
292
+ * Apply scale factor to a value
293
+ */
294
+ applyScaleFactor(value, scaleFactor) {
295
+ return value * Math.pow(10, scaleFactor);
296
+ }
297
+ /**
298
+ * Read MPPT data from Model 160
299
+ */
300
+ async readMPPTData(stringId = 1) {
301
+ const model = this.findModel(SunspecModelId.MPPT);
302
+ if (!model) {
303
+ console.log('MPPT model 160 not found');
304
+ return null;
305
+ }
306
+ const baseAddr = model.address + 2;
307
+ try {
308
+ // MPPT modules are repeating blocks, calculate offset for specific string
309
+ const moduleSize = 20; // Typical size of each MPPT module
310
+ const offset = (stringId - 1) * moduleSize;
311
+ const moduleAddr = baseAddr + offset;
312
+ // Read scale factors
313
+ const DCA_SF = this.convertToSigned16(await this.readRegisterValue(moduleAddr + 3, 1));
314
+ const DCV_SF = this.convertToSigned16(await this.readRegisterValue(moduleAddr + 5, 1));
315
+ const DCW_SF = this.convertToSigned16(await this.readRegisterValue(moduleAddr + 7, 1));
316
+ const Tmp_SF = this.convertToSigned16(await this.readRegisterValue(moduleAddr + 11, 1));
317
+ const data = {
318
+ id: stringId,
319
+ dcCurrent: this.applyScaleFactor(await this.readRegisterValue(moduleAddr + 2, 1), DCA_SF),
320
+ dcVoltage: this.applyScaleFactor(await this.readRegisterValue(moduleAddr + 4, 1), DCV_SF),
321
+ dcPower: this.applyScaleFactor(await this.readRegisterValue(moduleAddr + 6, 1), DCW_SF),
322
+ temperature: this.applyScaleFactor(this.convertToSigned16(await this.readRegisterValue(moduleAddr + 10, 1)), Tmp_SF),
323
+ operatingState: await this.readRegisterValue(moduleAddr + 12, 1),
324
+ events: await this.readRegisterValue(moduleAddr + 13, 1)
325
+ };
326
+ // Read DC Energy (32-bit)
327
+ const energyRaw = await this.readRegisterValue(moduleAddr + 8, 2);
328
+ data.dcEnergy = BigInt((energyRaw[0] << 16) | energyRaw[1]);
329
+ return data;
330
+ }
331
+ catch (error) {
332
+ console.error(`Error reading MPPT data for string ${stringId}: ${error}`);
333
+ return null;
334
+ }
335
+ }
336
+ /**
337
+ * Read all available MPPT strings
338
+ */
339
+ async readAllMPPTData() {
340
+ const mpptData = [];
341
+ // Try to read up to 4 MPPT strings (typical maximum)
342
+ for (let i = 1; i <= 4; i++) {
343
+ const data = await this.readMPPTData(i);
344
+ if (data && data.dcCurrent !== undefined && data.dcCurrent > 0) {
345
+ mpptData.push(data);
346
+ }
347
+ }
348
+ return mpptData;
349
+ }
350
+ /**
351
+ * Read meter data (Model 203 for 3-phase)
352
+ */
353
+ async readMeterData() {
354
+ let model = this.findModel(SunspecModelId.Meter3Phase);
355
+ if (!model) {
356
+ model = this.findModel(SunspecModelId.MeterWye);
357
+ }
358
+ if (!model) {
359
+ model = this.findModel(SunspecModelId.MeterSinglePhase);
360
+ }
361
+ if (!model) {
362
+ console.log('No meter model found');
363
+ return null;
364
+ }
365
+ const baseAddr = model.address + 2;
366
+ try {
367
+ // This is a simplified implementation
368
+ // Actual register offsets depend on specific meter model
369
+ return {
370
+ totalPower: await this.readRegisterWithScaleFactor(baseAddr + 10, baseAddr + 11),
371
+ frequency: await this.readRegisterWithScaleFactor(baseAddr + 20, baseAddr + 21)
372
+ };
373
+ }
374
+ catch (error) {
375
+ console.error(`Error reading meter data: ${error}`);
376
+ return null;
377
+ }
378
+ }
379
+ /**
380
+ * Read common block data (Model 1)
381
+ */
382
+ async readCommonBlock() {
383
+ const model = this.findModel(SunspecModelId.Common);
384
+ if (!model) {
385
+ console.error('Common block model not found');
386
+ return null;
387
+ }
388
+ const baseAddr = model.address + 2;
389
+ try {
390
+ if (!this.modbusClient) {
391
+ throw new Error('Modbus client not initialized');
392
+ }
393
+ const manufacturer = await this.modbusClient.readRegisterStringValue(baseAddr, 16);
394
+ const modelName = await this.modbusClient.readRegisterStringValue(baseAddr + 16, 16);
395
+ const serialNumber = await this.modbusClient.readRegisterStringValue(baseAddr + 48, 16);
396
+ return {
397
+ manufacturer: manufacturer.replace(/\u0000/gmi, '').trim(),
398
+ model: modelName.replace(/\u0000/gmi, '').trim(),
399
+ serialNumber: serialNumber.replace(/\u0000/gmi, '').trim()
400
+ };
401
+ }
402
+ catch (error) {
403
+ console.error(`Error reading common block: ${error}`);
404
+ return null;
405
+ }
406
+ }
407
+ /**
408
+ * Get serial number from device
409
+ */
410
+ async getSerialNumber() {
411
+ const commonData = await this.readCommonBlock();
412
+ return commonData?.serialNumber;
413
+ }
414
+ /**
415
+ * Check if connected
416
+ */
417
+ isConnected() {
418
+ return this.connected;
419
+ }
420
+ /**
421
+ * Check if connection is healthy
422
+ */
423
+ isHealthy() {
424
+ return this.connected && this.connectionHealth.isHealthy();
425
+ }
426
+ /**
427
+ * Get connection health details
428
+ */
429
+ getConnectionHealth() {
430
+ return this.connectionHealth;
431
+ }
432
+ }
433
+ exports.SunspecModbusClient = SunspecModbusClient;
@@ -0,0 +1,171 @@
1
+ import type { IConnectionHealth } from "../interfaces.cjs";
2
+ import { EnergyApp } from "../../../index.cjs";
3
+ export declare enum SunspecModelId {
4
+ Common = 1,
5
+ Inverter3Phase = 103,
6
+ InverterSinglePhase = 101,
7
+ MPPT = 160,
8
+ Battery = 124,
9
+ BatteryBase = 802,
10
+ BatteryControl = 803,
11
+ MeterSinglePhase = 201,
12
+ Meter3Phase = 203,
13
+ MeterWye = 204,
14
+ Nameplate = 120,
15
+ Settings = 121,
16
+ Status = 122,
17
+ Controls = 123,
18
+ EndMarker = 65535
19
+ }
20
+ interface SunspecModel {
21
+ id: number;
22
+ address: number;
23
+ length: number;
24
+ }
25
+ export interface SunspecInverterData {
26
+ acCurrent?: number;
27
+ phaseACurrent?: number;
28
+ phaseBCurrent?: number;
29
+ phaseCCurrent?: number;
30
+ voltageAB?: number;
31
+ voltageBC?: number;
32
+ voltageCA?: number;
33
+ voltageAN?: number;
34
+ voltageBN?: number;
35
+ voltageCN?: number;
36
+ acPower?: number;
37
+ frequency?: number;
38
+ apparentPower?: number;
39
+ reactivePower?: number;
40
+ powerFactor?: number;
41
+ acEnergy?: bigint;
42
+ dcCurrent?: number;
43
+ dcVoltage?: number;
44
+ dcPower?: number;
45
+ cabinetTemperature?: number;
46
+ operatingState?: number;
47
+ events?: number;
48
+ }
49
+ export interface SunspecMPPTData {
50
+ id: number;
51
+ dcCurrent?: number;
52
+ dcVoltage?: number;
53
+ dcPower?: number;
54
+ dcEnergy?: bigint;
55
+ temperature?: number;
56
+ operatingState?: number;
57
+ events?: number;
58
+ }
59
+ export interface SunspecBatteryData {
60
+ soc?: number;
61
+ soh?: number;
62
+ chargePower?: number;
63
+ dischargePower?: number;
64
+ voltage?: number;
65
+ current?: number;
66
+ temperature?: number;
67
+ status?: number;
68
+ }
69
+ export interface SunspecMeterData {
70
+ totalPower?: number;
71
+ phaseAPower?: number;
72
+ phaseBPower?: number;
73
+ phaseCPower?: number;
74
+ totalEnergy?: bigint;
75
+ exportedEnergy?: bigint;
76
+ importedEnergy?: bigint;
77
+ voltage?: number;
78
+ current?: number;
79
+ frequency?: number;
80
+ }
81
+ export declare class SunspecModbusClient {
82
+ private energyApp;
83
+ private modbusClient;
84
+ private discoveredModels;
85
+ private scaleFactors;
86
+ private connected;
87
+ private baseAddress;
88
+ private connectionHealth;
89
+ private faultTolerantReader;
90
+ private registerMapper;
91
+ private dataTypeConverter;
92
+ constructor(energyApp: EnergyApp);
93
+ /**
94
+ * Connect to Modbus device
95
+ */
96
+ connect(host: string, port?: number, unitId?: number): Promise<void>;
97
+ /**
98
+ * Disconnect from Modbus device
99
+ */
100
+ disconnect(): Promise<void>;
101
+ /**
102
+ * Discover all available Sunspec models
103
+ * Scans through the address space starting at 40001
104
+ */
105
+ discoverModels(): Promise<Map<number, SunspecModel>>;
106
+ /**
107
+ * Find a specific model by ID
108
+ */
109
+ findModel(modelId: number): SunspecModel | undefined;
110
+ /**
111
+ * Read a register value and apply scale factor
112
+ */
113
+ readRegisterWithScaleFactor(valueAddress: number, scaleFactorAddress?: number, quantity?: number): Promise<number>;
114
+ /**
115
+ * Convert unsigned 16-bit value to signed
116
+ */
117
+ private convertToSigned16;
118
+ /**
119
+ * Helper to read register value(s) using the modbus client with error handling
120
+ */
121
+ private readRegisterValue;
122
+ /**
123
+ * Read inverter data from Model 103 (Three Phase)
124
+ */
125
+ readInverterData(): Promise<SunspecInverterData | null>;
126
+ /**
127
+ * Read single phase inverter data (Model 101)
128
+ */
129
+ private readSinglePhaseInverterData;
130
+ /**
131
+ * Read inverter scale factors
132
+ */
133
+ private readInverterScaleFactors;
134
+ /**
135
+ * Apply scale factor to a value
136
+ */
137
+ private applyScaleFactor;
138
+ /**
139
+ * Read MPPT data from Model 160
140
+ */
141
+ readMPPTData(stringId?: number): Promise<SunspecMPPTData | null>;
142
+ /**
143
+ * Read all available MPPT strings
144
+ */
145
+ readAllMPPTData(): Promise<SunspecMPPTData[]>;
146
+ /**
147
+ * Read meter data (Model 203 for 3-phase)
148
+ */
149
+ readMeterData(): Promise<SunspecMeterData | null>;
150
+ /**
151
+ * Read common block data (Model 1)
152
+ */
153
+ readCommonBlock(): Promise<any>;
154
+ /**
155
+ * Get serial number from device
156
+ */
157
+ getSerialNumber(): Promise<string | undefined>;
158
+ /**
159
+ * Check if connected
160
+ */
161
+ isConnected(): boolean;
162
+ /**
163
+ * Check if connection is healthy
164
+ */
165
+ isHealthy(): boolean;
166
+ /**
167
+ * Get connection health details
168
+ */
169
+ getConnectionHealth(): IConnectionHealth;
170
+ }
171
+ export {};
@@ -17,9 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.EnergyApp = void 0;
18
18
  const version_js_1 = require("./version.cjs");
19
19
  __exportStar(require("./energy-app-package-definition.cjs"), exports);
20
- __exportStar(require("./implementations/modbus/EnergyAppModbusBattery.cjs"), exports);
21
- __exportStar(require("./implementations/modbus/EnergyAppModbusMeter.cjs"), exports);
22
- __exportStar(require("./implementations/modbus/EnergyAppModbusInverter.cjs"), exports);
23
20
  __exportStar(require("./version.cjs"), exports);
24
21
  __exportStar(require("./implementations/ocpp/ocpp16.cjs"), exports);
25
22
  __exportStar(require("./implementations/ocpp/ocpp201.cjs"), exports);
@@ -29,6 +26,8 @@ __exportStar(require("./types/enyo-settings.cjs"), exports);
29
26
  __exportStar(require("./types/enyo-energy-tariff.cjs"), exports);
30
27
  __exportStar(require("./types/enyo-electricity-prices.cjs"), exports);
31
28
  __exportStar(require("./types/enyo-notification.cjs"), exports);
29
+ __exportStar(require("./implementations/appliances/appliance-manager.cjs"), exports);
30
+ __exportStar(require("./implementations/appliances/identifier-strategies.cjs"), exports);
32
31
  class EnergyApp {
33
32
  energyAppSdk;
34
33
  constructor() {
@@ -14,9 +14,6 @@ import { EnergyAppSettings } from "./packages/energy-app-settings.cjs";
14
14
  import { EnergyAppElectricityPrices } from "./packages/energy-app-electricity-prices.cjs";
15
15
  import { EnergyAppNotification } from "./packages/energy-app-notification.cjs";
16
16
  export * from './energy-app-package-definition.cjs';
17
- export * from './implementations/modbus/EnergyAppModbusBattery.cjs';
18
- export * from './implementations/modbus/EnergyAppModbusMeter.cjs';
19
- export * from './implementations/modbus/EnergyAppModbusInverter.cjs';
20
17
  export * from './version.cjs';
21
18
  export * from './implementations/ocpp/ocpp16.cjs';
22
19
  export * from './implementations/ocpp/ocpp201.cjs';
@@ -26,6 +23,8 @@ export * from './types/enyo-settings.cjs';
26
23
  export * from './types/enyo-energy-tariff.cjs';
27
24
  export * from './types/enyo-electricity-prices.cjs';
28
25
  export * from './types/enyo-notification.cjs';
26
+ export * from './implementations/appliances/appliance-manager.cjs';
27
+ export * from './implementations/appliances/identifier-strategies.cjs';
29
28
  export declare class EnergyApp implements EnyoEnergyAppSdk {
30
29
  private readonly energyAppSdk;
31
30
  constructor();
@@ -109,6 +109,7 @@ export declare enum EnyoDataBusMessageEnum {
109
109
  AggregatedStateUpdateV1 = "AggregatedStateUpdateV1",
110
110
  EnergyTariffUpdateV1 = "EnergyTariffUpdateV1"
111
111
  }
112
+ export type EnyoDataBusMessageResolution = '10s' | '30s' | '1m' | '15m' | '1h' | '1d' | 'dynamic';
112
113
  export interface EnyoDataBusMessage {
113
114
  id: string;
114
115
  message: EnyoDataBusMessageEnum;
@@ -118,7 +119,7 @@ export interface EnyoDataBusMessage {
118
119
  clockId?: string;
119
120
  timestampIso: string;
120
121
  /** If you just forward events that occur, use dynamic as resolution */
121
- resolution?: '10s' | '30s' | '1m' | '15m' | '1h' | '1d' | 'dynamic';
122
+ resolution?: EnyoDataBusMessageResolution;
122
123
  data: object;
123
124
  }
124
125
  export interface EnyoDataBusMessageAnswer extends EnyoDataBusMessage {
@@ -9,7 +9,7 @@ exports.getSdkVersion = getSdkVersion;
9
9
  /**
10
10
  * Current version of the enyo Energy App SDK.
11
11
  */
12
- exports.SDK_VERSION = '0.0.37';
12
+ exports.SDK_VERSION = '0.0.39';
13
13
  /**
14
14
  * Gets the current SDK version.
15
15
  * @returns The semantic version string of the SDK
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export declare const SDK_VERSION = "0.0.37";
8
+ export declare const SDK_VERSION = "0.0.39";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK