@enyo-energy/sunspec-sdk 0.0.9 → 0.0.10

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.
@@ -1,6 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SunspecModbusClient = void 0;
4
+ /**
5
+ * Sunspec Modbus Client Implementation
6
+ *
7
+ * This module implements the Sunspec protocol for reading data from solar inverters,
8
+ * meters, and other energy devices over Modbus TCP/RTU.
9
+ *
10
+ * Sunspec NOT_IMPLEMENTED values reference:
11
+ * - int16: 0x8000 (-32768)
12
+ * - uint16: 0xFFFF (65535)
13
+ * - int32: 0x80000000 (-2147483648)
14
+ * - uint32: 0xFFFFFFFF (4294967295)
15
+ * - acc16: 0x0000 (NOT_ACCUMULATED, valid but zero)
16
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, valid but zero)
17
+ * - enum16/bitfield16: 0xFFFF
18
+ * - enum32/bitfield32: 0xFFFFFFFF
19
+ * - pad: 0x8000 (always returns this value)
20
+ * - string: all registers 0x0000 (NULL)
21
+ */
4
22
  const sunspec_interfaces_js_1 = require("./sunspec-interfaces.cjs");
5
23
  const EnergyAppModbusConnectionHealth_js_1 = require("@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusConnectionHealth.js");
6
24
  const EnergyAppModbusFaultTolerantReader_js_1 = require("@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js");
@@ -151,58 +169,65 @@ class SunspecModbusClient {
151
169
  return this.discoveredModels.get(modelId);
152
170
  }
153
171
  /**
154
- * Read a register value and apply scale factor
155
- */
156
- async readRegisterWithScaleFactor(valueAddress, scaleFactorAddress, quantity = 1) {
157
- if (!this.connected) {
158
- throw new Error('Not connected to Modbus device');
159
- }
160
- // Read the raw value
161
- if (!this.modbusClient) {
162
- throw new Error('Modbus client not initialized');
163
- }
164
- const buffer = await this.modbusClient.readHoldingRegisters(valueAddress, quantity);
165
- let value = buffer.readUInt16BE(0);
166
- // Apply scale factor if provided
167
- if (scaleFactorAddress) {
168
- let scaleFactor = this.scaleFactors[`sf_${scaleFactorAddress}`];
169
- if (scaleFactor === undefined) {
170
- if (!this.modbusClient) {
171
- throw new Error('Modbus client not initialized');
172
- }
173
- const sfBuffer = await this.modbusClient.readHoldingRegisters(scaleFactorAddress, 1);
174
- // Scale factors are signed int16
175
- scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
176
- this.scaleFactors[`sf_${scaleFactorAddress}`] = scaleFactor;
177
- }
178
- // Apply scale factor: value * 10^scaleFactor
179
- value = value * Math.pow(10, scaleFactor);
180
- }
181
- return value;
182
- }
183
- /**
184
- * Convert unsigned 16-bit value to signed
185
- */
186
- convertToSigned16(value) {
187
- if (value > 32767) {
188
- return value - 65536;
189
- }
190
- return value;
191
- }
192
- /**
193
- * Check if a value is "unimplemented" according to Sunspec
172
+ * Check if a value is "unimplemented" according to Sunspec specification
194
173
  * Returns true if the value represents an unimplemented/not applicable register
174
+ *
175
+ * Sunspec NOT_IMPLEMENTED values:
176
+ * - int16: 0x8000
177
+ * - uint16: 0xFFFF
178
+ * - int32: 0x80000000
179
+ * - uint32: 0xFFFFFFFF
180
+ * - int64: 0x8000000000000000
181
+ * - uint64: 0xFFFFFFFFFFFFFFFF
182
+ * - acc16: 0x0000 (NOT_ACCUMULATED, not truly unimplemented)
183
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, not truly unimplemented)
184
+ * - acc64: 0x0000000000000000 (NOT_ACCUMULATED, not truly unimplemented)
185
+ * - enum16: 0xFFFF
186
+ * - enum32: 0xFFFFFFFF
187
+ * - bitfield16: 0xFFFF
188
+ * - bitfield32: 0xFFFFFFFF
189
+ * - pad: 0x8000 (always returns this value)
190
+ * - ipaddr: 0x00000000 (NOT_CONFIGURED)
191
+ * - string: all registers 0x0000 (NULL)
195
192
  */
196
193
  isUnimplementedValue(value, dataType = 'uint16') {
197
194
  switch (dataType) {
198
195
  case 'uint16':
199
- return value === 0xFFFF || value === 65535;
196
+ case 'enum16':
197
+ case 'bitfield16':
198
+ return value === 0xFFFF;
200
199
  case 'int16':
201
- return value === 0x7FFF || value === 32767;
200
+ case 'pad':
201
+ return value === 0x8000;
202
202
  case 'uint32':
203
+ case 'enum32':
204
+ case 'bitfield32':
203
205
  return value === 0xFFFFFFFF;
204
206
  case 'int32':
205
- return value === 0x7FFFFFFF;
207
+ return value === 0x80000000;
208
+ case 'uint64':
209
+ return value === 0xffffffffffffffffn;
210
+ case 'int64':
211
+ return value === 0x8000000000000000n;
212
+ case 'acc16':
213
+ // 0x0000 means NOT_ACCUMULATED (value is valid but zero)
214
+ // For accumulators, we typically don't treat 0 as unimplemented
215
+ return false;
216
+ case 'acc32':
217
+ // 0x00000000 means NOT_ACCUMULATED (value is valid but zero)
218
+ // For accumulators, we typically don't treat 0 as unimplemented
219
+ return false;
220
+ case 'acc64':
221
+ // 0x0000000000000000 means NOT_ACCUMULATED (value is valid but zero)
222
+ // For accumulators, we typically don't treat 0 as unimplemented
223
+ return false;
224
+ case 'ipaddr':
225
+ // 0x00000000 means NOT_CONFIGURED
226
+ return value === 0x00000000;
227
+ case 'string':
228
+ // For strings, all 0x0000 means unimplemented
229
+ // This would need special handling in the string reading logic
230
+ return value === 0;
206
231
  default:
207
232
  return false;
208
233
  }
@@ -242,24 +267,15 @@ class SunspecModbusClient {
242
267
  }
243
268
  return this.cleanString(str);
244
269
  case 'int16':
245
- return this.convertToSigned16(buffer.readUInt16BE(0));
270
+ return buffer.readInt16BE(0);
246
271
  case 'uint32':
247
272
  case 'acc32':
248
- // 32-bit values use 2 registers
249
- return (buffer.readUInt16BE(0) << 16) | buffer.readUInt16BE(2);
273
+ return buffer.readUint32BE(0);
250
274
  case 'int32':
251
- const val = (buffer.readUInt16BE(0) << 16) | buffer.readUInt16BE(2);
252
- return val > 0x7FFFFFFF ? val - 0x100000000 : val;
275
+ return buffer.readInt32BE(0);
253
276
  case 'uint16':
254
277
  default:
255
- if (quantity === 1) {
256
- return buffer.readUInt16BE(0);
257
- }
258
- const values = [];
259
- for (let i = 0; i < quantity; i++) {
260
- values.push(buffer.readUInt16BE(i * 2));
261
- }
262
- return values;
278
+ return buffer.readUInt16BE(0);
263
279
  }
264
280
  }
