@enyo-energy/sunspec-sdk 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/sunspec-devices.cjs +11 -2
- package/dist/cjs/sunspec-modbus-client.cjs +130 -22
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/sunspec-devices.js +11 -2
- package/dist/sunspec-modbus-client.js +130 -22
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -103,6 +103,15 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
103
103
|
const inverterData = await this.sunspecClient.readInverterData();
|
|
104
104
|
const mpptDataList = await this.sunspecClient.readAllMPPTData();
|
|
105
105
|
if (inverterData) {
|
|
106
|
+
// Log what we're sending
|
|
107
|
+
console.log('Preparing Inverter Message:', {
|
|
108
|
+
pvPowerW: inverterData.dcPower,
|
|
109
|
+
acPower: inverterData.acPower,
|
|
110
|
+
voltageL1: inverterData.voltageAN,
|
|
111
|
+
voltageL2: inverterData.voltageBN,
|
|
112
|
+
voltageL3: inverterData.voltageCN,
|
|
113
|
+
stringsCount: mpptDataList.length
|
|
114
|
+
});
|
|
106
115
|
const inverterMessage = {
|
|
107
116
|
id: (0, node_crypto_1.randomUUID)(),
|
|
108
117
|
message: enyo_data_bus_value_js_1.EnyoDataBusMessageEnum.InverterValuesUpdateV1,
|
|
@@ -117,8 +126,8 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
117
126
|
activePowerLimitationW: inverterData.acPower || 0,
|
|
118
127
|
state: this.mapOperatingState(inverterData.operatingState),
|
|
119
128
|
voltageL1: inverterData.voltageAN || 0,
|
|
120
|
-
voltageL2: inverterData.voltageBN ?? undefined, // Use
|
|
121
|
-
voltageL3: inverterData.voltageCN ?? undefined, // Use
|
|
129
|
+
voltageL2: inverterData.voltageBN ?? undefined, // Use undefined if unimplemented phase
|
|
130
|
+
voltageL3: inverterData.voltageCN ?? undefined, // Use undefined if unimplemented phase
|
|
122
131
|
strings: this.mapMPPTToStrings(mpptDataList)
|
|
123
132
|
}
|
|
124
133
|
};
|
|
@@ -279,11 +279,14 @@ class SunspecModbusClient {
|
|
|
279
279
|
console.error('No inverter model found');
|
|
280
280
|
return null;
|
|
281
281
|
}
|
|
282
|
+
console.warn('IMPORTANT: Working with single-phase inverter, but 3-phase is expected!');
|
|
282
283
|
return this.readSinglePhaseInverterData(singlePhaseModel);
|
|
283
284
|
}
|
|
285
|
+
console.log(`Found 3-phase inverter model 103 at address ${model.address} with length ${model.length}`);
|
|
284
286
|
const baseAddr = model.address + 2; // Skip ID and Length
|
|
285
287
|
try {
|
|
286
288
|
// Read all scale factors first using fault-tolerant reader
|
|
289
|
+
console.log(`Reading Inverter Data from Model 103 at base address: ${baseAddr}`);
|
|
287
290
|
const scaleFactors = await this.readInverterScaleFactors(baseAddr);
|
|
288
291
|
// Read values using fault-tolerant reader with proper data types
|
|
289
292
|
// Read raw voltage values to check for unimplemented phases
|
|
@@ -300,7 +303,12 @@ class SunspecModbusClient {
|
|
|
300
303
|
blockAddress: model.address,
|
|
301
304
|
blockLength: model.length,
|
|
302
305
|
// AC Current values - Offsets 2-5
|
|
303
|
-
acCurrent: this.applyScaleFactor(await
|
|
306
|
+
acCurrent: this.applyScaleFactor(await (async () => {
|
|
307
|
+
const addr = baseAddr + 2;
|
|
308
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
309
|
+
console.log(`AC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
310
|
+
return raw;
|
|
311
|
+
})(), scaleFactors.A_SF),
|
|
304
312
|
phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF),
|
|
305
313
|
phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF),
|
|
306
314
|
phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF),
|
|
@@ -313,16 +321,36 @@ class SunspecModbusClient {
|
|
|
313
321
|
voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF),
|
|
314
322
|
voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF),
|
|
315
323
|
// Power values - Offsets 14, 18, 20, 22
|
|
316
|
-
acPower: this.applyScaleFactor(await
|
|
324
|
+
acPower: this.applyScaleFactor(await (async () => {
|
|
325
|
+
const addr = baseAddr + 14;
|
|
326
|
+
const raw = await this.readRegisterValue(addr, 1, 'int16');
|
|
327
|
+
console.log(`AC Power (W): address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.W_SF}`);
|
|
328
|
+
return raw;
|
|
329
|
+
})(), scaleFactors.W_SF, 'int16'),
|
|
317
330
|
apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF),
|
|
318
331
|
reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF),
|
|
319
332
|
powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF),
|
|
320
333
|
// Frequency - Offset 16
|
|
321
334
|
frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF),
|
|
322
335
|
// DC values - Offsets 27, 28, 30
|
|
323
|
-
dcCurrent: this.applyScaleFactor(await
|
|
324
|
-
|
|
325
|
-
|
|
336
|
+
dcCurrent: this.applyScaleFactor(await (async () => {
|
|
337
|
+
const addr = baseAddr + 27;
|
|
338
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
339
|
+
console.log(`DC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
340
|
+
return raw;
|
|
341
|
+
})(), scaleFactors.DCA_SF),
|
|
342
|
+
dcVoltage: this.applyScaleFactor(await (async () => {
|
|
343
|
+
const addr = baseAddr + 28;
|
|
344
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
345
|
+
console.log(`DC Voltage: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
346
|
+
return raw;
|
|
347
|
+
})(), scaleFactors.DCV_SF),
|
|
348
|
+
dcPower: this.applyScaleFactor(await (async () => {
|
|
349
|
+
const addr = baseAddr + 30;
|
|
350
|
+
const raw = await this.readRegisterValue(addr, 1, 'int16');
|
|
351
|
+
console.log(`DC Power: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.DCW_SF}`);
|
|
352
|
+
return raw;
|
|
353
|
+
})(), scaleFactors.DCW_SF, 'int16'),
|
|
326
354
|
// Temperature values - Offsets 32, 34, 35, 36
|
|
327
355
|
cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF),
|
|
328
356
|
heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF),
|
|
@@ -340,8 +368,21 @@ class SunspecModbusClient {
|
|
|
340
368
|
vendorEvents4: await this.readRegisterValue(baseAddr + 50, 2, 'uint32')
|
|
341
369
|
};
|
|
342
370
|
// Read AC Energy (32-bit accumulator) - Offset 24-25
|
|
343
|
-
const
|
|
371
|
+
const acEnergyAddr = baseAddr + 24;
|
|
372
|
+
const acEnergy = await this.readRegisterValue(acEnergyAddr, 2, 'acc32');
|
|
373
|
+
console.log(`AC Energy: address=${acEnergyAddr}, raw=0x${acEnergy.toString(16).toUpperCase()} (${acEnergy}), SF=${scaleFactors.WH_SF}`);
|
|
344
374
|
data.acEnergy = BigInt(acEnergy) * BigInt(Math.pow(10, scaleFactors.WH_SF));
|
|
375
|
+
// Log final calculated values
|
|
376
|
+
console.log('Inverter Final Values:', {
|
|
377
|
+
acPower: data.acPower,
|
|
378
|
+
dcPower: data.dcPower,
|
|
379
|
+
voltageAN: data.voltageAN,
|
|
380
|
+
voltageBN: data.voltageBN,
|
|
381
|
+
voltageCN: data.voltageCN,
|
|
382
|
+
dcVoltage: data.dcVoltage,
|
|
383
|
+
dcCurrent: data.dcCurrent,
|
|
384
|
+
acCurrent: data.acCurrent
|
|
385
|
+
});
|
|
345
386
|
return data;
|
|
346
387
|
}
|
|
347
388
|
catch (error) {
|
|
@@ -357,15 +398,53 @@ class SunspecModbusClient {
|
|
|
357
398
|
// Implementation would be similar but simplified
|
|
358
399
|
const baseAddr = model.address + 2;
|
|
359
400
|
try {
|
|
360
|
-
|
|
401
|
+
console.log(`Reading Single-Phase Inverter Data from Model 101 at base address: ${baseAddr}`);
|
|
402
|
+
// Read scale factors for single phase model
|
|
403
|
+
const scaleFactors = {
|
|
404
|
+
A_SF: await this.readRegisterValue(baseAddr + 6, 1, 'int16'),
|
|
405
|
+
V_SF: await this.readRegisterValue(baseAddr + 13, 1, 'int16'),
|
|
406
|
+
W_SF: await this.readRegisterValue(baseAddr + 10, 1, 'int16'),
|
|
407
|
+
Hz_SF: await this.readRegisterValue(baseAddr + 12, 1, 'int16'),
|
|
408
|
+
DCA_SF: await this.readRegisterValue(baseAddr + 18, 1, 'int16'),
|
|
409
|
+
DCV_SF: await this.readRegisterValue(baseAddr + 19, 1, 'int16'),
|
|
410
|
+
DCW_SF: await this.readRegisterValue(baseAddr + 21, 1, 'int16')
|
|
411
|
+
};
|
|
412
|
+
console.log('Single-Phase Inverter Scale Factors:', JSON.stringify(scaleFactors, null, 2));
|
|
413
|
+
// Read raw values with logging
|
|
414
|
+
const acCurrentAddr = baseAddr + 2;
|
|
415
|
+
const acCurrentRaw = await this.readRegisterValue(acCurrentAddr, 1, 'uint16');
|
|
416
|
+
console.log(`AC Current: address=${acCurrentAddr}, raw=0x${acCurrentRaw.toString(16).toUpperCase()} (${acCurrentRaw})`);
|
|
417
|
+
const voltageAddr = baseAddr + 7;
|
|
418
|
+
const voltageRaw = await this.readRegisterValue(voltageAddr, 1, 'uint16');
|
|
419
|
+
console.log(`AC Voltage: address=${voltageAddr}, raw=0x${voltageRaw.toString(16).toUpperCase()} (${voltageRaw})`);
|
|
420
|
+
const acPowerAddr = baseAddr + 9;
|
|
421
|
+
const acPowerRaw = await this.readRegisterValue(acPowerAddr, 1, 'int16');
|
|
422
|
+
console.log(`AC Power: address=${acPowerAddr}, raw=0x${acPowerRaw.toString(16).toUpperCase()} (${acPowerRaw}), SF=${scaleFactors.W_SF}`);
|
|
423
|
+
const freqAddr = baseAddr + 11;
|
|
424
|
+
const freqRaw = await this.readRegisterValue(freqAddr, 1, 'uint16');
|
|
425
|
+
console.log(`Frequency: address=${freqAddr}, raw=0x${freqRaw.toString(16).toUpperCase()} (${freqRaw})`);
|
|
426
|
+
const dcCurrentAddr = baseAddr + 14;
|
|
427
|
+
const dcCurrentRaw = await this.readRegisterValue(dcCurrentAddr, 1, 'uint16');
|
|
428
|
+
console.log(`DC Current: address=${dcCurrentAddr}, raw=0x${dcCurrentRaw.toString(16).toUpperCase()} (${dcCurrentRaw})`);
|
|
429
|
+
const dcVoltageAddr = baseAddr + 15;
|
|
430
|
+
const dcVoltageRaw = await this.readRegisterValue(dcVoltageAddr, 1, 'uint16');
|
|
431
|
+
console.log(`DC Voltage: address=${dcVoltageAddr}, raw=0x${dcVoltageRaw.toString(16).toUpperCase()} (${dcVoltageRaw})`);
|
|
432
|
+
const dcPowerAddr = baseAddr + 20;
|
|
433
|
+
const dcPowerRaw = await this.readRegisterValue(dcPowerAddr, 1, 'int16');
|
|
434
|
+
console.log(`DC Power: address=${dcPowerAddr}, raw=0x${dcPowerRaw.toString(16).toUpperCase()} (${dcPowerRaw}), SF=${scaleFactors.DCW_SF}`);
|
|
435
|
+
const stateAddr = baseAddr + 24;
|
|
436
|
+
const stateRaw = await this.readRegisterValue(stateAddr, 1, 'uint16');
|
|
437
|
+
console.log(`Operating State: address=${stateAddr}, raw=0x${stateRaw.toString(16).toUpperCase()} (${stateRaw})`);
|
|
361
438
|
return {
|
|
362
439
|
blockNumber: 101,
|
|
363
|
-
voltageAN:
|
|
364
|
-
acCurrent:
|
|
365
|
-
acPower:
|
|
366
|
-
frequency:
|
|
367
|
-
|
|
368
|
-
|
|
440
|
+
voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF),
|
|
441
|
+
acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF),
|
|
442
|
+
acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16'),
|
|
443
|
+
frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF),
|
|
444
|
+
dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
|
|
445
|
+
dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
|
|
446
|
+
dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16'),
|
|
447
|
+
operatingState: stateRaw
|
|
369
448
|
};
|
|
370
449
|
}
|
|
371
450
|
catch (error) {
|
|
@@ -403,11 +482,6 @@ class SunspecModbusClient {
|
|
|
403
482
|
if (this.isUnimplementedValue(value, dataType)) {
|
|
404
483
|
return undefined;
|
|
405
484
|
}
|
|
406
|
-
// Validate scale factor is within reasonable range (-10 to +10)
|
|
407
|
-
if (Math.abs(scaleFactor) > 10) {
|
|
408
|
-
console.warn(`Scale factor ${scaleFactor} is outside reasonable range, clamping to ±10`);
|
|
409
|
-
scaleFactor = Math.max(-10, Math.min(10, scaleFactor));
|
|
410
|
-
}
|
|
411
485
|
return value * Math.pow(10, scaleFactor);
|
|
412
486
|
}
|
|
413
487
|
/**
|
|
@@ -536,13 +610,47 @@ class SunspecModbusClient {
|
|
|
536
610
|
return null;
|
|
537
611
|
}
|
|
538
612
|
const baseAddr = model.address + 2;
|
|
613
|
+
console.log(`Reading Meter Data from Model ${model.id} at base address: ${baseAddr}`);
|
|
539
614
|
try {
|
|
540
|
-
//
|
|
541
|
-
//
|
|
615
|
+
// Model 201 (single phase) and 203 (3-phase) have different offsets
|
|
616
|
+
// Model 201: Power at offset 12, Frequency at offset 18
|
|
617
|
+
// Model 203: Power at offset 14, Frequency at offset 24
|
|
618
|
+
const isPowerMeter201 = model.id === 201;
|
|
619
|
+
const powerOffset = isPowerMeter201 ? 12 : 14; // Total Real Power offset
|
|
620
|
+
const powerSFOffset = isPowerMeter201 ? 15 : 17; // Power scale factor offset
|
|
621
|
+
const freqOffset = isPowerMeter201 ? 18 : 24; // Frequency offset
|
|
622
|
+
const freqSFOffset = isPowerMeter201 ? 21 : 27; // Frequency scale factor offset
|
|
623
|
+
const exportOffset = isPowerMeter201 ? 32 : 38; // Total Wh Exported offset
|
|
624
|
+
const importOffset = isPowerMeter201 ? 40 : 46; // Total Wh Imported offset
|
|
625
|
+
const energySFOffset = 4; // Energy scale factor is typically at offset 4
|
|
626
|
+
// Read scale factors
|
|
627
|
+
const powerSF = await this.readRegisterValue(baseAddr + powerSFOffset, 1, 'int16');
|
|
628
|
+
const freqSF = await this.readRegisterValue(baseAddr + freqSFOffset, 1, 'int16');
|
|
629
|
+
const energySF = await this.readRegisterValue(baseAddr + energySFOffset, 1, 'int16');
|
|
630
|
+
console.log(`Meter Scale Factors: Power_SF=${powerSF}, Freq_SF=${freqSF}, Energy_SF=${energySF}`);
|
|
631
|
+
// Read raw values
|
|
632
|
+
const powerAddr = baseAddr + powerOffset;
|
|
633
|
+
const powerRaw = await this.readRegisterValue(powerAddr, 1, 'int16');
|
|
634
|
+
console.log(`Meter Total Power: address=${powerAddr}, raw=0x${powerRaw.toString(16).toUpperCase()} (${powerRaw}), SF=${powerSF}`);
|
|
635
|
+
const freqAddr = baseAddr + freqOffset;
|
|
636
|
+
const freqRaw = await this.readRegisterValue(freqAddr, 1, 'uint16');
|
|
637
|
+
console.log(`Meter Frequency: address=${freqAddr}, raw=0x${freqRaw.toString(16).toUpperCase()} (${freqRaw}), SF=${freqSF}`);
|
|
638
|
+
const exportAddr = baseAddr + exportOffset;
|
|
639
|
+
const exportRaw = await this.readRegisterValue(exportAddr, 2, 'acc32');
|
|
640
|
+
console.log(`Meter Export Energy: address=${exportAddr}, raw=0x${exportRaw.toString(16).toUpperCase()} (${exportRaw}), SF=${energySF}`);
|
|
641
|
+
const importAddr = baseAddr + importOffset;
|
|
642
|
+
const importRaw = await this.readRegisterValue(importAddr, 2, 'acc32');
|
|
643
|
+
console.log(`Meter Import Energy: address=${importAddr}, raw=0x${importRaw.toString(16).toUpperCase()} (${importRaw}), SF=${energySF}`);
|
|
542
644
|
return {
|
|
543
645
|
blockNumber: model.id,
|
|
544
|
-
totalPower:
|
|
545
|
-
frequency:
|
|
646
|
+
totalPower: this.applyScaleFactor(powerRaw, powerSF, 'int16'),
|
|
647
|
+
frequency: this.applyScaleFactor(freqRaw, freqSF),
|
|
648
|
+
exportedEnergy: !this.isUnimplementedValue(exportRaw, 'uint32')
|
|
649
|
+
? BigInt(exportRaw) * BigInt(Math.pow(10, energySF))
|
|
650
|
+
: undefined,
|
|
651
|
+
importedEnergy: !this.isUnimplementedValue(importRaw, 'uint32')
|
|
652
|
+
? BigInt(importRaw) * BigInt(Math.pow(10, energySF))
|
|
653
|
+
: undefined
|
|
546
654
|
};
|
|
547
655
|
}
|
|
548
656
|
catch (error) {
|
package/dist/cjs/version.cjs
CHANGED
package/dist/cjs/version.d.cts
CHANGED
package/dist/sunspec-devices.js
CHANGED
|
@@ -99,6 +99,15 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
99
99
|
const inverterData = await this.sunspecClient.readInverterData();
|
|
100
100
|
const mpptDataList = await this.sunspecClient.readAllMPPTData();
|
|
101
101
|
if (inverterData) {
|
|
102
|
+
// Log what we're sending
|
|
103
|
+
console.log('Preparing Inverter Message:', {
|
|
104
|
+
pvPowerW: inverterData.dcPower,
|
|
105
|
+
acPower: inverterData.acPower,
|
|
106
|
+
voltageL1: inverterData.voltageAN,
|
|
107
|
+
voltageL2: inverterData.voltageBN,
|
|
108
|
+
voltageL3: inverterData.voltageCN,
|
|
109
|
+
stringsCount: mpptDataList.length
|
|
110
|
+
});
|
|
102
111
|
const inverterMessage = {
|
|
103
112
|
id: randomUUID(),
|
|
104
113
|
message: EnyoDataBusMessageEnum.InverterValuesUpdateV1,
|
|
@@ -113,8 +122,8 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
113
122
|
activePowerLimitationW: inverterData.acPower || 0,
|
|
114
123
|
state: this.mapOperatingState(inverterData.operatingState),
|
|
115
124
|
voltageL1: inverterData.voltageAN || 0,
|
|
116
|
-
voltageL2: inverterData.voltageBN ?? undefined, // Use
|
|
117
|
-
voltageL3: inverterData.voltageCN ?? undefined, // Use
|
|
125
|
+
voltageL2: inverterData.voltageBN ?? undefined, // Use undefined if unimplemented phase
|
|
126
|
+
voltageL3: inverterData.voltageCN ?? undefined, // Use undefined if unimplemented phase
|
|
118
127
|
strings: this.mapMPPTToStrings(mpptDataList)
|
|
119
128
|
}
|
|
120
129
|
};
|
|
@@ -276,11 +276,14 @@ export class SunspecModbusClient {
|
|
|
276
276
|
console.error('No inverter model found');
|
|
277
277
|
return null;
|
|
278
278
|
}
|
|
279
|
+
console.warn('IMPORTANT: Working with single-phase inverter, but 3-phase is expected!');
|
|
279
280
|
return this.readSinglePhaseInverterData(singlePhaseModel);
|
|
280
281
|
}
|
|
282
|
+
console.log(`Found 3-phase inverter model 103 at address ${model.address} with length ${model.length}`);
|
|
281
283
|
const baseAddr = model.address + 2; // Skip ID and Length
|
|
282
284
|
try {
|
|
283
285
|
// Read all scale factors first using fault-tolerant reader
|
|
286
|
+
console.log(`Reading Inverter Data from Model 103 at base address: ${baseAddr}`);
|
|
284
287
|
const scaleFactors = await this.readInverterScaleFactors(baseAddr);
|
|
285
288
|
// Read values using fault-tolerant reader with proper data types
|
|
286
289
|
// Read raw voltage values to check for unimplemented phases
|
|
@@ -297,7 +300,12 @@ export class SunspecModbusClient {
|
|
|
297
300
|
blockAddress: model.address,
|
|
298
301
|
blockLength: model.length,
|
|
299
302
|
// AC Current values - Offsets 2-5
|
|
300
|
-
acCurrent: this.applyScaleFactor(await
|
|
303
|
+
acCurrent: this.applyScaleFactor(await (async () => {
|
|
304
|
+
const addr = baseAddr + 2;
|
|
305
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
306
|
+
console.log(`AC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
307
|
+
return raw;
|
|
308
|
+
})(), scaleFactors.A_SF),
|
|
301
309
|
phaseACurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 3, 1, 'uint16'), scaleFactors.A_SF),
|
|
302
310
|
phaseBCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 4, 1, 'uint16'), scaleFactors.A_SF),
|
|
303
311
|
phaseCCurrent: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 5, 1, 'uint16'), scaleFactors.A_SF),
|
|
@@ -310,16 +318,36 @@ export class SunspecModbusClient {
|
|
|
310
318
|
voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF),
|
|
311
319
|
voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF),
|
|
312
320
|
// Power values - Offsets 14, 18, 20, 22
|
|
313
|
-
acPower: this.applyScaleFactor(await
|
|
321
|
+
acPower: this.applyScaleFactor(await (async () => {
|
|
322
|
+
const addr = baseAddr + 14;
|
|
323
|
+
const raw = await this.readRegisterValue(addr, 1, 'int16');
|
|
324
|
+
console.log(`AC Power (W): address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.W_SF}`);
|
|
325
|
+
return raw;
|
|
326
|
+
})(), scaleFactors.W_SF, 'int16'),
|
|
314
327
|
apparentPower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 18, 1, 'uint16'), scaleFactors.VA_SF),
|
|
315
328
|
reactivePower: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 20, 1, 'int16'), scaleFactors.VAr_SF),
|
|
316
329
|
powerFactor: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 22, 1, 'int16'), scaleFactors.PF_SF),
|
|
317
330
|
// Frequency - Offset 16
|
|
318
331
|
frequency: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 16, 1, 'uint16'), scaleFactors.Hz_SF),
|
|
319
332
|
// DC values - Offsets 27, 28, 30
|
|
320
|
-
dcCurrent: this.applyScaleFactor(await
|
|
321
|
-
|
|
322
|
-
|
|
333
|
+
dcCurrent: this.applyScaleFactor(await (async () => {
|
|
334
|
+
const addr = baseAddr + 27;
|
|
335
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
336
|
+
console.log(`DC Current: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
337
|
+
return raw;
|
|
338
|
+
})(), scaleFactors.DCA_SF),
|
|
339
|
+
dcVoltage: this.applyScaleFactor(await (async () => {
|
|
340
|
+
const addr = baseAddr + 28;
|
|
341
|
+
const raw = await this.readRegisterValue(addr, 1, 'uint16');
|
|
342
|
+
console.log(`DC Voltage: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw})`);
|
|
343
|
+
return raw;
|
|
344
|
+
})(), scaleFactors.DCV_SF),
|
|
345
|
+
dcPower: this.applyScaleFactor(await (async () => {
|
|
346
|
+
const addr = baseAddr + 30;
|
|
347
|
+
const raw = await this.readRegisterValue(addr, 1, 'int16');
|
|
348
|
+
console.log(`DC Power: address=${addr}, raw=0x${raw.toString(16).toUpperCase()} (${raw}), SF=${scaleFactors.DCW_SF}`);
|
|
349
|
+
return raw;
|
|
350
|
+
})(), scaleFactors.DCW_SF, 'int16'),
|
|
323
351
|
// Temperature values - Offsets 32, 34, 35, 36
|
|
324
352
|
cabinetTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 32, 1, 'int16'), scaleFactors.Tmp_SF),
|
|
325
353
|
heatSinkTemperature: this.applyScaleFactor(await this.readRegisterValue(baseAddr + 34, 1, 'int16'), scaleFactors.Tmp_SF),
|
|
@@ -337,8 +365,21 @@ export class SunspecModbusClient {
|
|
|
337
365
|
vendorEvents4: await this.readRegisterValue(baseAddr + 50, 2, 'uint32')
|
|
338
366
|
};
|
|
339
367
|
// Read AC Energy (32-bit accumulator) - Offset 24-25
|
|
340
|
-
const
|
|
368
|
+
const acEnergyAddr = baseAddr + 24;
|
|
369
|
+
const acEnergy = await this.readRegisterValue(acEnergyAddr, 2, 'acc32');
|
|
370
|
+
console.log(`AC Energy: address=${acEnergyAddr}, raw=0x${acEnergy.toString(16).toUpperCase()} (${acEnergy}), SF=${scaleFactors.WH_SF}`);
|
|
341
371
|
data.acEnergy = BigInt(acEnergy) * BigInt(Math.pow(10, scaleFactors.WH_SF));
|
|
372
|
+
// Log final calculated values
|
|
373
|
+
console.log('Inverter Final Values:', {
|
|
374
|
+
acPower: data.acPower,
|
|
375
|
+
dcPower: data.dcPower,
|
|
376
|
+
voltageAN: data.voltageAN,
|
|
377
|
+
voltageBN: data.voltageBN,
|
|
378
|
+
voltageCN: data.voltageCN,
|
|
379
|
+
dcVoltage: data.dcVoltage,
|
|
380
|
+
dcCurrent: data.dcCurrent,
|
|
381
|
+
acCurrent: data.acCurrent
|
|
382
|
+
});
|
|
342
383
|
return data;
|
|
343
384
|
}
|
|
344
385
|
catch (error) {
|
|
@@ -354,15 +395,53 @@ export class SunspecModbusClient {
|
|
|
354
395
|
// Implementation would be similar but simplified
|
|
355
396
|
const baseAddr = model.address + 2;
|
|
356
397
|
try {
|
|
357
|
-
|
|
398
|
+
console.log(`Reading Single-Phase Inverter Data from Model 101 at base address: ${baseAddr}`);
|
|
399
|
+
// Read scale factors for single phase model
|
|
400
|
+
const scaleFactors = {
|
|
401
|
+
A_SF: await this.readRegisterValue(baseAddr + 6, 1, 'int16'),
|
|
402
|
+
V_SF: await this.readRegisterValue(baseAddr + 13, 1, 'int16'),
|
|
403
|
+
W_SF: await this.readRegisterValue(baseAddr + 10, 1, 'int16'),
|
|
404
|
+
Hz_SF: await this.readRegisterValue(baseAddr + 12, 1, 'int16'),
|
|
405
|
+
DCA_SF: await this.readRegisterValue(baseAddr + 18, 1, 'int16'),
|
|
406
|
+
DCV_SF: await this.readRegisterValue(baseAddr + 19, 1, 'int16'),
|
|
407
|
+
DCW_SF: await this.readRegisterValue(baseAddr + 21, 1, 'int16')
|
|
408
|
+
};
|
|
409
|
+
console.log('Single-Phase Inverter Scale Factors:', JSON.stringify(scaleFactors, null, 2));
|
|
410
|
+
// Read raw values with logging
|
|
411
|
+
const acCurrentAddr = baseAddr + 2;
|
|
412
|
+
const acCurrentRaw = await this.readRegisterValue(acCurrentAddr, 1, 'uint16');
|
|
413
|
+
console.log(`AC Current: address=${acCurrentAddr}, raw=0x${acCurrentRaw.toString(16).toUpperCase()} (${acCurrentRaw})`);
|
|
414
|
+
const voltageAddr = baseAddr + 7;
|
|
415
|
+
const voltageRaw = await this.readRegisterValue(voltageAddr, 1, 'uint16');
|
|
416
|
+
console.log(`AC Voltage: address=${voltageAddr}, raw=0x${voltageRaw.toString(16).toUpperCase()} (${voltageRaw})`);
|
|
417
|
+
const acPowerAddr = baseAddr + 9;
|
|
418
|
+
const acPowerRaw = await this.readRegisterValue(acPowerAddr, 1, 'int16');
|
|
419
|
+
console.log(`AC Power: address=${acPowerAddr}, raw=0x${acPowerRaw.toString(16).toUpperCase()} (${acPowerRaw}), SF=${scaleFactors.W_SF}`);
|
|
420
|
+
const freqAddr = baseAddr + 11;
|
|
421
|
+
const freqRaw = await this.readRegisterValue(freqAddr, 1, 'uint16');
|
|
422
|
+
console.log(`Frequency: address=${freqAddr}, raw=0x${freqRaw.toString(16).toUpperCase()} (${freqRaw})`);
|
|
423
|
+
const dcCurrentAddr = baseAddr + 14;
|
|
424
|
+
const dcCurrentRaw = await this.readRegisterValue(dcCurrentAddr, 1, 'uint16');
|
|
425
|
+
console.log(`DC Current: address=${dcCurrentAddr}, raw=0x${dcCurrentRaw.toString(16).toUpperCase()} (${dcCurrentRaw})`);
|
|
426
|
+
const dcVoltageAddr = baseAddr + 15;
|
|
427
|
+
const dcVoltageRaw = await this.readRegisterValue(dcVoltageAddr, 1, 'uint16');
|
|
428
|
+
console.log(`DC Voltage: address=${dcVoltageAddr}, raw=0x${dcVoltageRaw.toString(16).toUpperCase()} (${dcVoltageRaw})`);
|
|
429
|
+
const dcPowerAddr = baseAddr + 20;
|
|
430
|
+
const dcPowerRaw = await this.readRegisterValue(dcPowerAddr, 1, 'int16');
|
|
431
|
+
console.log(`DC Power: address=${dcPowerAddr}, raw=0x${dcPowerRaw.toString(16).toUpperCase()} (${dcPowerRaw}), SF=${scaleFactors.DCW_SF}`);
|
|
432
|
+
const stateAddr = baseAddr + 24;
|
|
433
|
+
const stateRaw = await this.readRegisterValue(stateAddr, 1, 'uint16');
|
|
434
|
+
console.log(`Operating State: address=${stateAddr}, raw=0x${stateRaw.toString(16).toUpperCase()} (${stateRaw})`);
|
|
358
435
|
return {
|
|
359
436
|
blockNumber: 101,
|
|
360
|
-
voltageAN:
|
|
361
|
-
acCurrent:
|
|
362
|
-
acPower:
|
|
363
|
-
frequency:
|
|
364
|
-
|
|
365
|
-
|
|
437
|
+
voltageAN: this.applyScaleFactor(voltageRaw, scaleFactors.V_SF),
|
|
438
|
+
acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF),
|
|
439
|
+
acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16'),
|
|
440
|
+
frequency: this.applyScaleFactor(freqRaw, scaleFactors.Hz_SF),
|
|
441
|
+
dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF),
|
|
442
|
+
dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF),
|
|
443
|
+
dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16'),
|
|
444
|
+
operatingState: stateRaw
|
|
366
445
|
};
|
|
367
446
|
}
|
|
368
447
|
catch (error) {
|
|
@@ -400,11 +479,6 @@ export class SunspecModbusClient {
|
|
|
400
479
|
if (this.isUnimplementedValue(value, dataType)) {
|
|
401
480
|
return undefined;
|
|
402
481
|
}
|
|
403
|
-
// Validate scale factor is within reasonable range (-10 to +10)
|
|
404
|
-
if (Math.abs(scaleFactor) > 10) {
|
|
405
|
-
console.warn(`Scale factor ${scaleFactor} is outside reasonable range, clamping to ±10`);
|
|
406
|
-
scaleFactor = Math.max(-10, Math.min(10, scaleFactor));
|
|
407
|
-
}
|
|
408
482
|
return value * Math.pow(10, scaleFactor);
|
|
409
483
|
}
|
|
410
484
|
/**
|
|
@@ -533,13 +607,47 @@ export class SunspecModbusClient {
|
|
|
533
607
|
return null;
|
|
534
608
|
}
|
|
535
609
|
const baseAddr = model.address + 2;
|
|
610
|
+
console.log(`Reading Meter Data from Model ${model.id} at base address: ${baseAddr}`);
|
|
536
611
|
try {
|
|
537
|
-
//
|
|
538
|
-
//
|
|
612
|
+
// Model 201 (single phase) and 203 (3-phase) have different offsets
|
|
613
|
+
// Model 201: Power at offset 12, Frequency at offset 18
|
|
614
|
+
// Model 203: Power at offset 14, Frequency at offset 24
|
|
615
|
+
const isPowerMeter201 = model.id === 201;
|
|
616
|
+
const powerOffset = isPowerMeter201 ? 12 : 14; // Total Real Power offset
|
|
617
|
+
const powerSFOffset = isPowerMeter201 ? 15 : 17; // Power scale factor offset
|
|
618
|
+
const freqOffset = isPowerMeter201 ? 18 : 24; // Frequency offset
|
|
619
|
+
const freqSFOffset = isPowerMeter201 ? 21 : 27; // Frequency scale factor offset
|
|
620
|
+
const exportOffset = isPowerMeter201 ? 32 : 38; // Total Wh Exported offset
|
|
621
|
+
const importOffset = isPowerMeter201 ? 40 : 46; // Total Wh Imported offset
|
|
622
|
+
const energySFOffset = 4; // Energy scale factor is typically at offset 4
|
|
623
|
+
// Read scale factors
|
|
624
|
+
const powerSF = await this.readRegisterValue(baseAddr + powerSFOffset, 1, 'int16');
|
|
625
|
+
const freqSF = await this.readRegisterValue(baseAddr + freqSFOffset, 1, 'int16');
|
|
626
|
+
const energySF = await this.readRegisterValue(baseAddr + energySFOffset, 1, 'int16');
|
|
627
|
+
console.log(`Meter Scale Factors: Power_SF=${powerSF}, Freq_SF=${freqSF}, Energy_SF=${energySF}`);
|
|
628
|
+
// Read raw values
|
|
629
|
+
const powerAddr = baseAddr + powerOffset;
|
|
630
|
+
const powerRaw = await this.readRegisterValue(powerAddr, 1, 'int16');
|
|
631
|
+
console.log(`Meter Total Power: address=${powerAddr}, raw=0x${powerRaw.toString(16).toUpperCase()} (${powerRaw}), SF=${powerSF}`);
|
|
632
|
+
const freqAddr = baseAddr + freqOffset;
|
|
633
|
+
const freqRaw = await this.readRegisterValue(freqAddr, 1, 'uint16');
|
|
634
|
+
console.log(`Meter Frequency: address=${freqAddr}, raw=0x${freqRaw.toString(16).toUpperCase()} (${freqRaw}), SF=${freqSF}`);
|
|
635
|
+
const exportAddr = baseAddr + exportOffset;
|
|
636
|
+
const exportRaw = await this.readRegisterValue(exportAddr, 2, 'acc32');
|
|
637
|
+
console.log(`Meter Export Energy: address=${exportAddr}, raw=0x${exportRaw.toString(16).toUpperCase()} (${exportRaw}), SF=${energySF}`);
|
|
638
|
+
const importAddr = baseAddr + importOffset;
|
|
639
|
+
const importRaw = await this.readRegisterValue(importAddr, 2, 'acc32');
|
|
640
|
+
console.log(`Meter Import Energy: address=${importAddr}, raw=0x${importRaw.toString(16).toUpperCase()} (${importRaw}), SF=${energySF}`);
|
|
539
641
|
return {
|
|
540
642
|
blockNumber: model.id,
|
|
541
|
-
totalPower:
|
|
542
|
-
frequency:
|
|
643
|
+
totalPower: this.applyScaleFactor(powerRaw, powerSF, 'int16'),
|
|
644
|
+
frequency: this.applyScaleFactor(freqRaw, freqSF),
|
|
645
|
+
exportedEnergy: !this.isUnimplementedValue(exportRaw, 'uint32')
|
|
646
|
+
? BigInt(exportRaw) * BigInt(Math.pow(10, energySF))
|
|
647
|
+
: undefined,
|
|
648
|
+
importedEnergy: !this.isUnimplementedValue(importRaw, 'uint32')
|
|
649
|
+
? BigInt(importRaw) * BigInt(Math.pow(10, energySF))
|
|
650
|
+
: undefined
|
|
543
651
|
};
|
|
544
652
|
}
|
|
545
653
|
catch (error) {
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED