@enyo-energy/sunspec-sdk 0.0.38 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +626 -1
- package/dist/cjs/sunspec-modbus-client.cjs +394 -370
- package/dist/cjs/sunspec-modbus-client.d.cts +25 -4
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/sunspec-modbus-client.d.ts +25 -4
- package/dist/sunspec-modbus-client.js +394 -370
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -363,6 +363,42 @@ export class SunspecModbusClient {
|
|
|
363
363
|
cleanString(value) {
|
|
364
364
|
return value.replace(/\u0000/g, '').trim();
|
|
365
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* Read an entire model's register block in a single Modbus call.
|
|
368
|
+
* Returns a Buffer containing all registers for the model.
|
|
369
|
+
*/
|
|
370
|
+
async readModelBlock(model) {
|
|
371
|
+
if (!this.faultTolerantReader) {
|
|
372
|
+
throw new Error('Fault-tolerant reader not initialized');
|
|
373
|
+
}
|
|
374
|
+
// Read model.length + 2 registers: the 2-register header (ID + length) plus all data registers.
|
|
375
|
+
// This way buffer offsets match the convention used throughout: offset 0 = model ID,
|
|
376
|
+
// offset 1 = model length, offset 2 = first data register, etc.
|
|
377
|
+
const totalRegisters = model.length + 2;
|
|
378
|
+
const result = await this.faultTolerantReader.readHoldingRegisters(model.address, totalRegisters);
|
|
379
|
+
if (!result.success || !result.value) {
|
|
380
|
+
throw new Error(`Failed to read model block ${model.id} at address ${model.address}: ${result.error?.message || 'Unknown error'}`);
|
|
381
|
+
}
|
|
382
|
+
this.connectionHealth.recordSuccess();
|
|
383
|
+
return result.value;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Extract a typed value from a model block buffer at a given register offset.
|
|
387
|
+
* @param buffer - The buffer returned by readModelBlock
|
|
388
|
+
* @param offset - Register offset within the model (0-based)
|
|
389
|
+
* @param dataType - The data type to convert to
|
|
390
|
+
* @param quantity - Number of registers to read (default: auto from dataType for strings, 1 otherwise)
|
|
391
|
+
*/
|
|
392
|
+
extractValue(buffer, offset, dataType, quantity = 1) {
|
|
393
|
+
const byteOffset = offset * 2;
|
|
394
|
+
const byteLength = quantity * 2;
|
|
395
|
+
const sliced = buffer.subarray(byteOffset, byteOffset + byteLength);
|
|
396
|
+
const value = this.modbusDataTypeConverter.convertFromBuffer(sliced, dataType, undefined, quantity);
|
|
397
|
+
if (dataType === 'string') {
|
|
398
|
+
return this.cleanString(value);
|
|
399
|
+
}
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
366
402
|
/**
|
|
367
403
|
* Helper to read register value(s) using the fault-tolerant reader with data type conversion
|
|
368
404
|
*/
|
|
@@ -451,64 +487,63 @@ export class SunspecModbusClient {
|
|
|
451
487
|
return this.readSinglePhaseInverterData(singlePhaseModel);
|
|
452
488
|
}
|
|
453
489
|
console.log(`Found 3-phase inverter model 103 at address ${model.address} with length ${model.length}`);
|
|
454
|
-
const baseAddr = model.address;
|
|
455
490
|
try {
|
|
456
|
-
// Read
|
|
457
|
-
console.log(`Reading Inverter Data from Model ${model.id} at base address: ${
|
|
458
|
-
const
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
const
|
|
466
|
-
const acPowerRaw =
|
|
467
|
-
const dcCurrentRaw =
|
|
468
|
-
const dcVoltageRaw =
|
|
469
|
-
const dcPowerRaw =
|
|
491
|
+
// Read entire model block in a single Modbus call
|
|
492
|
+
console.log(`Reading Inverter Data from Model ${model.id} at base address: ${model.address}`);
|
|
493
|
+
const buffer = await this.readModelBlock(model);
|
|
494
|
+
// Extract all scale factors from buffer
|
|
495
|
+
const scaleFactors = this.extractInverterScaleFactors(buffer);
|
|
496
|
+
// Extract raw values from buffer
|
|
497
|
+
const acCurrentRaw = this.extractValue(buffer, 2, 'uint16');
|
|
498
|
+
const voltageANRaw = this.extractValue(buffer, 10, 'uint16');
|
|
499
|
+
const voltageBNRaw = this.extractValue(buffer, 11, 'uint16');
|
|
500
|
+
const voltageCNRaw = this.extractValue(buffer, 12, 'uint16');
|
|
501
|
+
const acPowerRaw = this.extractValue(buffer, 14, 'int16');
|
|
502
|
+
const dcCurrentRaw = this.extractValue(buffer, 27, 'uint16');
|
|
503
|
+
const dcVoltageRaw = this.extractValue(buffer, 28, 'uint16');
|
|
504
|
+
const dcPowerRaw = this.extractValue(buffer, 30, 'int16');
|
|
470
505
|
const data = {
|
|
471
506
|
blockNumber: 103,
|
|
472
507
|
blockAddress: model.address,
|
|
473
508
|
blockLength: model.length,
|
|
474
509
|
// AC Current values - Offsets 2-5
|
|
475
510
|
acCurrent: this.applyScaleFactor(acCurrentRaw, scaleFactors.A_SF, 'uint16', 'AC Current', 2, 103),
|
|
476
|
-
phaseACurrent: this.applyScaleFactor(
|
|
477
|
-
phaseBCurrent: this.applyScaleFactor(
|
|
478
|
-
phaseCCurrent: this.applyScaleFactor(
|
|
511
|
+
phaseACurrent: this.applyScaleFactor(this.extractValue(buffer, 3, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase A Current', 3, 103),
|
|
512
|
+
phaseBCurrent: this.applyScaleFactor(this.extractValue(buffer, 4, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase B Current', 4, 103),
|
|
513
|
+
phaseCCurrent: this.applyScaleFactor(this.extractValue(buffer, 5, 'uint16'), scaleFactors.A_SF, 'uint16', 'Phase C Current', 5, 103),
|
|
479
514
|
// Voltage values - Offsets 7-12
|
|
480
|
-
voltageAB: this.applyScaleFactor(
|
|
481
|
-
voltageBC: this.applyScaleFactor(
|
|
482
|
-
voltageCA: this.applyScaleFactor(
|
|
515
|
+
voltageAB: this.applyScaleFactor(this.extractValue(buffer, 7, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage AB', 7, 103),
|
|
516
|
+
voltageBC: this.applyScaleFactor(this.extractValue(buffer, 8, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage BC', 8, 103),
|
|
517
|
+
voltageCA: this.applyScaleFactor(this.extractValue(buffer, 9, 'uint16'), scaleFactors.V_SF, 'uint16', 'Voltage CA', 9, 103),
|
|
483
518
|
voltageAN: this.applyScaleFactor(voltageANRaw, scaleFactors.V_SF, 'uint16', 'Voltage AN', 10, 103),
|
|
484
519
|
voltageBN: this.applyScaleFactor(voltageBNRaw, scaleFactors.V_SF, 'uint16', 'Voltage BN', 11, 103),
|
|
485
520
|
voltageCN: this.applyScaleFactor(voltageCNRaw, scaleFactors.V_SF, 'uint16', 'Voltage CN', 12, 103),
|
|
486
521
|
// Power values - Offsets 14, 18, 20, 22
|
|
487
522
|
acPower: this.applyScaleFactor(acPowerRaw, scaleFactors.W_SF, 'int16', 'AC Power', 14, 103),
|
|
488
|
-
apparentPower: this.applyScaleFactor(
|
|
489
|
-
reactivePower: this.applyScaleFactor(
|
|
490
|
-
powerFactor: this.applyScaleFactor(
|
|
523
|
+
apparentPower: this.applyScaleFactor(this.extractValue(buffer, 18, 'uint16'), scaleFactors.VA_SF, 'uint16', 'Apparent Power', 18, 103),
|
|
524
|
+
reactivePower: this.applyScaleFactor(this.extractValue(buffer, 20, 'int16'), scaleFactors.VAr_SF, 'int16', 'Reactive Power', 20, 103),
|
|
525
|
+
powerFactor: this.applyScaleFactor(this.extractValue(buffer, 22, 'int16'), scaleFactors.PF_SF, 'int16', 'Power Factor', 22, 103),
|
|
491
526
|
// Frequency - Offset 16
|
|
492
|
-
frequency: this.applyScaleFactor(
|
|
527
|
+
frequency: this.applyScaleFactor(this.extractValue(buffer, 16, 'uint16'), scaleFactors.Hz_SF, 'uint16', 'Frequency', 16, 103),
|
|
493
528
|
// DC values - Offsets 27, 28, 30
|
|
494
529
|
dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', 'DC Current', 27, 103),
|
|
495
530
|
dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', 'DC Voltage', 28, 103),
|
|
496
531
|
dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'int16', 'DC Power', 30, 103),
|
|
497
532
|
// Temperature values - Offsets 32, 34, 35, 36
|
|
498
|
-
cabinetTemperature: this.applyScaleFactor(
|
|
499
|
-
heatSinkTemperature: this.applyScaleFactor(
|
|
500
|
-
transformerTemperature: this.applyScaleFactor(
|
|
501
|
-
otherTemperature: this.applyScaleFactor(
|
|
533
|
+
cabinetTemperature: this.applyScaleFactor(this.extractValue(buffer, 32, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Cabinet Temperature', 32, 103),
|
|
534
|
+
heatSinkTemperature: this.applyScaleFactor(this.extractValue(buffer, 34, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Heat Sink Temperature', 34, 103),
|
|
535
|
+
transformerTemperature: this.applyScaleFactor(this.extractValue(buffer, 35, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Transformer Temperature', 35, 103),
|
|
536
|
+
otherTemperature: this.applyScaleFactor(this.extractValue(buffer, 36, 'int16'), scaleFactors.Tmp_SF, 'int16', 'Other Temperature', 36, 103),
|
|
502
537
|
// Status values - Offsets 38, 39
|
|
503
|
-
operatingState:
|
|
504
|
-
vendorState:
|
|
538
|
+
operatingState: this.extractValue(buffer, 38, 'uint16'),
|
|
539
|
+
vendorState: this.extractValue(buffer, 39, 'uint16'),
|
|
505
540
|
// Event bitfields - Offsets 40-51
|
|
506
|
-
events:
|
|
507
|
-
events2:
|
|
508
|
-
vendorEvents1:
|
|
509
|
-
vendorEvents2:
|
|
510
|
-
vendorEvents3:
|
|
511
|
-
vendorEvents4:
|
|
541
|
+
events: this.extractValue(buffer, 40, 'uint32', 2),
|
|
542
|
+
events2: this.extractValue(buffer, 42, 'uint32', 2),
|
|
543
|
+
vendorEvents1: this.extractValue(buffer, 44, 'uint32', 2),
|
|
544
|
+
vendorEvents2: this.extractValue(buffer, 46, 'uint32', 2),
|
|
545
|
+
vendorEvents3: this.extractValue(buffer, 48, 'uint32', 2),
|
|
546
|
+
vendorEvents4: this.extractValue(buffer, 50, 'uint32', 2)
|
|
512
547
|
};
|
|
513
548
|
// Log non-scaled fields
|
|
514
549
|
this.logRegisterRead(103, 38, 'Operating State', data.operatingState, 'enum16');
|
|
@@ -520,7 +555,7 @@ export class SunspecModbusClient {
|
|
|
520
555
|
this.logRegisterRead(103, 48, 'Vendor Events 3', data.vendorEvents3, 'bitfield32');
|
|
521
556
|
this.logRegisterRead(103, 50, 'Vendor Events 4', data.vendorEvents4, 'bitfield32');
|
|
522
557
|
// Read AC Energy (32-bit accumulator) - Offset 24-25
|
|
523
|
-
const acEnergy =
|
|
558
|
+
const acEnergy = this.extractValue(buffer, 24, 'uint32', 2);
|
|
524
559
|
this.logRegisterRead(103, 24, 'AC Energy', acEnergy, 'acc32');
|
|
525
560
|
data.acEnergy = !this.isUnimplementedValue(acEnergy, 'acc32')
|
|
526
561
|
? acEnergy * Math.pow(10, scaleFactors.WH_SF)
|
|
@@ -536,20 +571,19 @@ export class SunspecModbusClient {
|
|
|
536
571
|
* Read single phase inverter data (Model 101)
|
|
537
572
|
*/
|
|
538
573
|
async readSinglePhaseInverterData(model) {
|
|
539
|
-
// Similar to 3-phase but with fewer phase-specific values
|
|
540
|
-
// Implementation would be similar but simplified
|
|
541
|
-
const baseAddr = model.address;
|
|
542
574
|
try {
|
|
543
|
-
console.log(`Reading Single-Phase Inverter Data from Model 101 at base address: ${
|
|
544
|
-
// Read
|
|
575
|
+
console.log(`Reading Single-Phase Inverter Data from Model 101 at base address: ${model.address}`);
|
|
576
|
+
// Read entire model block in a single Modbus call
|
|
577
|
+
const buffer = await this.readModelBlock(model);
|
|
578
|
+
// Extract scale factors from buffer
|
|
545
579
|
const scaleFactors = {
|
|
546
|
-
A_SF:
|
|
547
|
-
V_SF:
|
|
548
|
-
W_SF:
|
|
549
|
-
Hz_SF:
|
|
550
|
-
DCA_SF:
|
|
551
|
-
DCV_SF:
|
|
552
|
-
DCW_SF:
|
|
580
|
+
A_SF: this.extractValue(buffer, 6, 'int16'),
|
|
581
|
+
V_SF: this.extractValue(buffer, 13, 'int16'),
|
|
582
|
+
W_SF: this.extractValue(buffer, 10, 'int16'),
|
|
583
|
+
Hz_SF: this.extractValue(buffer, 12, 'int16'),
|
|
584
|
+
DCA_SF: this.extractValue(buffer, 18, 'int16'),
|
|
585
|
+
DCV_SF: this.extractValue(buffer, 19, 'int16'),
|
|
586
|
+
DCW_SF: this.extractValue(buffer, 21, 'int16')
|
|
553
587
|
};
|
|
554
588
|
this.logRegisterRead(101, 6, 'A_SF', scaleFactors.A_SF, 'int16');
|
|
555
589
|
this.logRegisterRead(101, 13, 'V_SF', scaleFactors.V_SF, 'int16');
|
|
@@ -558,15 +592,15 @@ export class SunspecModbusClient {
|
|
|
558
592
|
this.logRegisterRead(101, 18, 'DCA_SF', scaleFactors.DCA_SF, 'int16');
|
|
559
593
|
this.logRegisterRead(101, 19, 'DCV_SF', scaleFactors.DCV_SF, 'int16');
|
|
560
594
|
this.logRegisterRead(101, 21, 'DCW_SF', scaleFactors.DCW_SF, 'int16');
|
|
561
|
-
//
|
|
562
|
-
const acCurrentRaw =
|
|
563
|
-
const voltageRaw =
|
|
564
|
-
const acPowerRaw =
|
|
565
|
-
const freqRaw =
|
|
566
|
-
const dcCurrentRaw =
|
|
567
|
-
const dcVoltageRaw =
|
|
568
|
-
const dcPowerRaw =
|
|
569
|
-
const stateRaw =
|
|
595
|
+
// Extract raw values from buffer
|
|
596
|
+
const acCurrentRaw = this.extractValue(buffer, 2, 'uint16');
|
|
597
|
+
const voltageRaw = this.extractValue(buffer, 7, 'uint16');
|
|
598
|
+
const acPowerRaw = this.extractValue(buffer, 9, 'int16');
|
|
599
|
+
const freqRaw = this.extractValue(buffer, 11, 'uint16');
|
|
600
|
+
const dcCurrentRaw = this.extractValue(buffer, 14, 'uint16');
|
|
601
|
+
const dcVoltageRaw = this.extractValue(buffer, 15, 'uint16');
|
|
602
|
+
const dcPowerRaw = this.extractValue(buffer, 20, 'int16');
|
|
603
|
+
const stateRaw = this.extractValue(buffer, 24, 'uint16');
|
|
570
604
|
this.logRegisterRead(101, 24, 'Operating State', stateRaw, 'enum16');
|
|
571
605
|
return {
|
|
572
606
|
blockNumber: 101,
|
|
@@ -586,22 +620,22 @@ export class SunspecModbusClient {
|
|
|
586
620
|
}
|
|
587
621
|
}
|
|
588
622
|
/**
|
|
589
|
-
*
|
|
623
|
+
* Extract inverter scale factors from a pre-read model buffer
|
|
590
624
|
*/
|
|
591
|
-
|
|
625
|
+
extractInverterScaleFactors(buffer) {
|
|
592
626
|
const scaleFactors = {
|
|
593
|
-
A_SF:
|
|
594
|
-
V_SF:
|
|
595
|
-
W_SF:
|
|
596
|
-
Hz_SF:
|
|
597
|
-
VA_SF:
|
|
598
|
-
VAr_SF:
|
|
599
|
-
PF_SF:
|
|
600
|
-
WH_SF:
|
|
601
|
-
DCA_SF:
|
|
602
|
-
DCV_SF:
|
|
603
|
-
DCW_SF:
|
|
604
|
-
Tmp_SF:
|
|
627
|
+
A_SF: this.extractValue(buffer, 6, 'int16'), // Offset 6
|
|
628
|
+
V_SF: this.extractValue(buffer, 13, 'int16'), // Offset 13
|
|
629
|
+
W_SF: this.extractValue(buffer, 15, 'int16'), // Offset 15
|
|
630
|
+
Hz_SF: this.extractValue(buffer, 17, 'int16'), // Offset 17
|
|
631
|
+
VA_SF: this.extractValue(buffer, 19, 'int16'), // Offset 19
|
|
632
|
+
VAr_SF: this.extractValue(buffer, 21, 'int16'), // Offset 21
|
|
633
|
+
PF_SF: this.extractValue(buffer, 23, 'int16'), // Offset 23
|
|
634
|
+
WH_SF: this.extractValue(buffer, 26, 'int16'), // Offset 26
|
|
635
|
+
DCA_SF: this.extractValue(buffer, 28, 'int16'), // Offset 28
|
|
636
|
+
DCV_SF: this.extractValue(buffer, 29, 'int16'), // Offset 29
|
|
637
|
+
DCW_SF: this.extractValue(buffer, 31, 'int16'), // Offset 31
|
|
638
|
+
Tmp_SF: this.extractValue(buffer, 36, 'int16') // Offset 36
|
|
605
639
|
};
|
|
606
640
|
this.logRegisterRead(103, 6, 'A_SF', scaleFactors.A_SF, 'int16');
|
|
607
641
|
this.logRegisterRead(103, 13, 'V_SF', scaleFactors.V_SF, 'int16');
|
|
@@ -663,38 +697,89 @@ export class SunspecModbusClient {
|
|
|
663
697
|
*
|
|
664
698
|
* @returns Object containing all scale factors or null if model not found
|
|
665
699
|
*/
|
|
700
|
+
/**
|
|
701
|
+
* Extract MPPT scale factors from a pre-read model buffer
|
|
702
|
+
*/
|
|
703
|
+
extractMPPTScaleFactors(buffer) {
|
|
704
|
+
const scaleFactors = {
|
|
705
|
+
DCA_SF: this.extractValue(buffer, 2, 'int16'),
|
|
706
|
+
DCV_SF: this.extractValue(buffer, 3, 'int16'),
|
|
707
|
+
DCW_SF: this.extractValue(buffer, 4, 'int16'),
|
|
708
|
+
DCWH_SF: this.extractValue(buffer, 5, 'int16'),
|
|
709
|
+
};
|
|
710
|
+
this.logRegisterRead(160, 2, 'DCA_SF', scaleFactors.DCA_SF, 'int16');
|
|
711
|
+
this.logRegisterRead(160, 3, 'DCV_SF', scaleFactors.DCV_SF, 'int16');
|
|
712
|
+
this.logRegisterRead(160, 4, 'DCW_SF', scaleFactors.DCW_SF, 'int16');
|
|
713
|
+
this.logRegisterRead(160, 5, 'DCWH_SF', scaleFactors.DCWH_SF, 'int16');
|
|
714
|
+
return scaleFactors;
|
|
715
|
+
}
|
|
666
716
|
async readMPPTScaleFactors() {
|
|
667
717
|
const model = this.findModel(SunspecModelId.MPPT);
|
|
668
718
|
if (!model) {
|
|
669
719
|
console.log('MPPT model 160 not found');
|
|
670
720
|
return null;
|
|
671
721
|
}
|
|
672
|
-
const baseAddr = model.address;
|
|
673
722
|
try {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
// Read scale factors at their specific offsets
|
|
677
|
-
const DCA_SF = await this.readRegisterValue(moduleAddr + 2, 1, 'int16');
|
|
678
|
-
const DCV_SF = await this.readRegisterValue(moduleAddr + 3, 1, 'int16');
|
|
679
|
-
const DCW_SF = await this.readRegisterValue(moduleAddr + 4, 1, 'int16');
|
|
680
|
-
const DCWH_SF = await this.readRegisterValue(moduleAddr + 5, 1, 'int16');
|
|
681
|
-
const scaleFactors = {
|
|
682
|
-
DCA_SF, // Current Scale Factor
|
|
683
|
-
DCV_SF, // Voltage Scale Factor
|
|
684
|
-
DCW_SF, // Power Scale Factor
|
|
685
|
-
DCWH_SF, // Energy Scale Factor
|
|
686
|
-
};
|
|
687
|
-
this.logRegisterRead(160, 2, 'DCA_SF', DCA_SF, 'int16');
|
|
688
|
-
this.logRegisterRead(160, 3, 'DCV_SF', DCV_SF, 'int16');
|
|
689
|
-
this.logRegisterRead(160, 4, 'DCW_SF', DCW_SF, 'int16');
|
|
690
|
-
this.logRegisterRead(160, 5, 'DCWH_SF', DCWH_SF, 'int16');
|
|
691
|
-
return scaleFactors;
|
|
723
|
+
const buffer = await this.readModelBlock(model);
|
|
724
|
+
return this.extractMPPTScaleFactors(buffer);
|
|
692
725
|
}
|
|
693
726
|
catch (error) {
|
|
694
727
|
console.error(`Error reading MPPT scale factors: ${error}`);
|
|
695
728
|
return null;
|
|
696
729
|
}
|
|
697
730
|
}
|
|
731
|
+
/**
|
|
732
|
+
* Extract MPPT module data from a pre-read model buffer
|
|
733
|
+
*/
|
|
734
|
+
extractMPPTModuleData(buffer, model, moduleId, scaleFactors) {
|
|
735
|
+
const fixedBlockScaleFactorsOffset = 10;
|
|
736
|
+
const moduleSize = 20;
|
|
737
|
+
const offset = (moduleId - 1) * moduleSize;
|
|
738
|
+
const moduleOffset = fixedBlockScaleFactorsOffset + offset;
|
|
739
|
+
const id = this.extractValue(buffer, moduleOffset, 'uint16');
|
|
740
|
+
const idString = this.extractValue(buffer, moduleOffset + 1, 'string', 8);
|
|
741
|
+
const dcCurrentRaw = this.extractValue(buffer, moduleOffset + 9, 'uint16');
|
|
742
|
+
const dcVoltageRaw = this.extractValue(buffer, moduleOffset + 10, 'uint16');
|
|
743
|
+
const dcPowerRaw = this.extractValue(buffer, moduleOffset + 11, 'uint16');
|
|
744
|
+
const dcEnergyRaw = this.extractValue(buffer, moduleOffset + 12, 'uint32', 2);
|
|
745
|
+
const temperatureRaw = this.extractValue(buffer, moduleOffset + 16, 'int16');
|
|
746
|
+
const dcst = this.extractValue(buffer, moduleOffset + 17, 'uint16');
|
|
747
|
+
this.logRegisterRead(160, 0, `MPPT ${moduleId} ID`, id, 'uint16');
|
|
748
|
+
this.logRegisterRead(160, 1, `MPPT ${moduleId} String ID`, idString, 'string');
|
|
749
|
+
if (this.isUnimplementedValue(id, 'uint16') &&
|
|
750
|
+
this.isUnimplementedValue(dcCurrentRaw, 'uint16') &&
|
|
751
|
+
this.isUnimplementedValue(dcVoltageRaw, 'uint16') &&
|
|
752
|
+
this.isUnimplementedValue(dcPowerRaw, 'uint16')) {
|
|
753
|
+
console.log(`MPPT module ${moduleId} appears to be unconnected (all values are 0xFFFF)`);
|
|
754
|
+
return null;
|
|
755
|
+
}
|
|
756
|
+
const temperatureScaleFactor = -1;
|
|
757
|
+
this.logRegisterRead(160, 12, `MPPT ${moduleId} DC Energy`, dcEnergyRaw, 'acc32');
|
|
758
|
+
const timestampRaw = this.extractValue(buffer, moduleOffset + 14, 'uint32', 2);
|
|
759
|
+
this.logRegisterRead(160, 14, `MPPT ${moduleId} Timestamp`, timestampRaw, 'uint32');
|
|
760
|
+
this.logRegisterRead(160, 17, `MPPT ${moduleId} Operating State`, dcst, 'enum16');
|
|
761
|
+
return {
|
|
762
|
+
blockNumber: 160,
|
|
763
|
+
blockAddress: model.address,
|
|
764
|
+
blockLength: model.length,
|
|
765
|
+
id: id,
|
|
766
|
+
stringId: idString,
|
|
767
|
+
dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', `MPPT ${moduleId} DC Current`, 9, 160),
|
|
768
|
+
dcCurrentSF: scaleFactors.DCA_SF,
|
|
769
|
+
dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', `MPPT ${moduleId} DC Voltage`, 10, 160),
|
|
770
|
+
dcVoltageSF: scaleFactors.DCV_SF,
|
|
771
|
+
dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'uint16', `MPPT ${moduleId} DC Power`, 11, 160),
|
|
772
|
+
dcPowerSF: scaleFactors.DCW_SF,
|
|
773
|
+
dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'acc32')
|
|
774
|
+
? dcEnergyRaw * Math.pow(10, scaleFactors.DCWH_SF)
|
|
775
|
+
: undefined,
|
|
776
|
+
dcEnergySF: scaleFactors.DCWH_SF,
|
|
777
|
+
timestamp: timestampRaw,
|
|
778
|
+
temperature: this.applyScaleFactor(temperatureRaw, temperatureScaleFactor, 'int16', `MPPT ${moduleId} Temperature`, 16, 160),
|
|
779
|
+
temperatureSF: temperatureScaleFactor,
|
|
780
|
+
operatingState: dcst,
|
|
781
|
+
};
|
|
782
|
+
}
|
|
698
783
|
/**
|
|
699
784
|
* Read MPPT data from Model 160
|
|
700
785
|
*/
|
|
@@ -704,68 +789,11 @@ export class SunspecModbusClient {
|
|
|
704
789
|
console.log('MPPT model 160 not found');
|
|
705
790
|
return null;
|
|
706
791
|
}
|
|
707
|
-
const baseAddr = model.address;
|
|
708
792
|
try {
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
const moduleAddr = baseAddr + fixedBlockScaleFactorsOffset + offset;
|
|
714
|
-
// Read scale factors using dedicated method
|
|
715
|
-
const scaleFactors = await this.readMPPTScaleFactors();
|
|
716
|
-
if (!scaleFactors) {
|
|
717
|
-
console.error(`Failed to read scale factors for MPPT module ${moduleId}`);
|
|
718
|
-
return null;
|
|
719
|
-
}
|
|
720
|
-
const id = await this.readRegisterValue(moduleAddr, 1, 'uint16');
|
|
721
|
-
const idString = await this.readRegisterValue(moduleAddr + 1, 8, 'string');
|
|
722
|
-
const dcCurrentRaw = await this.readRegisterValue(moduleAddr + 9, 1, 'uint16');
|
|
723
|
-
const dcVoltageRaw = await this.readRegisterValue(moduleAddr + 10, 1, 'uint16');
|
|
724
|
-
const dcPowerRaw = await this.readRegisterValue(moduleAddr + 11, 1, 'uint16');
|
|
725
|
-
const dcEnergyRaw = await this.readRegisterValue(moduleAddr + 12, 2, 'uint32');
|
|
726
|
-
const temperatureRaw = await this.readRegisterValue(moduleAddr + 16, 1, 'int16');
|
|
727
|
-
const dcst = await this.readRegisterValue(moduleAddr + 17, 1, 'uint16');
|
|
728
|
-
this.logRegisterRead(160, 0, `MPPT ${moduleId} ID`, id, 'uint16');
|
|
729
|
-
this.logRegisterRead(160, 1, `MPPT ${moduleId} String ID`, idString, 'string');
|
|
730
|
-
// Map the DC module state to human-readable name
|
|
731
|
-
// Check if this module is actually implemented/connected
|
|
732
|
-
// If all key values are unimplemented, this module doesn't exist
|
|
733
|
-
if (this.isUnimplementedValue(id, 'uint16') &&
|
|
734
|
-
this.isUnimplementedValue(dcCurrentRaw, 'uint16') &&
|
|
735
|
-
this.isUnimplementedValue(dcVoltageRaw, 'uint16') &&
|
|
736
|
-
this.isUnimplementedValue(dcPowerRaw, 'uint16')) {
|
|
737
|
-
console.log(`MPPT module ${moduleId} appears to be unconnected (all values are 0xFFFF)`);
|
|
738
|
-
return null;
|
|
739
|
-
}
|
|
740
|
-
// Note: There appears to be a temperature scale factor in the original model,
|
|
741
|
-
// but it's not in the current register map. We'll apply a default scale factor.
|
|
742
|
-
const temperatureScaleFactor = -1; // Common default for temperature readings
|
|
743
|
-
this.logRegisterRead(160, 12, `MPPT ${moduleId} DC Energy`, dcEnergyRaw, 'acc32');
|
|
744
|
-
const timestampRaw = await this.readRegisterValue(moduleAddr + 14, 2, 'uint32');
|
|
745
|
-
this.logRegisterRead(160, 14, `MPPT ${moduleId} Timestamp`, timestampRaw, 'uint32');
|
|
746
|
-
this.logRegisterRead(160, 17, `MPPT ${moduleId} Operating State`, dcst, 'enum16');
|
|
747
|
-
const data = {
|
|
748
|
-
blockNumber: 160,
|
|
749
|
-
blockAddress: model.address,
|
|
750
|
-
blockLength: model.length,
|
|
751
|
-
id: id,
|
|
752
|
-
stringId: idString,
|
|
753
|
-
dcCurrent: this.applyScaleFactor(dcCurrentRaw, scaleFactors.DCA_SF, 'uint16', `MPPT ${moduleId} DC Current`, 9, 160),
|
|
754
|
-
dcCurrentSF: scaleFactors.DCA_SF,
|
|
755
|
-
dcVoltage: this.applyScaleFactor(dcVoltageRaw, scaleFactors.DCV_SF, 'uint16', `MPPT ${moduleId} DC Voltage`, 10, 160),
|
|
756
|
-
dcVoltageSF: scaleFactors.DCV_SF,
|
|
757
|
-
dcPower: this.applyScaleFactor(dcPowerRaw, scaleFactors.DCW_SF, 'uint16', `MPPT ${moduleId} DC Power`, 11, 160),
|
|
758
|
-
dcPowerSF: scaleFactors.DCW_SF,
|
|
759
|
-
dcEnergy: !this.isUnimplementedValue(dcEnergyRaw, 'acc32')
|
|
760
|
-
? dcEnergyRaw * Math.pow(10, scaleFactors.DCWH_SF)
|
|
761
|
-
: undefined,
|
|
762
|
-
dcEnergySF: scaleFactors.DCWH_SF,
|
|
763
|
-
timestamp: timestampRaw,
|
|
764
|
-
temperature: this.applyScaleFactor(temperatureRaw, temperatureScaleFactor, 'int16', `MPPT ${moduleId} Temperature`, 16, 160),
|
|
765
|
-
temperatureSF: temperatureScaleFactor,
|
|
766
|
-
operatingState: dcst,
|
|
767
|
-
};
|
|
768
|
-
return data;
|
|
793
|
+
// Read entire model block in a single Modbus call
|
|
794
|
+
const buffer = await this.readModelBlock(model);
|
|
795
|
+
const scaleFactors = this.extractMPPTScaleFactors(buffer);
|
|
796
|
+
return this.extractMPPTModuleData(buffer, model, moduleId, scaleFactors);
|
|
769
797
|
}
|
|
770
798
|
catch (error) {
|
|
771
799
|
console.error(`Error reading MPPT data for module ${moduleId}: ${error}`);
|
|
@@ -777,24 +805,18 @@ export class SunspecModbusClient {
|
|
|
777
805
|
*/
|
|
778
806
|
async readAllMPPTData() {
|
|
779
807
|
const mpptData = [];
|
|
780
|
-
// Find the MPPT model first
|
|
781
808
|
const model = this.findModel(SunspecModelId.MPPT);
|
|
782
809
|
if (!model) {
|
|
783
810
|
console.log('MPPT model 160 not found');
|
|
784
811
|
return [];
|
|
785
812
|
}
|
|
786
|
-
const scaleFactors = await this.readMPPTScaleFactors();
|
|
787
|
-
if (!scaleFactors) {
|
|
788
|
-
console.error(`Failed to read scale factors for MPPT`);
|
|
789
|
-
return [];
|
|
790
|
-
}
|
|
791
|
-
// Read the module count from register 8
|
|
792
|
-
let moduleCount = 4; // Default fallback value
|
|
793
813
|
try {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
const
|
|
797
|
-
//
|
|
814
|
+
// Read entire model block in a single Modbus call
|
|
815
|
+
const buffer = await this.readModelBlock(model);
|
|
816
|
+
const scaleFactors = this.extractMPPTScaleFactors(buffer);
|
|
817
|
+
// Read the module count from register 8
|
|
818
|
+
let moduleCount = 4; // Default fallback value
|
|
819
|
+
const count = this.extractValue(buffer, 8, 'uint16');
|
|
798
820
|
if (!this.isUnimplementedValue(count, 'uint16') && count > 0 && count <= 20) {
|
|
799
821
|
moduleCount = count;
|
|
800
822
|
console.log(`MPPT module count from register 8: ${moduleCount}`);
|
|
@@ -802,27 +824,25 @@ export class SunspecModbusClient {
|
|
|
802
824
|
else {
|
|
803
825
|
console.log(`Invalid or unimplemented module count (${count}), using default: ${moduleCount}`);
|
|
804
826
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
mpptData.push(data);
|
|
827
|
+
// Extract each MPPT module from the same buffer
|
|
828
|
+
for (let i = 1; i <= moduleCount; i++) {
|
|
829
|
+
try {
|
|
830
|
+
const data = this.extractMPPTModuleData(buffer, model, i, scaleFactors);
|
|
831
|
+
console.log(`MPPT ${i} has id ${data?.id} (${data?.stringId}) with ${data?.dcPower}W`);
|
|
832
|
+
if (data &&
|
|
833
|
+
(data.dcCurrent !== undefined ||
|
|
834
|
+
data.dcVoltage !== undefined ||
|
|
835
|
+
data.dcPower !== undefined)) {
|
|
836
|
+
mpptData.push(data);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
catch (error) {
|
|
840
|
+
console.debug(`Could not read MPPT module ${i}: ${error}`);
|
|
820
841
|
}
|
|
821
842
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
843
|
+
}
|
|
844
|
+
catch (error) {
|
|
845
|
+
console.error(`Error reading all MPPT data: ${error}`);
|
|
826
846
|
}
|
|
827
847
|
return mpptData;
|
|
828
848
|
}
|
|
@@ -919,22 +939,22 @@ export class SunspecModbusClient {
|
|
|
919
939
|
}
|
|
920
940
|
}
|
|
921
941
|
/**
|
|
922
|
-
*
|
|
942
|
+
* Extract Model 802 scale factors from a pre-read buffer (offsets 52-63)
|
|
923
943
|
*/
|
|
924
|
-
|
|
944
|
+
extractBatteryBaseScaleFactors(buffer) {
|
|
925
945
|
const scaleFactors = {
|
|
926
|
-
AHRtg_SF:
|
|
927
|
-
WHRtg_SF:
|
|
928
|
-
WChaDisChaMax_SF:
|
|
929
|
-
DisChaRte_SF:
|
|
930
|
-
SoC_SF:
|
|
931
|
-
DoD_SF:
|
|
932
|
-
SoH_SF:
|
|
933
|
-
V_SF:
|
|
934
|
-
CellV_SF:
|
|
935
|
-
A_SF:
|
|
936
|
-
AMax_SF:
|
|
937
|
-
W_SF:
|
|
946
|
+
AHRtg_SF: this.extractValue(buffer, 52, 'int16'),
|
|
947
|
+
WHRtg_SF: this.extractValue(buffer, 53, 'int16'),
|
|
948
|
+
WChaDisChaMax_SF: this.extractValue(buffer, 54, 'int16'),
|
|
949
|
+
DisChaRte_SF: this.extractValue(buffer, 55, 'int16'),
|
|
950
|
+
SoC_SF: this.extractValue(buffer, 56, 'int16'),
|
|
951
|
+
DoD_SF: this.extractValue(buffer, 57, 'int16'),
|
|
952
|
+
SoH_SF: this.extractValue(buffer, 58, 'int16'),
|
|
953
|
+
V_SF: this.extractValue(buffer, 59, 'int16'),
|
|
954
|
+
CellV_SF: this.extractValue(buffer, 60, 'int16'),
|
|
955
|
+
A_SF: this.extractValue(buffer, 61, 'int16'),
|
|
956
|
+
AMax_SF: this.extractValue(buffer, 62, 'int16'),
|
|
957
|
+
W_SF: this.extractValue(buffer, 63, 'int16'),
|
|
938
958
|
};
|
|
939
959
|
this.logRegisterRead(802, 52, 'AHRtg_SF', scaleFactors.AHRtg_SF, 'int16');
|
|
940
960
|
this.logRegisterRead(802, 53, 'WHRtg_SF', scaleFactors.WHRtg_SF, 'int16');
|
|
@@ -959,51 +979,52 @@ export class SunspecModbusClient {
|
|
|
959
979
|
console.log('Battery Base model 802 not found');
|
|
960
980
|
return null;
|
|
961
981
|
}
|
|
962
|
-
|
|
963
|
-
console.log(`Reading Battery Base Data from Model 802 at base address: ${baseAddr}`);
|
|
982
|
+
console.log(`Reading Battery Base Data from Model 802 at base address: ${model.address}`);
|
|
964
983
|
try {
|
|
965
|
-
// Read
|
|
966
|
-
const
|
|
967
|
-
//
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
const
|
|
972
|
-
const
|
|
973
|
-
const
|
|
974
|
-
const
|
|
975
|
-
const
|
|
976
|
-
const
|
|
977
|
-
const
|
|
978
|
-
const
|
|
979
|
-
const
|
|
980
|
-
const
|
|
981
|
-
const
|
|
982
|
-
const
|
|
983
|
-
const
|
|
984
|
-
const
|
|
985
|
-
const
|
|
986
|
-
const
|
|
987
|
-
const
|
|
988
|
-
const
|
|
989
|
-
const
|
|
990
|
-
const
|
|
991
|
-
const
|
|
992
|
-
const
|
|
993
|
-
const
|
|
994
|
-
const
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
const
|
|
999
|
-
const
|
|
1000
|
-
const
|
|
1001
|
-
const
|
|
1002
|
-
const
|
|
1003
|
-
const
|
|
1004
|
-
const
|
|
1005
|
-
const
|
|
1006
|
-
const
|
|
984
|
+
// Read entire model block in a single Modbus call
|
|
985
|
+
const buffer = await this.readModelBlock(model);
|
|
986
|
+
// Extract scale factors from buffer (offsets 52-63)
|
|
987
|
+
const sf = this.extractBatteryBaseScaleFactors(buffer);
|
|
988
|
+
// Extract raw values from buffer
|
|
989
|
+
const ahRtgRaw = this.extractValue(buffer, 2, 'uint16');
|
|
990
|
+
const whRtgRaw = this.extractValue(buffer, 3, 'uint16');
|
|
991
|
+
const wChaRteMaxRaw = this.extractValue(buffer, 4, 'uint16');
|
|
992
|
+
const wDisChaRteMaxRaw = this.extractValue(buffer, 5, 'uint16');
|
|
993
|
+
const disChaRteRaw = this.extractValue(buffer, 6, 'uint16');
|
|
994
|
+
const soCMaxRaw = this.extractValue(buffer, 7, 'uint16');
|
|
995
|
+
const soCMinRaw = this.extractValue(buffer, 8, 'uint16');
|
|
996
|
+
const soCRsvMaxRaw = this.extractValue(buffer, 9, 'uint16');
|
|
997
|
+
const soCRsvMinRaw = this.extractValue(buffer, 10, 'uint16');
|
|
998
|
+
const soCRaw = this.extractValue(buffer, 11, 'uint16');
|
|
999
|
+
const doDRaw = this.extractValue(buffer, 12, 'uint16');
|
|
1000
|
+
const soHRaw = this.extractValue(buffer, 13, 'uint16');
|
|
1001
|
+
const nCycRaw = this.extractValue(buffer, 14, 'uint32', 2);
|
|
1002
|
+
const chaStRaw = this.extractValue(buffer, 16, 'uint16');
|
|
1003
|
+
const locRemCtlRaw = this.extractValue(buffer, 17, 'uint16');
|
|
1004
|
+
const typRaw = this.extractValue(buffer, 21, 'uint16');
|
|
1005
|
+
const stateRaw = this.extractValue(buffer, 22, 'uint16');
|
|
1006
|
+
const evt1Raw = this.extractValue(buffer, 26, 'uint32', 2);
|
|
1007
|
+
const evt2Raw = this.extractValue(buffer, 28, 'uint32', 2);
|
|
1008
|
+
const evtVnd1Raw = this.extractValue(buffer, 30, 'uint32', 2);
|
|
1009
|
+
const evtVnd2Raw = this.extractValue(buffer, 32, 'uint32', 2);
|
|
1010
|
+
const vRaw = this.extractValue(buffer, 34, 'uint16');
|
|
1011
|
+
const vMaxRaw = this.extractValue(buffer, 35, 'uint16');
|
|
1012
|
+
const vMinRaw = this.extractValue(buffer, 36, 'uint16');
|
|
1013
|
+
const cellVMaxRaw = this.extractValue(buffer, 37, 'uint16');
|
|
1014
|
+
const cellVMaxStrRaw = this.extractValue(buffer, 38, 'uint16');
|
|
1015
|
+
const cellVMaxModRaw = this.extractValue(buffer, 39, 'uint16');
|
|
1016
|
+
const cellVMinRaw = this.extractValue(buffer, 40, 'uint16');
|
|
1017
|
+
const cellVMinStrRaw = this.extractValue(buffer, 41, 'uint16');
|
|
1018
|
+
const cellVMinModRaw = this.extractValue(buffer, 42, 'uint16');
|
|
1019
|
+
const cellVAvgRaw = this.extractValue(buffer, 43, 'uint16');
|
|
1020
|
+
const aRaw = this.extractValue(buffer, 44, 'int16');
|
|
1021
|
+
const aChaMaxRaw = this.extractValue(buffer, 45, 'uint16');
|
|
1022
|
+
const aDisChaMaxRaw = this.extractValue(buffer, 46, 'uint16');
|
|
1023
|
+
const wRaw = this.extractValue(buffer, 47, 'int16');
|
|
1024
|
+
const reqInvStateRaw = this.extractValue(buffer, 48, 'uint16');
|
|
1025
|
+
const reqWRaw = this.extractValue(buffer, 49, 'int16');
|
|
1026
|
+
const setOpRaw = this.extractValue(buffer, 50, 'uint16');
|
|
1027
|
+
const setInvStateRaw = this.extractValue(buffer, 51, 'uint16');
|
|
1007
1028
|
// Map enum fields
|
|
1008
1029
|
const chaStName = this.mapBatteryChargeState(chaStRaw);
|
|
1009
1030
|
const typName = this.mapBatteryType(typRaw);
|
|
@@ -1103,22 +1124,23 @@ export class SunspecModbusClient {
|
|
|
1103
1124
|
console.log('No battery model found');
|
|
1104
1125
|
return null;
|
|
1105
1126
|
}
|
|
1106
|
-
|
|
1107
|
-
console.log(`Reading Battery Data from Model ${model.id} at base address: ${baseAddr}`);
|
|
1127
|
+
console.log(`Reading Battery Data from Model ${model.id} at base address: ${model.address}`);
|
|
1108
1128
|
try {
|
|
1109
1129
|
if (model.id === 124) {
|
|
1110
1130
|
// Model 124: Basic Storage Controls
|
|
1111
1131
|
console.log('Using Model 124 (Basic Storage Controls)');
|
|
1112
|
-
// Read
|
|
1132
|
+
// Read entire model block in a single Modbus call
|
|
1133
|
+
const buffer = await this.readModelBlock(model);
|
|
1134
|
+
// Extract scale factors from buffer (offsets 18-25)
|
|
1113
1135
|
const scaleFactors = {
|
|
1114
|
-
WChaMax_SF:
|
|
1115
|
-
WChaDisChaGra_SF:
|
|
1116
|
-
VAChaMax_SF:
|
|
1117
|
-
MinRsvPct_SF:
|
|
1118
|
-
ChaState_SF:
|
|
1119
|
-
StorAval_SF:
|
|
1120
|
-
InBatV_SF:
|
|
1121
|
-
InOutWRte_SF:
|
|
1136
|
+
WChaMax_SF: this.extractValue(buffer, 18, 'int16'),
|
|
1137
|
+
WChaDisChaGra_SF: this.extractValue(buffer, 19, 'int16'),
|
|
1138
|
+
VAChaMax_SF: this.extractValue(buffer, 20, 'int16'),
|
|
1139
|
+
MinRsvPct_SF: this.extractValue(buffer, 21, 'int16'),
|
|
1140
|
+
ChaState_SF: this.extractValue(buffer, 22, 'int16'),
|
|
1141
|
+
StorAval_SF: this.extractValue(buffer, 23, 'int16'),
|
|
1142
|
+
InBatV_SF: this.extractValue(buffer, 24, 'int16'),
|
|
1143
|
+
InOutWRte_SF: this.extractValue(buffer, 25, 'int16')
|
|
1122
1144
|
};
|
|
1123
1145
|
this.logRegisterRead(124, 18, 'WChaMax_SF', scaleFactors.WChaMax_SF, 'int16');
|
|
1124
1146
|
this.logRegisterRead(124, 19, 'WChaDisChaGra_SF', scaleFactors.WChaDisChaGra_SF, 'int16');
|
|
@@ -1128,23 +1150,23 @@ export class SunspecModbusClient {
|
|
|
1128
1150
|
this.logRegisterRead(124, 23, 'StorAval_SF', scaleFactors.StorAval_SF, 'int16');
|
|
1129
1151
|
this.logRegisterRead(124, 24, 'InBatV_SF', scaleFactors.InBatV_SF, 'int16');
|
|
1130
1152
|
this.logRegisterRead(124, 25, 'InOutWRte_SF', scaleFactors.InOutWRte_SF, 'int16');
|
|
1131
|
-
//
|
|
1132
|
-
const wChaMaxRaw =
|
|
1133
|
-
const wChaGraRaw =
|
|
1134
|
-
const wDisChaGraRaw =
|
|
1135
|
-
const storCtlModRaw =
|
|
1136
|
-
const vaChaMaxRaw =
|
|
1137
|
-
const minRsvPctRaw =
|
|
1138
|
-
const chaStateRaw =
|
|
1139
|
-
const storAvalRaw =
|
|
1140
|
-
const inBatVRaw =
|
|
1141
|
-
const chaStRaw =
|
|
1142
|
-
const outWRteRaw =
|
|
1143
|
-
const inWRteRaw =
|
|
1144
|
-
const inOutWRteWinTmsRaw =
|
|
1145
|
-
const inOutWRteRvrtTmsRaw =
|
|
1146
|
-
const inOutWRteRmpTmsRaw =
|
|
1147
|
-
const chaGriSetRaw =
|
|
1153
|
+
// Extract raw values from buffer
|
|
1154
|
+
const wChaMaxRaw = this.extractValue(buffer, 2, 'uint16');
|
|
1155
|
+
const wChaGraRaw = this.extractValue(buffer, 3, 'uint16');
|
|
1156
|
+
const wDisChaGraRaw = this.extractValue(buffer, 4, 'uint16');
|
|
1157
|
+
const storCtlModRaw = this.extractValue(buffer, 5, 'uint16');
|
|
1158
|
+
const vaChaMaxRaw = this.extractValue(buffer, 6, 'uint16');
|
|
1159
|
+
const minRsvPctRaw = this.extractValue(buffer, 7, 'uint16');
|
|
1160
|
+
const chaStateRaw = this.extractValue(buffer, 8, 'uint16');
|
|
1161
|
+
const storAvalRaw = this.extractValue(buffer, 9, 'uint16');
|
|
1162
|
+
const inBatVRaw = this.extractValue(buffer, 10, 'uint16');
|
|
1163
|
+
const chaStRaw = this.extractValue(buffer, 11, 'uint16');
|
|
1164
|
+
const outWRteRaw = this.extractValue(buffer, 12, 'int16');
|
|
1165
|
+
const inWRteRaw = this.extractValue(buffer, 13, 'int16');
|
|
1166
|
+
const inOutWRteWinTmsRaw = this.extractValue(buffer, 14, 'uint16');
|
|
1167
|
+
const inOutWRteRvrtTmsRaw = this.extractValue(buffer, 15, 'uint16');
|
|
1168
|
+
const inOutWRteRmpTmsRaw = this.extractValue(buffer, 16, 'uint16');
|
|
1169
|
+
const chaGriSetRaw = this.extractValue(buffer, 17, 'uint16');
|
|
1148
1170
|
// Map charge state and log non-scaled fields
|
|
1149
1171
|
const chaStName = this.mapBatteryChargeState(chaStRaw);
|
|
1150
1172
|
this.logRegisterRead(124, 5, 'storCtlMod', storCtlModRaw, 'bitfield16');
|
|
@@ -1363,25 +1385,26 @@ export class SunspecModbusClient {
|
|
|
1363
1385
|
console.log('Battery model 124 not found');
|
|
1364
1386
|
return null;
|
|
1365
1387
|
}
|
|
1366
|
-
|
|
1367
|
-
console.log(`Reading Battery Controls from Model 124 at base address: ${baseAddr}`);
|
|
1388
|
+
console.log(`Reading Battery Controls from Model 124 at base address: ${model.address}`);
|
|
1368
1389
|
try {
|
|
1369
|
-
// Read
|
|
1390
|
+
// Read entire model block in a single Modbus call
|
|
1391
|
+
const buffer = await this.readModelBlock(model);
|
|
1392
|
+
// Extract scale factors from buffer
|
|
1370
1393
|
const scaleFactors = {
|
|
1371
|
-
WChaMax_SF:
|
|
1372
|
-
MinRsvPct_SF:
|
|
1373
|
-
InOutWRte_SF:
|
|
1394
|
+
WChaMax_SF: this.extractValue(buffer, 18, 'int16'),
|
|
1395
|
+
MinRsvPct_SF: this.extractValue(buffer, 21, 'int16'),
|
|
1396
|
+
InOutWRte_SF: this.extractValue(buffer, 25, 'int16')
|
|
1374
1397
|
};
|
|
1375
1398
|
this.logRegisterRead(124, 18, 'WChaMax_SF', scaleFactors.WChaMax_SF, 'int16');
|
|
1376
1399
|
this.logRegisterRead(124, 21, 'MinRsvPct_SF', scaleFactors.MinRsvPct_SF, 'int16');
|
|
1377
1400
|
this.logRegisterRead(124, 25, 'InOutWRte_SF', scaleFactors.InOutWRte_SF, 'int16');
|
|
1378
|
-
//
|
|
1379
|
-
const wChaMaxRaw =
|
|
1380
|
-
const storCtlModRaw =
|
|
1381
|
-
const minRsvPctRaw =
|
|
1382
|
-
const outWRteRaw =
|
|
1383
|
-
const inWRteRaw =
|
|
1384
|
-
const chaGriSetRaw =
|
|
1401
|
+
// Extract raw values from buffer
|
|
1402
|
+
const wChaMaxRaw = this.extractValue(buffer, 2, 'uint16');
|
|
1403
|
+
const storCtlModRaw = this.extractValue(buffer, 5, 'uint16');
|
|
1404
|
+
const minRsvPctRaw = this.extractValue(buffer, 7, 'uint16');
|
|
1405
|
+
const outWRteRaw = this.extractValue(buffer, 12, 'int16');
|
|
1406
|
+
const inWRteRaw = this.extractValue(buffer, 13, 'int16');
|
|
1407
|
+
const chaGriSetRaw = this.extractValue(buffer, 17, 'uint16');
|
|
1385
1408
|
this.logRegisterRead(124, 5, 'storCtlMod', storCtlModRaw, 'bitfield16');
|
|
1386
1409
|
this.logRegisterRead(124, 17, 'chaGriSet', chaGriSetRaw, 'enum16');
|
|
1387
1410
|
// Apply scale factors and return control settings
|
|
@@ -1414,8 +1437,7 @@ export class SunspecModbusClient {
|
|
|
1414
1437
|
console.log('No meter model found');
|
|
1415
1438
|
return null;
|
|
1416
1439
|
}
|
|
1417
|
-
|
|
1418
|
-
console.log(`Reading Meter Data from Model ${model.id} at base address: ${baseAddr}`);
|
|
1440
|
+
console.log(`Reading Meter Data from Model ${model.id} at base address: ${model.address}`);
|
|
1419
1441
|
try {
|
|
1420
1442
|
// Different meter models have different register offsets
|
|
1421
1443
|
console.log(`Meter is Model ${model.id}`);
|
|
@@ -1458,18 +1480,20 @@ export class SunspecModbusClient {
|
|
|
1458
1480
|
importOffset = 46; // TotWhImp - Total Wh Imported (acc32)
|
|
1459
1481
|
energySFOffset = 54; // TotWh_SF - Total Energy scale factor
|
|
1460
1482
|
}
|
|
1461
|
-
// Read
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1464
|
-
const
|
|
1483
|
+
// Read entire model block in a single Modbus call
|
|
1484
|
+
const buffer = await this.readModelBlock(model);
|
|
1485
|
+
// Extract scale factors from buffer
|
|
1486
|
+
const powerSF = this.extractValue(buffer, powerSFOffset, 'int16');
|
|
1487
|
+
const freqSF = this.extractValue(buffer, freqSFOffset, 'int16');
|
|
1488
|
+
const energySF = this.extractValue(buffer, energySFOffset, 'int16');
|
|
1465
1489
|
this.logRegisterRead(model.id, powerSFOffset, 'W_SF', powerSF, 'int16');
|
|
1466
1490
|
this.logRegisterRead(model.id, freqSFOffset, 'Hz_SF', freqSF, 'int16');
|
|
1467
1491
|
this.logRegisterRead(model.id, energySFOffset, 'TotWh_SF', energySF, 'int16');
|
|
1468
|
-
//
|
|
1469
|
-
const powerRaw =
|
|
1470
|
-
const freqRaw =
|
|
1471
|
-
const exportRaw =
|
|
1472
|
-
const importRaw =
|
|
1492
|
+
// Extract raw values from buffer
|
|
1493
|
+
const powerRaw = this.extractValue(buffer, powerOffset, 'int16');
|
|
1494
|
+
const freqRaw = this.extractValue(buffer, freqOffset, 'uint16');
|
|
1495
|
+
const exportRaw = this.extractValue(buffer, exportOffset, 'uint32', 2);
|
|
1496
|
+
const importRaw = this.extractValue(buffer, importOffset, 'uint32', 2);
|
|
1473
1497
|
this.logRegisterRead(model.id, exportOffset, 'TotWhExp', exportRaw, 'acc32');
|
|
1474
1498
|
this.logRegisterRead(model.id, importOffset, 'TotWhImp', importRaw, 'acc32');
|
|
1475
1499
|
// Calculate final values with scale factors
|
|
@@ -1499,28 +1523,26 @@ export class SunspecModbusClient {
|
|
|
1499
1523
|
console.error('Common block model not found');
|
|
1500
1524
|
return null;
|
|
1501
1525
|
}
|
|
1502
|
-
|
|
1503
|
-
console.log(`Reading Common Block - Model address: ${model.address}, Base address for data: ${baseAddr}`);
|
|
1526
|
+
console.log(`Reading Common Block - Model address: ${model.address}`);
|
|
1504
1527
|
try {
|
|
1505
|
-
// Read
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
const
|
|
1513
|
-
const manufacturer = await this.readRegisterValue(manufacturerAddr, 16, 'string');
|
|
1528
|
+
// Read entire model block in a single Modbus call
|
|
1529
|
+
const buffer = await this.readModelBlock(model);
|
|
1530
|
+
// Common block offsets are relative to the model start (after ID and Length header,
|
|
1531
|
+
// but readModelBlock reads from model.address which includes the data area).
|
|
1532
|
+
// The offsets below are relative to the data start within the model block.
|
|
1533
|
+
// Since model.address points to the first data register (after the 2-register header
|
|
1534
|
+
// is already accounted for in model discovery), offset 0 = first data register.
|
|
1535
|
+
const manufacturer = this.extractValue(buffer, 2, 'string', 16);
|
|
1514
1536
|
this.logRegisterRead(1, 0, 'Manufacturer', manufacturer, 'string');
|
|
1515
|
-
const modelName =
|
|
1537
|
+
const modelName = this.extractValue(buffer, 18, 'string', 16);
|
|
1516
1538
|
this.logRegisterRead(1, 16, 'Model', modelName, 'string');
|
|
1517
|
-
const options =
|
|
1539
|
+
const options = this.extractValue(buffer, 34, 'string', 8);
|
|
1518
1540
|
this.logRegisterRead(1, 32, 'Options', options, 'string');
|
|
1519
|
-
const version =
|
|
1541
|
+
const version = this.extractValue(buffer, 42, 'string', 8);
|
|
1520
1542
|
this.logRegisterRead(1, 40, 'Version', version, 'string');
|
|
1521
|
-
const serialNumber =
|
|
1543
|
+
const serialNumber = this.extractValue(buffer, 50, 'string', 16);
|
|
1522
1544
|
this.logRegisterRead(1, 48, 'Serial Number', serialNumber, 'string');
|
|
1523
|
-
const deviceAddress =
|
|
1545
|
+
const deviceAddress = this.extractValue(buffer, 66, 'uint16');
|
|
1524
1546
|
this.logRegisterRead(1, 64, 'Device Address', deviceAddress, 'uint16');
|
|
1525
1547
|
return {
|
|
1526
1548
|
manufacturer,
|
|
@@ -1570,20 +1592,21 @@ export class SunspecModbusClient {
|
|
|
1570
1592
|
console.log('Settings model 121 not found');
|
|
1571
1593
|
return null;
|
|
1572
1594
|
}
|
|
1573
|
-
const baseAddr = model.address;
|
|
1574
1595
|
try {
|
|
1575
|
-
// Read
|
|
1596
|
+
// Read entire model block in a single Modbus call
|
|
1597
|
+
const buffer = await this.readModelBlock(model);
|
|
1598
|
+
// Extract scale factors from buffer (offsets 22-31)
|
|
1576
1599
|
const scaleFactors = {
|
|
1577
|
-
WMax_SF:
|
|
1578
|
-
VRef_SF:
|
|
1579
|
-
VRefOfs_SF:
|
|
1580
|
-
VMinMax_SF:
|
|
1581
|
-
VAMax_SF:
|
|
1582
|
-
VArMax_SF:
|
|
1583
|
-
WGra_SF:
|
|
1584
|
-
PFMin_SF:
|
|
1585
|
-
MaxRmpRte_SF:
|
|
1586
|
-
ECPNomHz_SF:
|
|
1600
|
+
WMax_SF: this.extractValue(buffer, 22, 'int16'),
|
|
1601
|
+
VRef_SF: this.extractValue(buffer, 23, 'int16'),
|
|
1602
|
+
VRefOfs_SF: this.extractValue(buffer, 24, 'int16'),
|
|
1603
|
+
VMinMax_SF: this.extractValue(buffer, 25, 'int16'),
|
|
1604
|
+
VAMax_SF: this.extractValue(buffer, 26, 'int16'),
|
|
1605
|
+
VArMax_SF: this.extractValue(buffer, 27, 'int16'),
|
|
1606
|
+
WGra_SF: this.extractValue(buffer, 28, 'int16'),
|
|
1607
|
+
PFMin_SF: this.extractValue(buffer, 29, 'int16'),
|
|
1608
|
+
MaxRmpRte_SF: this.extractValue(buffer, 30, 'int16'),
|
|
1609
|
+
ECPNomHz_SF: this.extractValue(buffer, 31, 'int16')
|
|
1587
1610
|
};
|
|
1588
1611
|
this.logRegisterRead(121, 22, 'WMax_SF', scaleFactors.WMax_SF, 'int16');
|
|
1589
1612
|
this.logRegisterRead(121, 23, 'VRef_SF', scaleFactors.VRef_SF, 'int16');
|
|
@@ -1595,10 +1618,10 @@ export class SunspecModbusClient {
|
|
|
1595
1618
|
this.logRegisterRead(121, 29, 'PFMin_SF', scaleFactors.PFMin_SF, 'int16');
|
|
1596
1619
|
this.logRegisterRead(121, 30, 'MaxRmpRte_SF', scaleFactors.MaxRmpRte_SF, 'int16');
|
|
1597
1620
|
this.logRegisterRead(121, 31, 'ECPNomHz_SF', scaleFactors.ECPNomHz_SF, 'int16');
|
|
1598
|
-
//
|
|
1599
|
-
const vArActRaw =
|
|
1600
|
-
const clcTotVARaw =
|
|
1601
|
-
const connPhRaw =
|
|
1621
|
+
// Extract non-scaled fields from buffer
|
|
1622
|
+
const vArActRaw = this.extractValue(buffer, 17, 'uint16');
|
|
1623
|
+
const clcTotVARaw = this.extractValue(buffer, 18, 'uint16');
|
|
1624
|
+
const connPhRaw = this.extractValue(buffer, 21, 'uint16');
|
|
1602
1625
|
this.logRegisterRead(121, 17, 'VArAct', vArActRaw, 'enum16');
|
|
1603
1626
|
this.logRegisterRead(121, 18, 'ClcTotVA', clcTotVARaw, 'enum16');
|
|
1604
1627
|
this.logRegisterRead(121, 21, 'ConnPh', connPhRaw, 'enum16');
|
|
@@ -1607,40 +1630,40 @@ export class SunspecModbusClient {
|
|
|
1607
1630
|
blockAddress: model.address,
|
|
1608
1631
|
blockLength: model.length,
|
|
1609
1632
|
// Power settings - Offset 2
|
|
1610
|
-
WMax: this.applyScaleFactor(
|
|
1633
|
+
WMax: this.applyScaleFactor(this.extractValue(buffer, 2, 'uint16'), scaleFactors.WMax_SF, 'uint16', 'Max Power', 2, 121),
|
|
1611
1634
|
WMax_SF: scaleFactors.WMax_SF,
|
|
1612
1635
|
// Voltage settings - Offsets 3-6
|
|
1613
|
-
VRef: this.applyScaleFactor(
|
|
1636
|
+
VRef: this.applyScaleFactor(this.extractValue(buffer, 3, 'uint16'), scaleFactors.VRef_SF, 'uint16', 'Voltage Reference', 3, 121),
|
|
1614
1637
|
VRef_SF: scaleFactors.VRef_SF,
|
|
1615
|
-
VRefOfs: this.applyScaleFactor(
|
|
1638
|
+
VRefOfs: this.applyScaleFactor(this.extractValue(buffer, 4, 'int16'), scaleFactors.VRefOfs_SF, 'int16', 'Voltage Reference Offset', 4, 121),
|
|
1616
1639
|
VRefOfs_SF: scaleFactors.VRefOfs_SF,
|
|
1617
|
-
VMax: this.applyScaleFactor(
|
|
1618
|
-
VMin: this.applyScaleFactor(
|
|
1640
|
+
VMax: this.applyScaleFactor(this.extractValue(buffer, 5, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Max Voltage', 5, 121),
|
|
1641
|
+
VMin: this.applyScaleFactor(this.extractValue(buffer, 6, 'uint16'), scaleFactors.VMinMax_SF, 'uint16', 'Min Voltage', 6, 121),
|
|
1619
1642
|
VMinMax_SF: scaleFactors.VMinMax_SF,
|
|
1620
1643
|
// Apparent power settings - Offset 7
|
|
1621
|
-
VAMax: this.applyScaleFactor(
|
|
1644
|
+
VAMax: this.applyScaleFactor(this.extractValue(buffer, 7, 'uint16'), scaleFactors.VAMax_SF, 'uint16', 'Max Apparent Power', 7, 121),
|
|
1622
1645
|
VAMax_SF: scaleFactors.VAMax_SF,
|
|
1623
1646
|
// Reactive power settings - Offsets 8-11
|
|
1624
|
-
VArMaxQ1: this.applyScaleFactor(
|
|
1625
|
-
VArMaxQ2: this.applyScaleFactor(
|
|
1626
|
-
VArMaxQ3: this.applyScaleFactor(
|
|
1627
|
-
VArMaxQ4: this.applyScaleFactor(
|
|
1647
|
+
VArMaxQ1: this.applyScaleFactor(this.extractValue(buffer, 8, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q1', 8, 121),
|
|
1648
|
+
VArMaxQ2: this.applyScaleFactor(this.extractValue(buffer, 9, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q2', 9, 121),
|
|
1649
|
+
VArMaxQ3: this.applyScaleFactor(this.extractValue(buffer, 10, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q3', 10, 121),
|
|
1650
|
+
VArMaxQ4: this.applyScaleFactor(this.extractValue(buffer, 11, 'int16'), scaleFactors.VArMax_SF, 'int16', 'Max Reactive Power Q4', 11, 121),
|
|
1628
1651
|
VArMax_SF: scaleFactors.VArMax_SF,
|
|
1629
1652
|
// Ramp rate settings - Offset 12
|
|
1630
|
-
WGra: this.applyScaleFactor(
|
|
1653
|
+
WGra: this.applyScaleFactor(this.extractValue(buffer, 12, 'uint16'), scaleFactors.WGra_SF, 'uint16', 'Power Ramp Rate', 12, 121),
|
|
1631
1654
|
WGra_SF: scaleFactors.WGra_SF,
|
|
1632
1655
|
// Power factor settings - Offsets 13-16
|
|
1633
|
-
PFMinQ1: this.applyScaleFactor(
|
|
1634
|
-
PFMinQ2: this.applyScaleFactor(
|
|
1635
|
-
PFMinQ3: this.applyScaleFactor(
|
|
1636
|
-
PFMinQ4: this.applyScaleFactor(
|
|
1656
|
+
PFMinQ1: this.applyScaleFactor(this.extractValue(buffer, 13, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q1', 13, 121),
|
|
1657
|
+
PFMinQ2: this.applyScaleFactor(this.extractValue(buffer, 14, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q2', 14, 121),
|
|
1658
|
+
PFMinQ3: this.applyScaleFactor(this.extractValue(buffer, 15, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q3', 15, 121),
|
|
1659
|
+
PFMinQ4: this.applyScaleFactor(this.extractValue(buffer, 16, 'int16'), scaleFactors.PFMin_SF, 'int16', 'Min Power Factor Q4', 16, 121),
|
|
1637
1660
|
PFMin_SF: scaleFactors.PFMin_SF,
|
|
1638
1661
|
// Other settings - Offsets 17-21
|
|
1639
1662
|
VArAct: vArActRaw,
|
|
1640
1663
|
ClcTotVA: clcTotVARaw,
|
|
1641
|
-
MaxRmpRte: this.applyScaleFactor(
|
|
1664
|
+
MaxRmpRte: this.applyScaleFactor(this.extractValue(buffer, 19, 'uint16'), scaleFactors.MaxRmpRte_SF, 'uint16', 'Max Ramp Rate', 19, 121),
|
|
1642
1665
|
MaxRmpRte_SF: scaleFactors.MaxRmpRte_SF,
|
|
1643
|
-
ECPNomHz: this.applyScaleFactor(
|
|
1666
|
+
ECPNomHz: this.applyScaleFactor(this.extractValue(buffer, 20, 'uint16'), scaleFactors.ECPNomHz_SF, 'uint16', 'Nominal Frequency', 20, 121),
|
|
1644
1667
|
ECPNomHz_SF: scaleFactors.ECPNomHz_SF,
|
|
1645
1668
|
ConnPh: connPhRaw
|
|
1646
1669
|
};
|
|
@@ -1659,34 +1682,35 @@ export class SunspecModbusClient {
|
|
|
1659
1682
|
console.log('Controls model 123 not found');
|
|
1660
1683
|
return null;
|
|
1661
1684
|
}
|
|
1662
|
-
const baseAddr = model.address;
|
|
1663
1685
|
try {
|
|
1664
|
-
// Read
|
|
1686
|
+
// Read entire model block in a single Modbus call
|
|
1687
|
+
const buffer = await this.readModelBlock(model);
|
|
1688
|
+
// Extract scale factors from buffer (offsets 21-23)
|
|
1665
1689
|
const scaleFactors = {
|
|
1666
|
-
WMaxLimPct_SF:
|
|
1667
|
-
OutPFSet_SF:
|
|
1668
|
-
VArPct_SF:
|
|
1690
|
+
WMaxLimPct_SF: this.extractValue(buffer, 21, 'int16'),
|
|
1691
|
+
OutPFSet_SF: this.extractValue(buffer, 22, 'int16'),
|
|
1692
|
+
VArPct_SF: this.extractValue(buffer, 23, 'int16')
|
|
1669
1693
|
};
|
|
1670
1694
|
this.logRegisterRead(123, 21, 'WMaxLimPct_SF', scaleFactors.WMaxLimPct_SF, 'int16');
|
|
1671
1695
|
this.logRegisterRead(123, 22, 'OutPFSet_SF', scaleFactors.OutPFSet_SF, 'int16');
|
|
1672
1696
|
this.logRegisterRead(123, 23, 'VArPct_SF', scaleFactors.VArPct_SF, 'int16');
|
|
1673
|
-
//
|
|
1674
|
-
const connWinTmsRaw =
|
|
1675
|
-
const connRvrtTmsRaw =
|
|
1676
|
-
const connRaw =
|
|
1677
|
-
const wMaxLimPctWinTmsRaw =
|
|
1678
|
-
const wMaxLimPctRvrtTmsRaw =
|
|
1679
|
-
const wMaxLimPctRmpTmsRaw =
|
|
1680
|
-
const wMaxLimEnaRaw =
|
|
1681
|
-
const outPFSetWinTmsRaw =
|
|
1682
|
-
const outPFSetRvrtTmsRaw =
|
|
1683
|
-
const outPFSetRmpTmsRaw =
|
|
1684
|
-
const outPFSetEnaRaw =
|
|
1685
|
-
const vArPctWinTmsRaw =
|
|
1686
|
-
const vArPctRvrtTmsRaw =
|
|
1687
|
-
const vArPctRmpTmsRaw =
|
|
1688
|
-
const vArPctModRaw =
|
|
1689
|
-
const vArPctEnaRaw =
|
|
1697
|
+
// Extract non-scaled fields from buffer
|
|
1698
|
+
const connWinTmsRaw = this.extractValue(buffer, 0, 'uint16');
|
|
1699
|
+
const connRvrtTmsRaw = this.extractValue(buffer, 1, 'uint16');
|
|
1700
|
+
const connRaw = this.extractValue(buffer, 2, 'uint16');
|
|
1701
|
+
const wMaxLimPctWinTmsRaw = this.extractValue(buffer, 4, 'uint16');
|
|
1702
|
+
const wMaxLimPctRvrtTmsRaw = this.extractValue(buffer, 5, 'uint16');
|
|
1703
|
+
const wMaxLimPctRmpTmsRaw = this.extractValue(buffer, 6, 'uint16');
|
|
1704
|
+
const wMaxLimEnaRaw = this.extractValue(buffer, 7, 'uint16');
|
|
1705
|
+
const outPFSetWinTmsRaw = this.extractValue(buffer, 9, 'uint16');
|
|
1706
|
+
const outPFSetRvrtTmsRaw = this.extractValue(buffer, 10, 'uint16');
|
|
1707
|
+
const outPFSetRmpTmsRaw = this.extractValue(buffer, 11, 'uint16');
|
|
1708
|
+
const outPFSetEnaRaw = this.extractValue(buffer, 12, 'uint16');
|
|
1709
|
+
const vArPctWinTmsRaw = this.extractValue(buffer, 16, 'uint16');
|
|
1710
|
+
const vArPctRvrtTmsRaw = this.extractValue(buffer, 17, 'uint16');
|
|
1711
|
+
const vArPctRmpTmsRaw = this.extractValue(buffer, 18, 'uint16');
|
|
1712
|
+
const vArPctModRaw = this.extractValue(buffer, 19, 'uint16');
|
|
1713
|
+
const vArPctEnaRaw = this.extractValue(buffer, 20, 'uint16');
|
|
1690
1714
|
this.logRegisterRead(123, 0, 'Conn_WinTms', connWinTmsRaw, 'uint16');
|
|
1691
1715
|
this.logRegisterRead(123, 1, 'Conn_RvrtTms', connRvrtTmsRaw, 'uint16');
|
|
1692
1716
|
this.logRegisterRead(123, 2, 'Conn', connRaw, 'enum16');
|
|
@@ -1712,23 +1736,23 @@ export class SunspecModbusClient {
|
|
|
1712
1736
|
Conn_RvrtTms: connRvrtTmsRaw,
|
|
1713
1737
|
Conn: connRaw,
|
|
1714
1738
|
// Power limit control - Offsets 3-7
|
|
1715
|
-
WMaxLimPct: this.applyScaleFactor(
|
|
1739
|
+
WMaxLimPct: this.applyScaleFactor(this.extractValue(buffer, 3, 'uint16'), scaleFactors.WMaxLimPct_SF, 'uint16', 'Power Limit Percentage', 3, 123),
|
|
1716
1740
|
WMaxLimPct_SF: scaleFactors.WMaxLimPct_SF,
|
|
1717
1741
|
WMaxLimPct_WinTms: wMaxLimPctWinTmsRaw,
|
|
1718
1742
|
WMaxLimPct_RvrtTms: wMaxLimPctRvrtTmsRaw,
|
|
1719
1743
|
WMaxLimPct_RmpTms: wMaxLimPctRmpTmsRaw,
|
|
1720
1744
|
WMaxLim_Ena: wMaxLimEnaRaw,
|
|
1721
1745
|
// Power factor control - Offsets 8-12
|
|
1722
|
-
OutPFSet: this.applyScaleFactor(
|
|
1746
|
+
OutPFSet: this.applyScaleFactor(this.extractValue(buffer, 8, 'int16'), scaleFactors.OutPFSet_SF, 'int16', 'Output Power Factor Set', 8, 123),
|
|
1723
1747
|
OutPFSet_SF: scaleFactors.OutPFSet_SF,
|
|
1724
1748
|
OutPFSet_WinTms: outPFSetWinTmsRaw,
|
|
1725
1749
|
OutPFSet_RvrtTms: outPFSetRvrtTmsRaw,
|
|
1726
1750
|
OutPFSet_RmpTms: outPFSetRmpTmsRaw,
|
|
1727
1751
|
OutPFSet_Ena: outPFSetEnaRaw,
|
|
1728
1752
|
// Reactive power control - Offsets 13-20
|
|
1729
|
-
VArWMaxPct: this.applyScaleFactor(
|
|
1730
|
-
VArMaxPct: this.applyScaleFactor(
|
|
1731
|
-
VArAvalPct: this.applyScaleFactor(
|
|
1753
|
+
VArWMaxPct: this.applyScaleFactor(this.extractValue(buffer, 13, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Reactive Power at Max Power %', 13, 123),
|
|
1754
|
+
VArMaxPct: this.applyScaleFactor(this.extractValue(buffer, 14, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Max Reactive Power %', 14, 123),
|
|
1755
|
+
VArAvalPct: this.applyScaleFactor(this.extractValue(buffer, 15, 'int16'), scaleFactors.VArPct_SF, 'int16', 'Available Reactive Power %', 15, 123),
|
|
1732
1756
|
VArPct_SF: scaleFactors.VArPct_SF,
|
|
1733
1757
|
VArPct_WinTms: vArPctWinTmsRaw,
|
|
1734
1758
|
VArPct_RvrtTms: vArPctRvrtTmsRaw,
|