265
281
  catch (error) {
@@ -308,54 +324,54 @@ class SunspecModbusClient {
308
324
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
309
325
  console.log(`AC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
310
326
  return raw;
311
- })(), scaleFactors.A_SF),
312
- phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF),
313
- phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF),
314
- phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF),
327
+ })(), scaleFactors.A_SF, 'uint16', 'AC Current'),
328
+ phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase A Current'),
329
+ phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase B Current'),
330
+ phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase C Current'),
315
331
  // Voltage values - Offsets 7-12
316
- voltageAB: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.V_SF),
317
- voltageBC: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'uint16'), scaleFactors.V_SF),
318
- voltageCA: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'uint16'), scaleFactors.V_SF),
332
+ voltageAB: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage AB'),
333
+ voltageBC: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage BC'),
334
+ voltageCA: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage CA'),
319
335
  // Apply scale factor with unimplemented value checking
320
- voltageAN: this.applyScaleFactor(voltageANRaw, scaleFactors.V_SF),
321
- voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF),
322
- voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF),
336
+ voltageAN: this.applyScaleFactor(voltageANRaw, scaleFactors.V_SF, 'uint16', 'Voltage AN'),
337
+ voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF, 'uint16', 'Voltage BN'),
338
+ voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF, 'uint16', 'Voltage CN'),
323
339
  // Power values - Offsets 14, 18, 20, 22
324
340
  acPower: this.applyScaleFactor(await (async () => {
325
341
  const addr = baseAddr + 14;
326
342
  const raw = await this.readRegisterValue(addr, 1, 'int16');
327
343
  console.log(`AC Power (W): address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.W_SF}`);
328
344
  return raw;
329
- })(), scaleFactors.W_SF, 'int16'),
330
- apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF),
331
- reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF),
332
- powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF),
345
+ })(), scaleFactors.W_SF, 'int16', 'AC Power'),
346
+ apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF, 'uint16', 'Apparent Power'),
347
+ reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF, 'int16', 'Reactive Power'),
348
+ powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF, 'int16', 'Power Factor'),
333
349
  // Frequency - Offset 16
334
- frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF),
350
+ frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF, 'uint16', 'Frequency'),
335
351
  // DC values - Offsets 27, 28, 30
336
352
  dcCurrent: this.applyScaleFactor(await (async () => {
337
353
  const addr = baseAddr + 27;
338
354
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
339
355
  console.log(`DC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
340
356
  return raw;
341
- })(), scaleFactors.DCA_SF),
357
+ })(), scaleFactors.DCA_SF, 'uint16', 'DC Current'),
342
358
  dcVoltage: this.applyScaleFactor(await (async () => {
343
359
  const addr = baseAddr + 28;
344
360
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
345
361
  console.log(`DC Voltage: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
346
362
  return raw;
347
- })(), scaleFactors.DCV_SF),
363
+ })(), scaleFactors.DCV_SF, 'uint16', 'DC Voltage'),
348
364
  dcPower: this.applyScaleFactor(await (async () => {
349
365
  const addr = baseAddr + 30;
350
366
  const raw = await this.readRegisterValue(addr, 1, 'int16');
351
367
  console.log(`DC Power: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.DCW_SF}`);
352
368
  return raw;
353
- })(), scaleFactors.DCW_SF, 'int16'),
369
+ })(), scaleFactors.DCW_SF, 'int16', 'DC Power'),
354
370
  // Temperature values - Offsets 32, 34, 35, 36
355
- cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF),
356
- heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF),
357
- transformerTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 35, 1, 'int16'), scaleFactors.Tmp_SF),
358
- otherTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 36, 1, 'int16'), scaleFactors.Tmp_SF),
371
+ cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Cabinet Temperature'),
372
+ heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Heat Sink Temperature'),
373
+ transformerTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 35, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Transformer Temperature'),
374
+ otherTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 36, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Other Temperature'),
359
375
  // Status values - Offsets 38, 39
360
376
  operatingState: await this.readRegisterValue(baseAddr + 38, 1, 'uint16'),
361
377
  vendorState: await this.readRegisterValue(baseAddr + 39, 1, 'uint16'),
@@ -371,7 +387,7 @@ class SunspecModbusClient {
371
387
  const acEnergyAddr = baseAddr + 24;
372
388
  const acEnergy = await this.readRegisterValue(acEnergyAddr, 2, 'acc32');
373
389
  console.log(`AC Energy: address=${acEnergyAddr}, raw=0x${acEnergy.toString(16).toUpperCase()} (${acEnergy}), SF=${scaleFactors.WH_SF}`);
374
- data.acEnergy = !this.isUnimplementedValue(acEnergy, 'uint32')
390
+ data.acEnergy = !this.isUnimplementedValue(acEnergy, 'acc32')
375
391
  ? acEnergy * Math.pow(10, scaleFactors.WH_SF) // Regular number with scale factor
376
392
  : undefined;
377
393
  // Log final calculated values
@@ -436,13 +452,13 @@ class SunspecModbusClient {
436
452
  console.log(`Operating State: address=${stateAddr}, raw=0x${stateRaw.toString(16).toUpperCase()} (${stateRaw})`);
437
453
  return {
438
454
  blockNumber: 101,
439
- voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF),
440
- acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF),
441
- acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16'),
442
- frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF),
443
- dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
444
- dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
445
- dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16'),
455
+ voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF, 'uint16', 'Single Phase Voltage'),
456
+ acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF, 'uint16', 'Single Phase AC Current'),
457
+ acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16', 'Single Phase AC Power'),
458
+ frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF, 'uint16', 'Single Phase Frequency'),
459
+ dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', 'Single Phase DC Current'),
460
+ dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', 'Single Phase DC Voltage'),
461
+ dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16', 'Single Phase DC Power'),
446
462
  operatingState: stateRaw
447
463
  };
448
464
  }
@@ -476,12 +492,16 @@ class SunspecModbusClient {
476
492
  * Apply scale factor to a value
477
493
  * Returns undefined if the value is unimplemented or scale factor is out of range
478
494
  */
479
- applyScaleFactor(value, scaleFactor, dataType = 'uint16') {
495
+ applyScaleFactor(value, scaleFactor, dataType = 'uint16', fieldName) {
480
496
  // Check for unimplemented values
481
497
  if (this.isUnimplementedValue(value, dataType)) {
482
498
  return undefined;
483
499
  }
484
- return value * Math.pow(10, scaleFactor);
500
+ const scaledValue = value * Math.pow(10, scaleFactor);
501
+ // Log the raw and scaled values in decimal format
502
+ const fieldPrefix = fieldName ? `${fieldName}: ` : '';
503
+ console.log(`Scale Factor Applied - ${fieldPrefix}raw=${value} (decimal), SF=${scaleFactor}, scaled=${scaledValue}`);
504
+ return scaledValue;
485
505
  }
486
506
  /**
487
507
  * Read MPPT data from Model 160
@@ -536,24 +556,24 @@ class SunspecModbusClient {
536
556
  // String ID - Offset 1 (8 registers for string)
537
557
  stringId: await this.readRegisterValue(moduleAddr + 1, 8, 'string'),
538
558
  // DC Current - Offset 9
539
- dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
559
+ dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', `MPPT ${moduleId} DC Current`),
540
560
  dcCurrentSF: scaleFactors.DCA_SF,
541
561
  // DC Voltage - Offset 11
542
- dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
562
+ dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', `MPPT ${moduleId} DC Voltage`),
543
563
  dcVoltageSF: scaleFactors.DCV_SF,
544
564
  // DC Power - Offset 13
545
- dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF),
565
+ dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'uint16', `MPPT ${moduleId} DC Power`),
546
566
  dcPowerSF: scaleFactors.DCW_SF,
547
567
  // DC Energy - Offset 15-16 (32-bit accumulator)
548
568
  // Only calculate if value is not unimplemented
549
- dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'uint32')
569
+ dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'acc32')
550
570
  ? dcEnergyRaw * Math.pow(10, scaleFactors.DCWH_SF) // Regular number with scale factor
551
571
  : undefined,
552
572
  dcEnergySF: scaleFactors.DCWH_SF,
553
573
  // Timestamp - Offset 18-19 (32-bit)
554
574
  timestamp: await this.readRegisterValue(moduleAddr + 18, 2, 'uint32'),
555
575
  // Temperature - Offset 20
556
- temperature: this.applyScaleFactor(temperatureRaw, scaleFactors.Tmp_SF, 'int16'),
576
+ temperature: this.applyScaleFactor(temperatureRaw, scaleFactors.Tmp_SF, 'int16', `MPPT ${moduleId} Temperature`),
557
577
  temperatureSF: scaleFactors.Tmp_SF,
558
578
  // Operating State - Offset 22
559
579
  operatingState: await this.readRegisterValue(moduleAddr + 22, 1, 'uint16'),
@@ -681,12 +701,12 @@ class SunspecModbusClient {
681
701
  const importRaw = await this.readRegisterValue(importAddr, 2, 'acc32');
682
702
  console.log(`Meter Import Energy: address=${importAddr}, raw=0x${importRaw.toString(16).toUpperCase()} (${importRaw}), SF=${energySF}`);
683
703
  // Calculate final values with scale factors
684
- const totalPower = this.applyScaleFactor(powerRaw, powerSF, 'int16');
685
- const frequency = this.applyScaleFactor(freqRaw, freqSF);
686
- const exportedEnergy = !this.isUnimplementedValue(exportRaw, 'uint32')
704
+ const totalPower = this.applyScaleFactor(powerRaw, powerSF, 'int16', 'Meter Total Power');
705
+ const frequency = this.applyScaleFactor(freqRaw, freqSF, 'uint16', 'Meter Frequency');
706
+ const exportedEnergy = !this.isUnimplementedValue(exportRaw, 'acc32')
687
707
  ? exportRaw * Math.pow(10, energySF) // Regular number, not BigInt
688
708
  : undefined;
689
- const importedEnergy = !this.isUnimplementedValue(importRaw, 'uint32')
709
+ const importedEnergy = !this.isUnimplementedValue(importRaw, 'acc32')
690
710
  ? importRaw * Math.pow(10, energySF) // Regular number, not BigInt
691
711
  : undefined;
692
712
  console.log('Meter Final Values:', {
@@ -812,40 +832,40 @@ class SunspecModbusClient {
812
832
  blockAddress: model.address,
813
833
  blockLength: model.length,
814
834
  // Power settings - Offset 2
815
- WMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 2, 1, 'uint16'), scaleFactors.WMax_SF),
835
+ WMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 2, 1, 'uint16'), scaleFactors.WMax_SF, 'uint16', 'Max Power'),
816
836
  WMax_SF: scaleFactors.WMax_SF,
817
837
  // Voltage settings - Offsets 3-6
818
- VRef: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.VRef_SF),
838
+ VRef: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.VRef_SF, 'uint16', 'Voltage Reference'),
819
839
  VRef_SF: scaleFactors.VRef_SF,
820
- VRefOfs: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'int16'), scaleFactors.VRefOfs_SF),
840
+ VRefOfs: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'int16'), scaleFactors.VRefOfs_SF, 'int16', 'Voltage Reference Offset'),
821
841
  VRefOfs_SF: scaleFactors.VRefOfs_SF,
822
- VMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.VMinMax_SF),
823
- VMin: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 6, 1, 'uint16'), scaleFactors.VMinMax_SF),
842
+ VMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Max Voltage'),
843
+ VMin: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 6, 1, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Min Voltage'),
824
844
  VMinMax_SF: scaleFactors.VMinMax_SF,
825
845
  // Apparent power settings - Offset 7
826
- VAMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.VAMax_SF),
846
+ VAMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.VAMax_SF, 'uint16', 'Max Apparent Power'),
827
847
  VAMax_SF: scaleFactors.VAMax_SF,
828
848
  // Reactive power settings - Offsets 8-11
829
- VArMaxQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.VArMax_SF),
830
- VArMaxQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'int16'), scaleFactors.VArMax_SF),
831
- VArMaxQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 10, 1, 'int16'), scaleFactors.VArMax_SF),
832
- VArMaxQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 11, 1, 'int16'), scaleFactors.VArMax_SF),
849
+ VArMaxQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q1'),
850
+ VArMaxQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q2'),
851
+ VArMaxQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 10, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q3'),
852
+ VArMaxQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 11, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q4'),
833
853
  VArMax_SF: scaleFactors.VArMax_SF,
834
854
  // Ramp rate settings - Offset 12
835
- WGra: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 12, 1, 'uint16'), scaleFactors.WGra_SF),
855
+ WGra: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 12, 1, 'uint16'), scaleFactors.WGra_SF, 'uint16', 'Power Ramp Rate'),
836
856
  WGra_SF: scaleFactors.WGra_SF,
837
857
  // Power factor settings - Offsets 13-16
838
- PFMinQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.PFMin_SF),
839
- PFMinQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.PFMin_SF),
840
- PFMinQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.PFMin_SF),
841
- PFMinQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'int16'), scaleFactors.PFMin_SF),
858
+ PFMinQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q1'),
859
+ PFMinQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q2'),
860
+ PFMinQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q3'),
861
+ PFMinQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q4'),
842
862
  PFMin_SF: scaleFactors.PFMin_SF,
843
863
  // Other settings - Offsets 17-21
844
864
  VArAct: await this.readRegisterValue(baseAddr + 17, 1, 'uint16'),
845
865
  ClcTotVA: await this.readRegisterValue(baseAddr + 18, 1, 'uint16'),
846
- MaxRmpRte: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 19, 1, 'uint16'), scaleFactors.MaxRmpRte_SF),
866
+ MaxRmpRte: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 19, 1, 'uint16'), scaleFactors.MaxRmpRte_SF, 'uint16', 'Max Ramp Rate'),
847
867
  MaxRmpRte_SF: scaleFactors.MaxRmpRte_SF,
848
- ECPNomHz: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'uint16'), scaleFactors.ECPNomHz_SF),
868
+ ECPNomHz: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'uint16'), scaleFactors.ECPNomHz_SF, 'uint16', 'Nominal Frequency'),
849
869
  ECPNomHz_SF: scaleFactors.ECPNomHz_SF,
850
870
  ConnPh: await this.readRegisterValue(baseAddr + 21, 1, 'uint16')
851
871
  };
@@ -882,23 +902,23 @@ class SunspecModbusClient {
882
902
  Conn_RvrtTms: await this.readRegisterValue(baseAddr + 1, 1, 'uint16'),
883
903
  Conn: await this.readRegisterValue(baseAddr + 2, 1, 'uint16'),
884
904
  // Power limit control - Offsets 3-7
885
- WMaxLimPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.WMaxLimPct_SF),
905
+ WMaxLimPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.WMaxLimPct_SF, 'uint16', 'Power Limit Percentage'),
886
906
  WMaxLimPct_SF: scaleFactors.WMaxLimPct_SF,
887
907
  WMaxLimPct_WinTms: await this.readRegisterValue(baseAddr + 4, 1, 'uint16'),
888
908
  WMaxLimPct_RvrtTms: await this.readRegisterValue(baseAddr + 5, 1, 'uint16'),
889
909
  WMaxLimPct_RmpTms: await this.readRegisterValue(baseAddr + 6, 1, 'uint16'),
890
910
  WMaxLim_Ena: await this.readRegisterValue(baseAddr + 7, 1, 'uint16'),
891
911
  // Power factor control - Offsets 8-12
892
- OutPFSet: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.OutPFSet_SF),
912
+ OutPFSet: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.OutPFSet_SF, 'int16', 'Output Power Factor Set'),
893
913
  OutPFSet_SF: scaleFactors.OutPFSet_SF,
894
914
  OutPFSet_WinTms: await this.readRegisterValue(baseAddr + 9, 1, 'uint16'),
895
915
  OutPFSet_RvrtTms: await this.readRegisterValue(baseAddr + 10, 1, 'uint16'),
896
916
  OutPFSet_RmpTms: await this.readRegisterValue(baseAddr + 11, 1, 'uint16'),
897
917
  OutPFSet_Ena: await this.readRegisterValue(baseAddr + 12, 1, 'uint16'),
898
918
  // Reactive power control - Offsets 13-20
899
- VArWMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.VArPct_SF),
900
- VArMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.VArPct_SF),
901
- VArAvalPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.VArPct_SF),
919
+ VArWMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Reactive Power at Max Power %'),
920
+ VArMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Max Reactive Power %'),
921
+ VArAvalPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Available Reactive Power %'),
902
922
  VArPct_SF: scaleFactors.VArPct_SF,
903
923
  VArPct_WinTms: await this.readRegisterValue(baseAddr + 16, 1, 'uint16'),
904
924
  VArPct_RvrtTms: await this.readRegisterValue(baseAddr + 17, 1, 'uint16'),
@@ -929,7 +949,7 @@ class SunspecModbusClient {
929
949
  if (settings.WMax !== undefined && this.modbusClient) {
930
950
  // Need to read scale factor first if not provided
931
951
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 22, 1);
932
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
952
+ const scaleFactor = sfBuffer.readInt16BE(0);
933
953
  const scaledValue = Math.round(settings.WMax / Math.pow(10, scaleFactor));
934
954
  // Writing registers needs to be implemented in EnergyAppModbusInstance
935
955
  // For now, log the write operation
@@ -937,7 +957,7 @@ class SunspecModbusClient {
937
957
  }
938
958
  if (settings.VRef !== undefined && this.modbusClient) {
939
959
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 23, 1);
940
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
960
+ const scaleFactor = sfBuffer.readInt16BE(0);
941
961
  const scaledValue = Math.round(settings.VRef / Math.pow(10, scaleFactor));
942
962
  console.log(`Would write value ${scaledValue} to register ${baseAddr + 1}`);
943
963
  }
@@ -969,7 +989,7 @@ class SunspecModbusClient {
969
989
  // Power limit control
970
990
  if (controls.WMaxLimPct !== undefined && this.modbusClient) {
971
991
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 21, 1);
972
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
992
+ const scaleFactor = sfBuffer.readInt16BE(0);
973
993
  const scaledValue = Math.round(controls.WMaxLimPct / Math.pow(10, scaleFactor));
974
994
  console.log(`Would write power limit ${scaledValue} to register ${baseAddr + 3}`);
975
995
  }
@@ -979,7 +999,7 @@ class SunspecModbusClient {
979
999
  // Power factor control
980
1000
  if (controls.OutPFSet !== undefined && this.modbusClient) {
981
1001
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 22, 1);
982
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
1002
+ const scaleFactor = sfBuffer.readInt16BE(0);
983
1003
  const scaledValue = Math.round(controls.OutPFSet / Math.pow(10, scaleFactor));
984
1004
  console.log(`Would write power factor ${scaledValue} to register ${baseAddr + 8}`);
985
1005
  }
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Sunspec Modbus Client Implementation
3
+ *
4
+ * This module implements the Sunspec protocol for reading data from solar inverters,
5
+ * meters, and other energy devices over Modbus TCP/RTU.
6
+ *
7
+ * Sunspec NOT_IMPLEMENTED values reference:
8
+ * - int16: 0x8000 (-32768)
9
+ * - uint16: 0xFFFF (65535)
10
+ * - int32: 0x80000000 (-2147483648)
11
+ * - uint32: 0xFFFFFFFF (4294967295)
12
+ * - acc16: 0x0000 (NOT_ACCUMULATED, valid but zero)
13
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, valid but zero)
14
+ * - enum16/bitfield16: 0xFFFF
15
+ * - enum32/bitfield32: 0xFFFFFFFF
16
+ * - pad: 0x8000 (always returns this value)
17
+ * - string: all registers 0x0000 (NULL)
18
+ */
1
19
  import { type SunspecInverterControls, type SunspecInverterData, type SunspecInverterSettings, type SunspecMeterData, type SunspecModel, type SunspecMPPTData } from "./sunspec-interfaces.cjs";
2
20
  import { IConnectionHealth } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/interfaces.js";
3
21
  import { EnergyApp } from "@enyo-energy/energy-app-sdk";
@@ -37,16 +55,26 @@ export declare class SunspecModbusClient {
37
55
  */
38
56
  findModel(modelId: number): SunspecModel | undefined;
39
57
  /**
40
- * Read a register value and apply scale factor
41
- */
42
- readRegisterWithScaleFactor(valueAddress: number, scaleFactorAddress?: number, quantity?: number): Promise<number>;
43
- /**
44
- * Convert unsigned 16-bit value to signed
45
- */
46
- private convertToSigned16;
47
- /**
48
- * Check if a value is "unimplemented" according to Sunspec
58
+ * Check if a value is "unimplemented" according to Sunspec specification
49
59
  * Returns true if the value represents an unimplemented/not applicable register
60
+ *
61
+ * Sunspec NOT_IMPLEMENTED values:
62
+ * - int16: 0x8000
63
+ * - uint16: 0xFFFF
64
+ * - int32: 0x80000000
65
+ * - uint32: 0xFFFFFFFF
66
+ * - int64: 0x8000000000000000
67
+ * - uint64: 0xFFFFFFFFFFFFFFFF
68
+ * - acc16: 0x0000 (NOT_ACCUMULATED, not truly unimplemented)
69
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, not truly unimplemented)
70
+ * - acc64: 0x0000000000000000 (NOT_ACCUMULATED, not truly unimplemented)
71
+ * - enum16: 0xFFFF
72
+ * - enum32: 0xFFFFFFFF
73
+ * - bitfield16: 0xFFFF
74
+ * - bitfield32: 0xFFFFFFFF
75
+ * - pad: 0x8000 (always returns this value)
76
+ * - ipaddr: 0x00000000 (NOT_CONFIGURED)
77
+ * - string: all registers 0x0000 (NULL)
50
78
  */
51
79
  private isUnimplementedValue;
52
80
  /**
@@ -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.9';
12
+ exports.SDK_VERSION = '0.0.10';
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.9";
8
+ export declare const SDK_VERSION = "0.0.10";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Sunspec Modbus Client Implementation
3
+ *
4
+ * This module implements the Sunspec protocol for reading data from solar inverters,
5
+ * meters, and other energy devices over Modbus TCP/RTU.
6
+ *
7
+ * Sunspec NOT_IMPLEMENTED values reference:
8
+ * - int16: 0x8000 (-32768)
9
+ * - uint16: 0xFFFF (65535)
10
+ * - int32: 0x80000000 (-2147483648)
11
+ * - uint32: 0xFFFFFFFF (4294967295)
12
+ * - acc16: 0x0000 (NOT_ACCUMULATED, valid but zero)
13
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, valid but zero)
14
+ * - enum16/bitfield16: 0xFFFF
15
+ * - enum32/bitfield32: 0xFFFFFFFF
16
+ * - pad: 0x8000 (always returns this value)
17
+ * - string: all registers 0x0000 (NULL)
18
+ */
1
19
  import { type SunspecInverterControls, type SunspecInverterData, type SunspecInverterSettings, type SunspecMeterData, type SunspecModel, type SunspecMPPTData } from "./sunspec-interfaces.js";
2
20
  import { IConnectionHealth } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/interfaces.js";
3
21
  import { EnergyApp } from "@enyo-energy/energy-app-sdk";
@@ -37,16 +55,26 @@ export declare class SunspecModbusClient {
37
55
  */
38
56
  findModel(modelId: number): SunspecModel | undefined;
39
57
  /**
40
- * Read a register value and apply scale factor
41
- */
42
- readRegisterWithScaleFactor(valueAddress: number, scaleFactorAddress?: number, quantity?: number): Promise<number>;
43
- /**
44
- * Convert unsigned 16-bit value to signed
45
- */
46
- private convertToSigned16;
47
- /**
48
- * Check if a value is "unimplemented" according to Sunspec
58
+ * Check if a value is "unimplemented" according to Sunspec specification
49
59
  * Returns true if the value represents an unimplemented/not applicable register
60
+ *
61
+ * Sunspec NOT_IMPLEMENTED values:
62
+ * - int16: 0x8000
63
+ * - uint16: 0xFFFF
64
+ * - int32: 0x80000000
65
+ * - uint32: 0xFFFFFFFF
66
+ * - int64: 0x8000000000000000
67
+ * - uint64: 0xFFFFFFFFFFFFFFFF
68
+ * - acc16: 0x0000 (NOT_ACCUMULATED, not truly unimplemented)
69
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, not truly unimplemented)
70
+ * - acc64: 0x0000000000000000 (NOT_ACCUMULATED, not truly unimplemented)
71
+ * - enum16: 0xFFFF
72
+ * - enum32: 0xFFFFFFFF
73
+ * - bitfield16: 0xFFFF
74
+ * - bitfield32: 0xFFFFFFFF
75
+ * - pad: 0x8000 (always returns this value)
76
+ * - ipaddr: 0x00000000 (NOT_CONFIGURED)
77
+ * - string: all registers 0x0000 (NULL)
50
78
  */
51
79
  private isUnimplementedValue;
52
80
  /**
@@ -1,3 +1,21 @@
1
+ /**
2
+ * Sunspec Modbus Client Implementation
3
+ *
4
+ * This module implements the Sunspec protocol for reading data from solar inverters,
5
+ * meters, and other energy devices over Modbus TCP/RTU.
6
+ *
7
+ * Sunspec NOT_IMPLEMENTED values reference:
8
+ * - int16: 0x8000 (-32768)
9
+ * - uint16: 0xFFFF (65535)
10
+ * - int32: 0x80000000 (-2147483648)
11
+ * - uint32: 0xFFFFFFFF (4294967295)
12
+ * - acc16: 0x0000 (NOT_ACCUMULATED, valid but zero)
13
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, valid but zero)
14
+ * - enum16/bitfield16: 0xFFFF
15
+ * - enum32/bitfield32: 0xFFFFFFFF
16
+ * - pad: 0x8000 (always returns this value)
17
+ * - string: all registers 0x0000 (NULL)
18
+ */
1
19
  import { SunspecModelId } from "./sunspec-interfaces.js";
2
20
  import { EnergyAppModbusConnectionHealth } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusConnectionHealth.js";
3
21
  import { EnergyAppModbusFaultTolerantReader } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js";
@@ -148,58 +166,65 @@ export class SunspecModbusClient {
148
166
  return this.discoveredModels.get(modelId);
149
167
  }
150
168
  /**
151
- * Read a register value and apply scale factor
152
- */
153
- async readRegisterWithScaleFactor(valueAddress, scaleFactorAddress, quantity = 1) {
154
- if (!this.connected) {
155
- throw new Error('Not connected to Modbus device');
156
- }
157
- // Read the raw value
158
- if (!this.modbusClient) {
159
- throw new Error('Modbus client not initialized');
160
- }
161
- const buffer = await this.modbusClient.readHoldingRegisters(valueAddress, quantity);
162
- let value = buffer.readUInt16BE(0);
163
- // Apply scale factor if provided
164
- if (scaleFactorAddress) {
165
- let scaleFactor = this.scaleFactors[`sf_${scaleFactorAddress}`];
166
- if (scaleFactor === undefined) {
167
- if (!this.modbusClient) {
168
- throw new Error('Modbus client not initialized');
169
- }
170
- const sfBuffer = await this.modbusClient.readHoldingRegisters(scaleFactorAddress, 1);
171
- // Scale factors are signed int16
172
- scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
173
- this.scaleFactors[`sf_${scaleFactorAddress}`] = scaleFactor;
174
- }
175
- // Apply scale factor: value * 10^scaleFactor
176
- value = value * Math.pow(10, scaleFactor);
177
- }
178
- return value;
179
- }
180
- /**
181
- * Convert unsigned 16-bit value to signed
182
- */
183
- convertToSigned16(value) {
184
- if (value > 32767) {
185
- return value - 65536;
186
- }
187
- return value;
188
- }
189
- /**
190
- * Check if a value is "unimplemented" according to Sunspec
169
+ * Check if a value is "unimplemented" according to Sunspec specification
191
170
  * Returns true if the value represents an unimplemented/not applicable register
171
+ *
172
+ * Sunspec NOT_IMPLEMENTED values:
173
+ * - int16: 0x8000
174
+ * - uint16: 0xFFFF
175
+ * - int32: 0x80000000
176
+ * - uint32: 0xFFFFFFFF
177
+ * - int64: 0x8000000000000000
178
+ * - uint64: 0xFFFFFFFFFFFFFFFF
179
+ * - acc16: 0x0000 (NOT_ACCUMULATED, not truly unimplemented)
180
+ * - acc32: 0x00000000 (NOT_ACCUMULATED, not truly unimplemented)
181
+ * - acc64: 0x0000000000000000 (NOT_ACCUMULATED, not truly unimplemented)
182
+ * - enum16: 0xFFFF
183
+ * - enum32: 0xFFFFFFFF
184
+ * - bitfield16: 0xFFFF
185
+ * - bitfield32: 0xFFFFFFFF
186
+ * - pad: 0x8000 (always returns this value)
187
+ * - ipaddr: 0x00000000 (NOT_CONFIGURED)
188
+ * - string: all registers 0x0000 (NULL)
192
189
  */
193
190
  isUnimplementedValue(value, dataType = 'uint16') {
194
191
  switch (dataType) {
195
192
  case 'uint16':
196
- return value === 0xFFFF || value === 65535;
193
+ case 'enum16':
194
+ case 'bitfield16':
195
+ return value === 0xFFFF;
197
196
  case 'int16':
198
- return value === 0x7FFF || value === 32767;
197
+ case 'pad':
198
+ return value === 0x8000;
199
199
  case 'uint32':
200
+ case 'enum32':
201
+ case 'bitfield32':
200
202
  return value === 0xFFFFFFFF;
201
203
  case 'int32':
202
- return value === 0x7FFFFFFF;
204
+ return value === 0x80000000;
205
+ case 'uint64':
206
+ return value === 0xffffffffffffffffn;
207
+ case 'int64':
208
+ return value === 0x8000000000000000n;
209
+ case 'acc16':
210
+ // 0x0000 means NOT_ACCUMULATED (value is valid but zero)
211
+ // For accumulators, we typically don't treat 0 as unimplemented
212
+ return false;
213
+ case 'acc32':
214
+ // 0x00000000 means NOT_ACCUMULATED (value is valid but zero)
215
+ // For accumulators, we typically don't treat 0 as unimplemented
216
+ return false;
217
+ case 'acc64':
218
+ // 0x0000000000000000 means NOT_ACCUMULATED (value is valid but zero)
219
+ // For accumulators, we typically don't treat 0 as unimplemented
220
+ return false;
221
+ case 'ipaddr':
222
+ // 0x00000000 means NOT_CONFIGURED
223
+ return value === 0x00000000;
224
+ case 'string':
225
+ // For strings, all 0x0000 means unimplemented
226
+ // This would need special handling in the string reading logic
227
+ return value === 0;
203
228
  default:
204
229
  return false;
205
230
  }
@@ -239,24 +264,15 @@ export class SunspecModbusClient {
239
264
  }
240
265
  return this.cleanString(str);
241
266
  case 'int16':
242
- return this.convertToSigned16(buffer.readUInt16BE(0));
267
+ return buffer.readInt16BE(0);
243
268
  case 'uint32':
244
269
  case 'acc32':
245
- // 32-bit values use 2 registers
246
- return (buffer.readUInt16BE(0) << 16) | buffer.readUInt16BE(2);
270
+ return buffer.readUint32BE(0);
247
271
  case 'int32':
248
- const val = (buffer.readUInt16BE(0) << 16) | buffer.readUInt16BE(2);
249
- return val > 0x7FFFFFFF ? val - 0x100000000 : val;
272
+ return buffer.readInt32BE(0);
250
273
  case 'uint16':
251
274
  default:
252
- if (quantity === 1) {
253
- return buffer.readUInt16BE(0);
254
- }
255
- const values = [];
256
- for (let i = 0; i < quantity; i++) {
257
- values.push(buffer.readUInt16BE(i * 2));
258
- }
259
- return values;
275
+ return buffer.readUInt16BE(0);
260
276
  }
261
277
  }
262
278
  catch (error) {
@@ -305,54 +321,54 @@ export class SunspecModbusClient {
305
321
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
306
322
  console.log(`AC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
307
323
  return raw;
308
- })(), scaleFactors.A_SF),
309
- phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF),
310
- phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF),
311
- phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF),
324
+ })(), scaleFactors.A_SF, 'uint16', 'AC Current'),
325
+ phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase A Current'),
326
+ phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase B Current'),
327
+ phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase C Current'),
312
328
  // Voltage values - Offsets 7-12
