@enyo-energy/sunspec-sdk 0.0.78 → 0.0.80
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 +29 -13
- package/dist/cjs/sunspec-devices.d.cts +1 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/sunspec-devices.d.ts +1 -0
- package/dist/sunspec-devices.js +29 -13
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -377,9 +377,18 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
377
377
|
}
|
|
378
378
|
await this.loadErrorState();
|
|
379
379
|
this.startDataBusListening();
|
|
380
|
+
// Cold-start recovery: if the persisted state says we were stuck in
|
|
381
|
+
// connection_lost but connect() just succeeded (we read commonBlock,
|
|
382
|
+
// settings, controls and MPPT above), the Modbus path is provably
|
|
383
|
+
// healthy. Clear the stale fault and emit Healthy via the same hook
|
|
384
|
+
// the in-process reconnect path uses.
|
|
385
|
+
if (this.errorState.lastStatus === 'connection_lost') {
|
|
386
|
+
await this.onConnectionRestored();
|
|
387
|
+
}
|
|
380
388
|
}
|
|
381
389
|
async disconnect() {
|
|
382
390
|
this.stopDataBusListening();
|
|
391
|
+
await this.removePersistedErrorState();
|
|
383
392
|
if (this.applianceId) {
|
|
384
393
|
try {
|
|
385
394
|
await this.applianceManager.updateApplianceState(this.applianceId, enyo_appliance_js_1.EnyoApplianceConnectionType.Connector, enyo_appliance_js_1.EnyoApplianceStateEnum.Offline);
|
|
@@ -435,10 +444,7 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
435
444
|
}
|
|
436
445
|
};
|
|
437
446
|
messages.push(inverterMessage);
|
|
438
|
-
|
|
439
|
-
if (statusMessage) {
|
|
440
|
-
messages.push(statusMessage);
|
|
441
|
-
}
|
|
447
|
+
await this.detectAndEmitStatusTransition(inverterData, timestamp);
|
|
442
448
|
}
|
|
443
449
|
this.consecutiveReconnectFailures = 0;
|
|
444
450
|
if (this.applianceId) {
|
|
@@ -571,17 +577,29 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
571
577
|
console.error(`Inverter ${this.applianceId}: failed to persist error state: ${error}`);
|
|
572
578
|
}
|
|
573
579
|
}
|
|
580
|
+
async removePersistedErrorState() {
|
|
581
|
+
const storage = this.storage ?? this.energyApp.useStorage();
|
|
582
|
+
try {
|
|
583
|
+
await storage.remove(this.storageKey());
|
|
584
|
+
}
|
|
585
|
+
catch (error) {
|
|
586
|
+
console.error(`Inverter ${this.applianceId}: failed to remove persisted error state: ${error}`);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
574
589
|
async detectAndEmitStatusTransition(data, timestamp) {
|
|
575
|
-
if (!this.applianceId)
|
|
576
|
-
return
|
|
590
|
+
if (!this.applianceId || !this.dataBus)
|
|
591
|
+
return;
|
|
577
592
|
const { codes, codeIds } = this.decodeActiveErrors(data);
|
|
578
593
|
const recoveringFromConnectionLoss = this.errorState.lastStatus === 'connection_lost';
|
|
579
594
|
if (!recoveringFromConnectionLoss && !this.hasErrorSetChanged(codeIds)) {
|
|
580
|
-
return
|
|
595
|
+
return;
|
|
581
596
|
}
|
|
582
597
|
const newStatus = codeIds.length === 0
|
|
583
598
|
? enyo_appliance_js_1.EnyoApplianceStatusEnum.Healthy
|
|
584
599
|
: enyo_appliance_js_1.EnyoApplianceStatusEnum.Faulted;
|
|
600
|
+
const message = this.buildStatusMessage(newStatus, codes, timestamp);
|
|
601
|
+
console.log(`Inverter ${this.applianceId}: status transition -> ${newStatus} (codes=[${codeIds.join(', ')}])`);
|
|
602
|
+
this.dataBus.sendMessage([message]);
|
|
585
603
|
this.errorState = {
|
|
586
604
|
evt1: data.events,
|
|
587
605
|
evt2: data.events2,
|
|
@@ -593,8 +611,6 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
593
611
|
lastStatus: newStatus === enyo_appliance_js_1.EnyoApplianceStatusEnum.Healthy ? 'healthy' : 'faulted',
|
|
594
612
|
};
|
|
595
613
|
await this.persistErrorState();
|
|
596
|
-
console.log(`Inverter ${this.applianceId}: status transition -> ${newStatus} (codes=[${codeIds.join(', ')}])`);
|
|
597
|
-
return this.buildStatusMessage(newStatus, codes, timestamp);
|
|
598
614
|
}
|
|
599
615
|
async onConnectionFailure(consecutiveFailures) {
|
|
600
616
|
if (!this.applianceId || !this.dataBus)
|
|
@@ -611,13 +627,13 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
611
627
|
]
|
|
612
628
|
}];
|
|
613
629
|
const message = this.buildStatusMessage(enyo_appliance_js_1.EnyoApplianceStatusEnum.Faulted, errorCodes, new Date());
|
|
630
|
+
console.log(`Inverter ${this.applianceId}: emitting faulted (${sunspec_interfaces_js_1.SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
631
|
+
this.dataBus.sendMessage([message]);
|
|
614
632
|
this.errorState = {
|
|
615
633
|
activeCodes: [sunspec_interfaces_js_1.SUNSPEC_CONNECTION_LOST_CODE],
|
|
616
634
|
lastStatus: 'connection_lost',
|
|
617
635
|
};
|
|
618
636
|
await this.persistErrorState();
|
|
619
|
-
console.log(`Inverter ${this.applianceId}: emitting faulted (${sunspec_interfaces_js_1.SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
620
|
-
this.dataBus.sendMessage([message]);
|
|
621
637
|
}
|
|
622
638
|
async onConnectionRestored() {
|
|
623
639
|
if (!this.applianceId || !this.dataBus)
|
|
@@ -625,13 +641,13 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
625
641
|
if (this.errorState.lastStatus !== 'connection_lost')
|
|
626
642
|
return;
|
|
627
643
|
const message = this.buildStatusMessage(enyo_appliance_js_1.EnyoApplianceStatusEnum.Healthy, [], new Date());
|
|
644
|
+
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
645
|
+
this.dataBus.sendMessage([message]);
|
|
628
646
|
this.errorState = {
|
|
629
647
|
activeCodes: [],
|
|
630
648
|
lastStatus: 'healthy',
|
|
631
649
|
};
|
|
632
650
|
await this.persistErrorState();
|
|
633
|
-
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
634
|
-
this.dataBus.sendMessage([message]);
|
|
635
651
|
}
|
|
636
652
|
/**
|
|
637
653
|
* Compute the currently active feed-in / production limit in Watts from the
|
|
@@ -148,6 +148,7 @@ export declare class SunspecInverter extends BaseSunspecDevice {
|
|
|
148
148
|
private storageKey;
|
|
149
149
|
private loadErrorState;
|
|
150
150
|
private persistErrorState;
|
|
151
|
+
private removePersistedErrorState;
|
|
151
152
|
private detectAndEmitStatusTransition;
|
|
152
153
|
protected onConnectionFailure(consecutiveFailures: number): Promise<void>;
|
|
153
154
|
protected onConnectionRestored(): Promise<void>;
|
package/dist/cjs/version.cjs
CHANGED
|
@@ -9,7 +9,7 @@ exports.getSdkVersion = getSdkVersion;
|
|
|
9
9
|
/**
|
|
10
10
|
* Current version of the enyo Energy App SDK.
|
|
11
11
|
*/
|
|
12
|
-
exports.SDK_VERSION = '0.0.
|
|
12
|
+
exports.SDK_VERSION = '0.0.80';
|
|
13
13
|
/**
|
|
14
14
|
* Gets the current SDK version.
|
|
15
15
|
* @returns The semantic version string of the SDK
|
package/dist/cjs/version.d.cts
CHANGED
|
@@ -148,6 +148,7 @@ export declare class SunspecInverter extends BaseSunspecDevice {
|
|
|
148
148
|
private storageKey;
|
|
149
149
|
private loadErrorState;
|
|
150
150
|
private persistErrorState;
|
|
151
|
+
private removePersistedErrorState;
|
|
151
152
|
private detectAndEmitStatusTransition;
|
|
152
153
|
protected onConnectionFailure(consecutiveFailures: number): Promise<void>;
|
|
153
154
|
protected onConnectionRestored(): Promise<void>;
|
package/dist/sunspec-devices.js
CHANGED
|
@@ -370,9 +370,18 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
370
370
|
}
|
|
371
371
|
await this.loadErrorState();
|
|
372
372
|
this.startDataBusListening();
|
|
373
|
+
// Cold-start recovery: if the persisted state says we were stuck in
|
|
374
|
+
// connection_lost but connect() just succeeded (we read commonBlock,
|
|
375
|
+
// settings, controls and MPPT above), the Modbus path is provably
|
|
376
|
+
// healthy. Clear the stale fault and emit Healthy via the same hook
|
|
377
|
+
// the in-process reconnect path uses.
|
|
378
|
+
if (this.errorState.lastStatus === 'connection_lost') {
|
|
379
|
+
await this.onConnectionRestored();
|
|
380
|
+
}
|
|
373
381
|
}
|
|
374
382
|
async disconnect() {
|
|
375
383
|
this.stopDataBusListening();
|
|
384
|
+
await this.removePersistedErrorState();
|
|
376
385
|
if (this.applianceId) {
|
|
377
386
|
try {
|
|
378
387
|
await this.applianceManager.updateApplianceState(this.applianceId, EnyoApplianceConnectionType.Connector, EnyoApplianceStateEnum.Offline);
|
|
@@ -428,10 +437,7 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
428
437
|
}
|
|
429
438
|
};
|
|
430
439
|
messages.push(inverterMessage);
|
|
431
|
-
|
|
432
|
-
if (statusMessage) {
|
|
433
|
-
messages.push(statusMessage);
|
|
434
|
-
}
|
|
440
|
+
await this.detectAndEmitStatusTransition(inverterData, timestamp);
|
|
435
441
|
}
|
|
436
442
|
this.consecutiveReconnectFailures = 0;
|
|
437
443
|
if (this.applianceId) {
|
|
@@ -564,17 +570,29 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
564
570
|
console.error(`Inverter ${this.applianceId}: failed to persist error state: ${error}`);
|
|
565
571
|
}
|
|
566
572
|
}
|
|
573
|
+
async removePersistedErrorState() {
|
|
574
|
+
const storage = this.storage ?? this.energyApp.useStorage();
|
|
575
|
+
try {
|
|
576
|
+
await storage.remove(this.storageKey());
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
console.error(`Inverter ${this.applianceId}: failed to remove persisted error state: ${error}`);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
567
582
|
async detectAndEmitStatusTransition(data, timestamp) {
|
|
568
|
-
if (!this.applianceId)
|
|
569
|
-
return
|
|
583
|
+
if (!this.applianceId || !this.dataBus)
|
|
584
|
+
return;
|
|
570
585
|
const { codes, codeIds } = this.decodeActiveErrors(data);
|
|
571
586
|
const recoveringFromConnectionLoss = this.errorState.lastStatus === 'connection_lost';
|
|
572
587
|
if (!recoveringFromConnectionLoss && !this.hasErrorSetChanged(codeIds)) {
|
|
573
|
-
return
|
|
588
|
+
return;
|
|
574
589
|
}
|
|
575
590
|
const newStatus = codeIds.length === 0
|
|
576
591
|
? EnyoApplianceStatusEnum.Healthy
|
|
577
592
|
: EnyoApplianceStatusEnum.Faulted;
|
|
593
|
+
const message = this.buildStatusMessage(newStatus, codes, timestamp);
|
|
594
|
+
console.log(`Inverter ${this.applianceId}: status transition -> ${newStatus} (codes=[${codeIds.join(', ')}])`);
|
|
595
|
+
this.dataBus.sendMessage([message]);
|
|
578
596
|
this.errorState = {
|
|
579
597
|
evt1: data.events,
|
|
580
598
|
evt2: data.events2,
|
|
@@ -586,8 +604,6 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
586
604
|
lastStatus: newStatus === EnyoApplianceStatusEnum.Healthy ? 'healthy' : 'faulted',
|
|
587
605
|
};
|
|
588
606
|
await this.persistErrorState();
|
|
589
|
-
console.log(`Inverter ${this.applianceId}: status transition -> ${newStatus} (codes=[${codeIds.join(', ')}])`);
|
|
590
|
-
return this.buildStatusMessage(newStatus, codes, timestamp);
|
|
591
607
|
}
|
|
592
608
|
async onConnectionFailure(consecutiveFailures) {
|
|
593
609
|
if (!this.applianceId || !this.dataBus)
|
|
@@ -604,13 +620,13 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
604
620
|
]
|
|
605
621
|
}];
|
|
606
622
|
const message = this.buildStatusMessage(EnyoApplianceStatusEnum.Faulted, errorCodes, new Date());
|
|
623
|
+
console.log(`Inverter ${this.applianceId}: emitting faulted (${SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
624
|
+
this.dataBus.sendMessage([message]);
|
|
607
625
|
this.errorState = {
|
|
608
626
|
activeCodes: [SUNSPEC_CONNECTION_LOST_CODE],
|
|
609
627
|
lastStatus: 'connection_lost',
|
|
610
628
|
};
|
|
611
629
|
await this.persistErrorState();
|
|
612
|
-
console.log(`Inverter ${this.applianceId}: emitting faulted (${SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
613
|
-
this.dataBus.sendMessage([message]);
|
|
614
630
|
}
|
|
615
631
|
async onConnectionRestored() {
|
|
616
632
|
if (!this.applianceId || !this.dataBus)
|
|
@@ -618,13 +634,13 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
618
634
|
if (this.errorState.lastStatus !== 'connection_lost')
|
|
619
635
|
return;
|
|
620
636
|
const message = this.buildStatusMessage(EnyoApplianceStatusEnum.Healthy, [], new Date());
|
|
637
|
+
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
638
|
+
this.dataBus.sendMessage([message]);
|
|
621
639
|
this.errorState = {
|
|
622
640
|
activeCodes: [],
|
|
623
641
|
lastStatus: 'healthy',
|
|
624
642
|
};
|
|
625
643
|
await this.persistErrorState();
|
|
626
|
-
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
627
|
-
this.dataBus.sendMessage([message]);
|
|
628
644
|
}
|
|
629
645
|
/**
|
|
630
646
|
* Compute the currently active feed-in / production limit in Watts from the
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED