@enyo-energy/sunspec-sdk 0.0.21 → 0.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/sunspec-devices.cjs +184 -3
- package/dist/cjs/sunspec-devices.d.cts +68 -1
- package/dist/cjs/sunspec-interfaces.cjs +27 -2
- package/dist/cjs/sunspec-interfaces.d.cts +39 -1
- package/dist/cjs/sunspec-modbus-client.cjs +185 -0
- package/dist/cjs/sunspec-modbus-client.d.cts +21 -1
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/sunspec-devices.d.ts +68 -1
- package/dist/sunspec-devices.js +185 -4
- package/dist/sunspec-interfaces.d.ts +39 -1
- package/dist/sunspec-interfaces.js +26 -1
- package/dist/sunspec-modbus-client.d.ts +21 -1
- package/dist/sunspec-modbus-client.js +186 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - pad: 0x8000 (always returns this value)
|
|
17
17
|
* - string: all registers 0x0000 (NULL)
|
|
18
18
|
*/
|
|
19
|
-
import { SunspecModelId, SunspecBatteryChargeState, SunspecStorageControlMode } from "./sunspec-interfaces.js";
|
|
19
|
+
import { SunspecModelId, SunspecBatteryChargeState, SunspecStorageControlMode, SunspecChargeSource, SunspecStorageMode } from "./sunspec-interfaces.js";
|
|
20
20
|
import { EnergyAppModbusConnectionHealth } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusConnectionHealth.js";
|
|
21
21
|
import { EnergyAppModbusFaultTolerantReader } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusFaultTolerantReader.js";
|
|
22
22
|
import { EnergyAppModbusDataTypeConverter } from "@enyo-energy/energy-app-sdk/dist/implementations/modbus/EnergyAppModbusDataTypeConverter.js";
|
|
@@ -262,6 +262,52 @@ export class SunspecModbusClient {
|
|
|
262
262
|
throw error;
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Helper to write register value(s)
|
|
267
|
+
*/
|
|
268
|
+
async writeRegisterValue(address, value, dataType = 'uint16') {
|
|
269
|
+
if (!this.modbusClient) {
|
|
270
|
+
throw new Error('Modbus client not initialized');
|
|
271
|
+
}
|
|
272
|
+
try {
|
|
273
|
+
// Convert value to array of register values
|
|
274
|
+
let registerValues;
|
|
275
|
+
if (Array.isArray(value)) {
|
|
276
|
+
// For arrays, use directly
|
|
277
|
+
registerValues = value;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
// For single values, convert based on data type
|
|
281
|
+
switch (dataType) {
|
|
282
|
+
case 'uint32':
|
|
283
|
+
case 'int32':
|
|
284
|
+
// Split 32-bit value into two 16-bit registers
|
|
285
|
+
const high = (value >>> 16) & 0xFFFF;
|
|
286
|
+
const low = value & 0xFFFF;
|
|
287
|
+
registerValues = [high, low];
|
|
288
|
+
break;
|
|
289
|
+
case 'int16':
|
|
290
|
+
// For signed 16-bit, ensure proper representation
|
|
291
|
+
registerValues = [value & 0xFFFF];
|
|
292
|
+
break;
|
|
293
|
+
case 'uint16':
|
|
294
|
+
default:
|
|
295
|
+
registerValues = [value & 0xFFFF];
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Write to holding registers
|
|
300
|
+
await this.modbusClient.writeMultipleRegisters(address, registerValues);
|
|
301
|
+
this.connectionHealth.recordSuccess();
|
|
302
|
+
console.log(`Successfully wrote value ${value} to register ${address}`);
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
this.connectionHealth.recordFailure(error);
|
|
307
|
+
console.error(`Error writing register at address ${address}: ${error}`);
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
265
311
|
/**
|
|
266
312
|
* Read inverter data from Model 103 (Three Phase)
|
|
267
313
|
*/
|
|
@@ -794,6 +840,145 @@ export class SunspecModbusClient {
|
|
|
794
840
|
return null;
|
|
795
841
|
}
|
|
796
842
|
}
|
|
843
|
+
/**
|
|
844
|
+
* Write battery control settings to Model 124
|
|
845
|
+
*/
|
|
846
|
+
async writeBatteryControls(controls) {
|
|
847
|
+
const model = this.findModel(SunspecModelId.Battery);
|
|
848
|
+
if (!model) {
|
|
849
|
+
console.error('Battery model 124 not found');
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
const baseAddr = model.address;
|
|
853
|
+
console.log(`Writing Battery Controls to Model 124 at base address: ${baseAddr}`);
|
|
854
|
+
try {
|
|
855
|
+
// Write storage control mode (Register 5)
|
|
856
|
+
if (controls.storCtlMod !== undefined) {
|
|
857
|
+
await this.writeRegisterValue(baseAddr + 5, controls.storCtlMod, 'uint16');
|
|
858
|
+
console.log(`Set storage control mode to 0x${controls.storCtlMod.toString(16)}`);
|
|
859
|
+
}
|
|
860
|
+
// Write charge source setting (Register 17)
|
|
861
|
+
if (controls.chaGriSet !== undefined) {
|
|
862
|
+
await this.writeRegisterValue(baseAddr + 17, controls.chaGriSet, 'uint16');
|
|
863
|
+
console.log(`Set charge source to ${controls.chaGriSet === SunspecChargeSource.GRID ? 'GRID' : 'PV'}`);
|
|
864
|
+
}
|
|
865
|
+
// Write maximum charge power (Register 2) - needs scale factor
|
|
866
|
+
if (controls.wChaMax !== undefined) {
|
|
867
|
+
const scaleFactorAddr = baseAddr + 18;
|
|
868
|
+
const scaleFactor = await this.readRegisterValue(scaleFactorAddr, 1, 'int16');
|
|
869
|
+
const scaledValue = Math.round(controls.wChaMax / Math.pow(10, scaleFactor));
|
|
870
|
+
await this.writeRegisterValue(baseAddr + 2, scaledValue, 'uint16');
|
|
871
|
+
console.log(`Set max charge power to ${controls.wChaMax}W (scaled: ${scaledValue})`);
|
|
872
|
+
}
|
|
873
|
+
// Write charge rate (Register 13) - needs scale factor
|
|
874
|
+
if (controls.inWRte !== undefined) {
|
|
875
|
+
const scaleFactorAddr = baseAddr + 25;
|
|
876
|
+
const scaleFactor = await this.readRegisterValue(scaleFactorAddr, 1, 'int16');
|
|
877
|
+
const scaledValue = Math.round(controls.inWRte / Math.pow(10, scaleFactor));
|
|
878
|
+
await this.writeRegisterValue(baseAddr + 13, scaledValue, 'int16');
|
|
879
|
+
console.log(`Set charge rate to ${controls.inWRte}% (scaled: ${scaledValue})`);
|
|
880
|
+
}
|
|
881
|
+
// Write discharge rate (Register 12) - needs scale factor
|
|
882
|
+
if (controls.outWRte !== undefined) {
|
|
883
|
+
const scaleFactorAddr = baseAddr + 25;
|
|
884
|
+
const scaleFactor = await this.readRegisterValue(scaleFactorAddr, 1, 'int16');
|
|
885
|
+
const scaledValue = Math.round(controls.outWRte / Math.pow(10, scaleFactor));
|
|
886
|
+
await this.writeRegisterValue(baseAddr + 12, scaledValue, 'int16');
|
|
887
|
+
console.log(`Set discharge rate to ${controls.outWRte}% (scaled: ${scaledValue})`);
|
|
888
|
+
}
|
|
889
|
+
// Write minimum reserve percentage (Register 7) - needs scale factor
|
|
890
|
+
if (controls.minRsvPct !== undefined) {
|
|
891
|
+
const scaleFactorAddr = baseAddr + 21;
|
|
892
|
+
const scaleFactor = await this.readRegisterValue(scaleFactorAddr, 1, 'int16');
|
|
893
|
+
const scaledValue = Math.round(controls.minRsvPct / Math.pow(10, scaleFactor));
|
|
894
|
+
await this.writeRegisterValue(baseAddr + 7, scaledValue, 'uint16');
|
|
895
|
+
console.log(`Set minimum reserve to ${controls.minRsvPct}% (scaled: ${scaledValue})`);
|
|
896
|
+
}
|
|
897
|
+
console.log('Battery controls written successfully');
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
catch (error) {
|
|
901
|
+
console.error(`Error writing battery controls: ${error}`);
|
|
902
|
+
return false;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
/**
|
|
906
|
+
* Set battery storage mode (simplified interface)
|
|
907
|
+
*/
|
|
908
|
+
async setStorageMode(mode) {
|
|
909
|
+
let storCtlMod;
|
|
910
|
+
switch (mode) {
|
|
911
|
+
case SunspecStorageMode.CHARGE:
|
|
912
|
+
// Enable charge only (bit 0 = 1, bit 1 = 0)
|
|
913
|
+
storCtlMod = SunspecStorageControlMode.CHARGE;
|
|
914
|
+
break;
|
|
915
|
+
case SunspecStorageMode.DISCHARGE:
|
|
916
|
+
// Enable discharge only (bit 0 = 0, bit 1 = 1)
|
|
917
|
+
storCtlMod = SunspecStorageControlMode.DISCHARGE;
|
|
918
|
+
break;
|
|
919
|
+
case SunspecStorageMode.HOLDING:
|
|
920
|
+
// Disable both charge and discharge (bits 0 and 1 = 0)
|
|
921
|
+
storCtlMod = 0;
|
|
922
|
+
break;
|
|
923
|
+
case SunspecStorageMode.AUTO:
|
|
924
|
+
// Enable both charge and discharge (bits 0 and 1 = 1)
|
|
925
|
+
storCtlMod = SunspecStorageControlMode.CHARGE | SunspecStorageControlMode.DISCHARGE;
|
|
926
|
+
break;
|
|
927
|
+
default:
|
|
928
|
+
console.error(`Invalid storage mode: ${mode}`);
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
console.log(`Setting storage mode to ${mode} (control bits: 0x${storCtlMod.toString(16)})`);
|
|
932
|
+
return this.writeBatteryControls({ storCtlMod });
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Enable or disable grid charging
|
|
936
|
+
*/
|
|
937
|
+
async enableGridCharging(enable) {
|
|
938
|
+
const chaGriSet = enable ? SunspecChargeSource.GRID : SunspecChargeSource.PV;
|
|
939
|
+
console.log(`${enable ? 'Enabling' : 'Disabling'} grid charging`);
|
|
940
|
+
return this.writeBatteryControls({ chaGriSet });
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Read current battery control settings
|
|
944
|
+
*/
|
|
945
|
+
async readBatteryControls() {
|
|
946
|
+
const model = this.findModel(SunspecModelId.Battery);
|
|
947
|
+
if (!model) {
|
|
948
|
+
console.log('Battery model 124 not found');
|
|
949
|
+
return null;
|
|
950
|
+
}
|
|
951
|
+
const baseAddr = model.address;
|
|
952
|
+
console.log(`Reading Battery Controls from Model 124 at base address: ${baseAddr}`);
|
|
953
|
+
try {
|
|
954
|
+
// Read scale factors
|
|
955
|
+
const scaleFactors = {
|
|
956
|
+
WChaMax_SF: await this.readRegisterValue(baseAddr + 18, 1, 'int16'),
|
|
957
|
+
MinRsvPct_SF: await this.readRegisterValue(baseAddr + 21, 1, 'int16'),
|
|
958
|
+
InOutWRte_SF: await this.readRegisterValue(baseAddr + 25, 1, 'int16')
|
|
959
|
+
};
|
|
960
|
+
// Read raw values
|
|
961
|
+
const wChaMaxRaw = await this.readRegisterValue(baseAddr + 2, 1, 'uint16');
|
|
962
|
+
const storCtlModRaw = await this.readRegisterValue(baseAddr + 5, 1, 'uint16');
|
|
963
|
+
const minRsvPctRaw = await this.readRegisterValue(baseAddr + 7, 1, 'uint16');
|
|
964
|
+
const outWRteRaw = await this.readRegisterValue(baseAddr + 12, 1, 'int16');
|
|
965
|
+
const inWRteRaw = await this.readRegisterValue(baseAddr + 13, 1, 'int16');
|
|
966
|
+
const chaGriSetRaw = await this.readRegisterValue(baseAddr + 17, 1, 'uint16');
|
|
967
|
+
// Apply scale factors and return control settings
|
|
968
|
+
return {
|
|
969
|
+
storCtlMod: !this.isUnimplementedValue(storCtlModRaw, 'bitfield16') ? storCtlModRaw : undefined,
|
|
970
|
+
chaGriSet: !this.isUnimplementedValue(chaGriSetRaw, 'enum16') ? chaGriSetRaw : undefined,
|
|
971
|
+
wChaMax: this.applyScaleFactor(wChaMaxRaw, scaleFactors.WChaMax_SF, 'uint16'),
|
|
972
|
+
inWRte: this.applyScaleFactor(inWRteRaw, scaleFactors.InOutWRte_SF, 'int16'),
|
|
973
|
+
outWRte: this.applyScaleFactor(outWRteRaw, scaleFactors.InOutWRte_SF, 'int16'),
|
|
974
|
+
minRsvPct: this.applyScaleFactor(minRsvPctRaw, scaleFactors.MinRsvPct_SF, 'uint16')
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
catch (error) {
|
|
978
|
+
console.error(`Error reading battery controls: ${error}`);
|
|
979
|
+
return null;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
797
982
|
/**
|
|
798
983
|
* Read meter data (Model 203 for 3-phase)
|
|
799
984
|
*/
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enyo-energy/sunspec-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.23",
|
|
4
4
|
"description": "enyo Energy Sunspec SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"typescript": "^5.8.3"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@enyo-energy/energy-app-sdk": "^0.0.
|
|
40
|
+
"@enyo-energy/energy-app-sdk": "^0.0.47"
|
|
41
41
|
},
|
|
42
42
|
"volta": {
|
|
43
43
|
"node": "22.17.0"
|