313
- voltageAB: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.V_SF),
314
- voltageBC: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'uint16'), scaleFactors.V_SF),
315
- voltageCA: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'uint16'), scaleFactors.V_SF),
329
+ voltageAB: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage AB'),
330
+ voltageBC: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage BC'),
331
+ voltageCA: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage CA'),
316
332
  // Apply scale factor with unimplemented value checking
317
- voltageAN: this.applyScaleFactor(voltageANRaw, scaleFactors.V_SF),
318
- voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF),
319
- voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF),
333
+ voltageAN: this.applyScaleFactor(voltageANRaw, scaleFactors.V_SF, 'uint16', 'Voltage AN'),
334
+ voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF, 'uint16', 'Voltage BN'),
335
+ voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF, 'uint16', 'Voltage CN'),
320
336
  // Power values - Offsets 14, 18, 20, 22
321
337
  acPower: this.applyScaleFactor(await (async () => {
322
338
  const addr = baseAddr + 14;
323
339
  const raw = await this.readRegisterValue(addr, 1, 'int16');
324
340
  console.log(`AC Power (W): address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.W_SF}`);
325
341
  return raw;
326
- })(), scaleFactors.W_SF, 'int16'),
327
- apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF),
328
- reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF),
329
- powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF),
342
+ })(), scaleFactors.W_SF, 'int16', 'AC Power'),
343
+ apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF, 'uint16', 'Apparent Power'),
344
+ reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF, 'int16', 'Reactive Power'),
345
+ powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF, 'int16', 'Power Factor'),
330
346
  // Frequency - Offset 16
