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