331
- frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF),
347
+ frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF, 'uint16', 'Frequency'),
332
348
  // DC values - Offsets 27, 28, 30
333
349
  dcCurrent: this.applyScaleFactor(await (async () => {
334
350
  const addr = baseAddr + 27;
335
351
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
336
352
  console.log(`DC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
337
353
  return raw;
338
- })(), scaleFactors.DCA_SF),
354
+ })(), scaleFactors.DCA_SF, 'uint16', 'DC Current'),
339
355
  dcVoltage: this.applyScaleFactor(await (async () => {
340
356
  const addr = baseAddr + 28;
341
357
  const raw = await this.readRegisterValue(addr, 1, 'uint16');
342
358
  console.log(`DC Voltage: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
343
359
  return raw;
344
- })(), scaleFactors.DCV_SF),
360
+ })(), scaleFactors.DCV_SF, 'uint16', 'DC Voltage'),
345
361
  dcPower: this.applyScaleFactor(await (async () => {
346
362
  const addr = baseAddr + 30;
347
363
  const raw = await this.readRegisterValue(addr, 1, 'int16');
348
364
  console.log(`DC Power: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.DCW_SF}`);
349
365
  return raw;
350
- })(), scaleFactors.DCW_SF, 'int16'),
366
+ })(), scaleFactors.DCW_SF, 'int16', 'DC Power'),
351
367
  // Temperature values - Offsets 32, 34, 35, 36
352
- cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF),
353
- heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF),
354
- transformerTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 35, 1, 'int16'), scaleFactors.Tmp_SF),
355
- otherTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 36, 1, 'int16'), scaleFactors.Tmp_SF),
368
+ cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Cabinet Temperature'),
369
+ heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Heat Sink Temperature'),
370
+ transformerTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 35, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Transformer Temperature'),
371
+ otherTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 36, 1, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Other Temperature'),
356
372
  // Status values - Offsets 38, 39
357
373
  operatingState: await this.readRegisterValue(baseAddr + 38, 1, 'uint16'),
358
374
  vendorState: await this.readRegisterValue(baseAddr + 39, 1, 'uint16'),
@@ -368,7 +384,7 @@ export class SunspecModbusClient {
368
384
  const acEnergyAddr = baseAddr + 24;
369
385
  const acEnergy = await this.readRegisterValue(acEnergyAddr, 2, 'acc32');
370
386
  console.log(`AC Energy: address=${acEnergyAddr}, raw=0x${acEnergy.toString(16).toUpperCase()} (${acEnergy}), SF=${scaleFactors.WH_SF}`);
371
- data.acEnergy = !this.isUnimplementedValue(acEnergy, 'uint32')
387
+ data.acEnergy = !this.isUnimplementedValue(acEnergy, 'acc32')
372
388
  ? acEnergy * Math.pow(10, scaleFactors.WH_SF) // Regular number with scale factor
373
389
  : undefined;
374
390
  // Log final calculated values
@@ -433,13 +449,13 @@ export class SunspecModbusClient {
433
449
  console.log(`Operating State: address=${stateAddr}, raw=0x${stateRaw.toString(16).toUpperCase()} (${stateRaw})`);
434
450
  return {
435
451
  blockNumber: 101,
436
- voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF),
437
- acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF),
438
- acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16'),
439
- frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF),
440
- dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
441
- dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
442
- dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16'),
452
+ voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF, 'uint16', 'Single Phase Voltage'),
453
+ acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF, 'uint16', 'Single Phase AC Current'),
454
+ acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16', 'Single Phase AC Power'),
455
+ frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF, 'uint16', 'Single Phase Frequency'),
456
+ dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', 'Single Phase DC Current'),
457
+ dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', 'Single Phase DC Voltage'),
458
+ dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16', 'Single Phase DC Power'),
443
459
  operatingState: stateRaw
444
460
  };
445
461
  }
@@ -473,12 +489,16 @@ export class SunspecModbusClient {
473
489
  * Apply scale factor to a value
474
490
  * Returns undefined if the value is unimplemented or scale factor is out of range
475
491
  */
476
- applyScaleFactor(value, scaleFactor, dataType = 'uint16') {
492
+ applyScaleFactor(value, scaleFactor, dataType = 'uint16', fieldName) {
477
493
  // Check for unimplemented values
478
494
  if (this.isUnimplementedValue(value, dataType)) {
479
495
  return undefined;
480
496
  }
481
- return value * Math.pow(10, scaleFactor);
497
+ const scaledValue = value * Math.pow(10, scaleFactor);
498
+ // Log the raw and scaled values in decimal format
499
+ const fieldPrefix = fieldName ? `${fieldName}: ` : '';
500
+ console.log(`Scale Factor Applied - ${fieldPrefix}raw=${value} (decimal), SF=${scaleFactor}, scaled=${scaledValue}`);
501
+ return scaledValue;
482
502
  }
483
503
  /**
484
504
  * Read MPPT data from Model 160
@@ -533,24 +553,24 @@ export class SunspecModbusClient {
533
553
  // String ID - Offset 1 (8 registers for string)
534
554
  stringId: await this.readRegisterValue(moduleAddr + 1, 8, 'string'),
535
555
  // DC Current - Offset 9
536
- dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
556
+ dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', `MPPT ${moduleId} DC Current`),
537
557
  dcCurrentSF: scaleFactors.DCA_SF,
538
558
  // DC Voltage - Offset 11
539
- dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
559
+ dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', `MPPT ${moduleId} DC Voltage`),
540
560
  dcVoltageSF: scaleFactors.DCV_SF,
541
561
  // DC Power - Offset 13
542
- dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF),
562
+ dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'uint16', `MPPT ${moduleId} DC Power`),
543
563
  dcPowerSF: scaleFactors.DCW_SF,
544
564
  // DC Energy - Offset 15-16 (32-bit accumulator)
545
565
  // Only calculate if value is not unimplemented
546
- dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'uint32')
566
+ dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'acc32')
547
567
  ? dcEnergyRaw * Math.pow(10, scaleFactors.DCWH_SF) // Regular number with scale factor
548
568
  : undefined,
549
569
  dcEnergySF: scaleFactors.DCWH_SF,
550
570
  // Timestamp - Offset 18-19 (32-bit)
551
571
  timestamp: await this.readRegisterValue(moduleAddr + 18, 2, 'uint32'),
552
572
  // Temperature - Offset 20
553
- temperature: this.applyScaleFactor(temperatureRaw, scaleFactors.Tmp_SF, 'int16'),
573
+ temperature: this.applyScaleFactor(temperatureRaw, scaleFactors.Tmp_SF, 'int16', `MPPT ${moduleId} Temperature`),
554
574
  temperatureSF: scaleFactors.Tmp_SF,
555
575
  // Operating State - Offset 22
556
576
  operatingState: await this.readRegisterValue(moduleAddr + 22, 1, 'uint16'),
@@ -678,12 +698,12 @@ export class SunspecModbusClient {
678
698
  const importRaw = await this.readRegisterValue(importAddr, 2, 'acc32');
679
699
  console.log(`Meter Import Energy: address=${importAddr}, raw=0x${importRaw.toString(16).toUpperCase()} (${importRaw}), SF=${energySF}`);
680
700
  // Calculate final values with scale factors
681
- const totalPower = this.applyScaleFactor(powerRaw, powerSF, 'int16');
682
- const frequency = this.applyScaleFactor(freqRaw, freqSF);
683
- const exportedEnergy = !this.isUnimplementedValue(exportRaw, 'uint32')
701
+ const totalPower = this.applyScaleFactor(powerRaw, powerSF, 'int16', 'Meter Total Power');
702
+ const frequency = this.applyScaleFactor(freqRaw, freqSF, 'uint16', 'Meter Frequency');
703
+ const exportedEnergy = !this.isUnimplementedValue(exportRaw, 'acc32')
684
704
  ? exportRaw * Math.pow(10, energySF) // Regular number, not BigInt
685
705
  : undefined;
686
- const importedEnergy = !this.isUnimplementedValue(importRaw, 'uint32')
706
+ const importedEnergy = !this.isUnimplementedValue(importRaw, 'acc32')
687
707
  ? importRaw * Math.pow(10, energySF) // Regular number, not BigInt
688
708
  : undefined;
689
709
  console.log('Meter Final Values:', {
@@ -809,40 +829,40 @@ export class SunspecModbusClient {
809
829
  blockAddress: model.address,
810
830
  blockLength: model.length,
811
831
  // Power settings - Offset 2
812
- WMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 2, 1, 'uint16'), scaleFactors.WMax_SF),
832
+ WMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 2, 1, 'uint16'), scaleFactors.WMax_SF, 'uint16', 'Max Power'),
813
833
  WMax_SF: scaleFactors.WMax_SF,
814
834
  // Voltage settings - Offsets 3-6
815
- VRef: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.VRef_SF),
835
+ VRef: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.VRef_SF, 'uint16', 'Voltage Reference'),
816
836
  VRef_SF: scaleFactors.VRef_SF,
817
- VRefOfs: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'int16'), scaleFactors.VRefOfs_SF),
837
+ VRefOfs: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'int16'), scaleFactors.VRefOfs_SF, 'int16', 'Voltage Reference Offset'),
818
838
  VRefOfs_SF: scaleFactors.VRefOfs_SF,
819
- VMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.VMinMax_SF),
820
- VMin: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 6, 1, 'uint16'), scaleFactors.VMinMax_SF),
839
+ VMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Max Voltage'),
840
+ VMin: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 6, 1, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Min Voltage'),
821
841
  VMinMax_SF: scaleFactors.VMinMax_SF,
822
842
  // Apparent power settings - Offset 7
823
- VAMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.VAMax_SF),
843
+ VAMax: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 7, 1, 'uint16'), scaleFactors.VAMax_SF, 'uint16', 'Max Apparent Power'),
824
844
  VAMax_SF: scaleFactors.VAMax_SF,
825
845
  // Reactive power settings - Offsets 8-11
826
- VArMaxQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.VArMax_SF),
827
- VArMaxQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'int16'), scaleFactors.VArMax_SF),
828
- VArMaxQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 10, 1, 'int16'), scaleFactors.VArMax_SF),
829
- VArMaxQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 11, 1, 'int16'), scaleFactors.VArMax_SF),
846
+ VArMaxQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q1'),
847
+ VArMaxQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 9, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q2'),
848
+ VArMaxQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 10, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q3'),
849
+ VArMaxQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 11, 1, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q4'),
830
850
  VArMax_SF: scaleFactors.VArMax_SF,
831
851
  // Ramp rate settings - Offset 12
832
- WGra: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 12, 1, 'uint16'), scaleFactors.WGra_SF),
852
+ WGra: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 12, 1, 'uint16'), scaleFactors.WGra_SF, 'uint16', 'Power Ramp Rate'),
833
853
  WGra_SF: scaleFactors.WGra_SF,
834
854
  // Power factor settings - Offsets 13-16
835
- PFMinQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.PFMin_SF),
836
- PFMinQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.PFMin_SF),
837
- PFMinQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.PFMin_SF),
838
- PFMinQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'int16'), scaleFactors.PFMin_SF),
855
+ PFMinQ1: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q1'),
856
+ PFMinQ2: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q2'),
857
+ PFMinQ3: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q3'),
858
+ PFMinQ4: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q4'),
839
859
  PFMin_SF: scaleFactors.PFMin_SF,
840
860
  // Other settings - Offsets 17-21
841
861
  VArAct: await this.readRegisterValue(baseAddr + 17, 1, 'uint16'),
842
862
  ClcTotVA: await this.readRegisterValue(baseAddr + 18, 1, 'uint16'),
843
- MaxRmpRte: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 19, 1, 'uint16'), scaleFactors.MaxRmpRte_SF),
863
+ MaxRmpRte: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 19, 1, 'uint16'), scaleFactors.MaxRmpRte_SF, 'uint16', 'Max Ramp Rate'),
844
864
  MaxRmpRte_SF: scaleFactors.MaxRmpRte_SF,
845
- ECPNomHz: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'uint16'), scaleFactors.ECPNomHz_SF),
865
+ ECPNomHz: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'uint16'), scaleFactors.ECPNomHz_SF, 'uint16', 'Nominal Frequency'),
846
866
  ECPNomHz_SF: scaleFactors.ECPNomHz_SF,
847
867
  ConnPh: await this.readRegisterValue(baseAddr + 21, 1, 'uint16')
848
868
  };
@@ -879,23 +899,23 @@ export class SunspecModbusClient {
879
899
  Conn_RvrtTms: await this.readRegisterValue(baseAddr + 1, 1, 'uint16'),
880
900
  Conn: await this.readRegisterValue(baseAddr + 2, 1, 'uint16'),
881
901
  // Power limit control - Offsets 3-7
882
- WMaxLimPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.WMaxLimPct_SF),
902
+ WMaxLimPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.WMaxLimPct_SF, 'uint16', 'Power Limit Percentage'),
883
903
  WMaxLimPct_SF: scaleFactors.WMaxLimPct_SF,
884
904
  WMaxLimPct_WinTms: await this.readRegisterValue(baseAddr + 4, 1, 'uint16'),
885
905
  WMaxLimPct_RvrtTms: await this.readRegisterValue(baseAddr + 5, 1, 'uint16'),
886
906
  WMaxLimPct_RmpTms: await this.readRegisterValue(baseAddr + 6, 1, 'uint16'),
887
907
  WMaxLim_Ena: await this.readRegisterValue(baseAddr + 7, 1, 'uint16'),
888
908
  // Power factor control - Offsets 8-12
889
- OutPFSet: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.OutPFSet_SF),
909
+ OutPFSet: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 8, 1, 'int16'), scaleFactors.OutPFSet_SF, 'int16', 'Output Power Factor Set'),
890
910
  OutPFSet_SF: scaleFactors.OutPFSet_SF,
891
911
  OutPFSet_WinTms: await this.readRegisterValue(baseAddr + 9, 1, 'uint16'),
892
912
  OutPFSet_RvrtTms: await this.readRegisterValue(baseAddr + 10, 1, 'uint16'),
893
913
  OutPFSet_RmpTms: await this.readRegisterValue(baseAddr + 11, 1, 'uint16'),
894
914
  OutPFSet_Ena: await this.readRegisterValue(baseAddr + 12, 1, 'uint16'),
895
915
  // Reactive power control - Offsets 13-20
896
- VArWMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.VArPct_SF),
897
- VArMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.VArPct_SF),
898
- VArAvalPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.VArPct_SF),
916
+ VArWMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 13, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Reactive Power at Max Power %'),
917
+ VArMaxPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 14, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Max Reactive Power %'),
918
+ VArAvalPct: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 15, 1, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Available Reactive Power %'),
899
919
  VArPct_SF: scaleFactors.VArPct_SF,
900
920
  VArPct_WinTms: await this.readRegisterValue(baseAddr + 16, 1, 'uint16'),
901
921
  VArPct_RvrtTms: await this.readRegisterValue(baseAddr + 17, 1, 'uint16'),
@@ -926,7 +946,7 @@ export class SunspecModbusClient {
926
946
  if (settings.WMax !== undefined && this.modbusClient) {
927
947
  // Need to read scale factor first if not provided
928
948
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 22, 1);
929
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
949
+ const scaleFactor = sfBuffer.readInt16BE(0);
930
950
  const scaledValue = Math.round(settings.WMax / Math.pow(10, scaleFactor));
931
951
  // Writing registers needs to be implemented in EnergyAppModbusInstance
932
952
  // For now, log the write operation
@@ -934,7 +954,7 @@ export class SunspecModbusClient {
934
954
  }
935
955
  if (settings.VRef !== undefined && this.modbusClient) {
936
956
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 23, 1);
937
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
957
+ const scaleFactor = sfBuffer.readInt16BE(0);
938
958
  const scaledValue = Math.round(settings.VRef / Math.pow(10, scaleFactor));
939
959
  console.log(`Would write value ${scaledValue} to register ${baseAddr + 1}`);
940
960
  }
@@ -966,7 +986,7 @@ export class SunspecModbusClient {
966
986
  // Power limit control
967
987
  if (controls.WMaxLimPct !== undefined && this.modbusClient) {
968
988
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 21, 1);
969
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
989
+ const scaleFactor = sfBuffer.readInt16BE(0);
970
990
  const scaledValue = Math.round(controls.WMaxLimPct / Math.pow(10, scaleFactor));
971
991
  console.log(`Would write power limit ${scaledValue} to register ${baseAddr + 3}`);
972
992
  }
@@ -976,7 +996,7 @@ export class SunspecModbusClient {
976
996
  // Power factor control
977
997
  if (controls.OutPFSet !== undefined && this.modbusClient) {
978
998
  const sfBuffer = await this.modbusClient.readHoldingRegisters(baseAddr + 22, 1);
979
- const scaleFactor = this.convertToSigned16(sfBuffer.readUInt16BE(0));
999
+ const scaleFactor = sfBuffer.readInt16BE(0);
980
1000
  const scaledValue = Math.round(controls.OutPFSet / Math.pow(10, scaleFactor));
981
1001
  console.log(`Would write power factor ${scaledValue} to register ${baseAddr + 8}`);
982
1002
  }
package/dist/version.d.ts CHANGED
@@ -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.9";
8
+ export declare const SDK_VERSION = "0.0.10";
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/dist/version.js CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * Current version of the enyo Energy App SDK.
7
7
  */
8
- export const SDK_VERSION = '0.0.9';
8
+ export const SDK_VERSION = '0.0.10';
9
9
  /**
10
10
  * Gets the current SDK version.
11
11
  * @returns The semantic version string of the SDK
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enyo-energy/sunspec-sdk",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "enyo Energy Sunspec SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",