@enyo-energy/sunspec-sdk 0.0.77 → 0.0.79
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 +41 -0
- package/dist/cjs/sunspec-devices.d.cts +7 -0
- package/dist/cjs/version.cjs +1 -1
- package/dist/cjs/version.d.cts +1 -1
- package/dist/sunspec-devices.d.ts +7 -0
- package/dist/sunspec-devices.js +41 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -181,6 +181,7 @@ class BaseSunspecDevice {
|
|
|
181
181
|
if (this.applianceId) {
|
|
182
182
|
await this.applianceManager.updateApplianceState(this.applianceId, enyo_appliance_js_1.EnyoApplianceConnectionType.Connector, enyo_appliance_js_1.EnyoApplianceStateEnum.Connected);
|
|
183
183
|
}
|
|
184
|
+
await this.onConnectionRestored();
|
|
184
185
|
const postStats = this.sunspecClient.getConnectionStats();
|
|
185
186
|
console.log(`${this.constructor.name} ${this.applianceId}: Reconnection successful after ${attempt} attempt(s) (opens=${postStats.opens}, closes=${postStats.closes}, openUnits=${postStats.openUnits})`);
|
|
186
187
|
return true;
|
|
@@ -202,6 +203,14 @@ class BaseSunspecDevice {
|
|
|
202
203
|
async onConnectionFailure(_consecutiveFailures) {
|
|
203
204
|
// Default: no-op. SunspecInverter overrides to publish a faulted status.
|
|
204
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* Hook for subclasses to react to a successful reconnect. Called once
|
|
208
|
+
* after the appliance state has been updated to Connected.
|
|
209
|
+
*/
|
|
210
|
+
async onConnectionRestored() {
|
|
211
|
+
// Default: no-op. SunspecInverter overrides to publish a healthy status
|
|
212
|
+
// when recovering from a previously emitted connection-lost fault.
|
|
213
|
+
}
|
|
205
214
|
/**
|
|
206
215
|
* Detect a silent read failure: the SDK's per-model readers swallow modbus errors and
|
|
207
216
|
* return null/[] rather than throwing, so a readData() cycle can complete "successfully"
|
|
@@ -368,9 +377,18 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
368
377
|
}
|
|
369
378
|
await this.loadErrorState();
|
|
370
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
|
+
}
|
|
371
388
|
}
|
|
372
389
|
async disconnect() {
|
|
373
390
|
this.stopDataBusListening();
|
|
391
|
+
await this.removePersistedErrorState();
|
|
374
392
|
if (this.applianceId) {
|
|
375
393
|
try {
|
|
376
394
|
await this.applianceManager.updateApplianceState(this.applianceId, enyo_appliance_js_1.EnyoApplianceConnectionType.Connector, enyo_appliance_js_1.EnyoApplianceStateEnum.Offline);
|
|
@@ -562,6 +580,15 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
562
580
|
console.error(`Inverter ${this.applianceId}: failed to persist error state: ${error}`);
|
|
563
581
|
}
|
|
564
582
|
}
|
|
583
|
+
async removePersistedErrorState() {
|
|
584
|
+
const storage = this.storage ?? this.energyApp.useStorage();
|
|
585
|
+
try {
|
|
586
|
+
await storage.remove(this.storageKey());
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
console.error(`Inverter ${this.applianceId}: failed to remove persisted error state: ${error}`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
565
592
|
async detectAndEmitStatusTransition(data, timestamp) {
|
|
566
593
|
if (!this.applianceId)
|
|
567
594
|
return undefined;
|
|
@@ -610,6 +637,20 @@ class SunspecInverter extends BaseSunspecDevice {
|
|
|
610
637
|
console.log(`Inverter ${this.applianceId}: emitting faulted (${sunspec_interfaces_js_1.SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
611
638
|
this.dataBus.sendMessage([message]);
|
|
612
639
|
}
|
|
640
|
+
async onConnectionRestored() {
|
|
641
|
+
if (!this.applianceId || !this.dataBus)
|
|
642
|
+
return;
|
|
643
|
+
if (this.errorState.lastStatus !== 'connection_lost')
|
|
644
|
+
return;
|
|
645
|
+
const message = this.buildStatusMessage(enyo_appliance_js_1.EnyoApplianceStatusEnum.Healthy, [], new Date());
|
|
646
|
+
this.errorState = {
|
|
647
|
+
activeCodes: [],
|
|
648
|
+
lastStatus: 'healthy',
|
|
649
|
+
};
|
|
650
|
+
await this.persistErrorState();
|
|
651
|
+
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
652
|
+
this.dataBus.sendMessage([message]);
|
|
653
|
+
}
|
|
613
654
|
/**
|
|
614
655
|
* Compute the currently active feed-in / production limit in Watts from the
|
|
615
656
|
* Model 121 settings (WMax) and Model 123 controls (WMaxLim_Ena, WMaxLimPct).
|
|
@@ -69,6 +69,11 @@ export declare abstract class BaseSunspecDevice {
|
|
|
69
69
|
* per failed attempt with the running consecutive-failure count.
|
|
70
70
|
*/
|
|
71
71
|
protected onConnectionFailure(_consecutiveFailures: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Hook for subclasses to react to a successful reconnect. Called once
|
|
74
|
+
* after the appliance state has been updated to Connected.
|
|
75
|
+
*/
|
|
76
|
+
protected onConnectionRestored(): Promise<void>;
|
|
72
77
|
/**
|
|
73
78
|
* Detect a silent read failure: the SDK's per-model readers swallow modbus errors and
|
|
74
79
|
* return null/[] rather than throwing, so a readData() cycle can complete "successfully"
|
|
@@ -143,8 +148,10 @@ export declare class SunspecInverter extends BaseSunspecDevice {
|
|
|
143
148
|
private storageKey;
|
|
144
149
|
private loadErrorState;
|
|
145
150
|
private persistErrorState;
|
|
151
|
+
private removePersistedErrorState;
|
|
146
152
|
private detectAndEmitStatusTransition;
|
|
147
153
|
protected onConnectionFailure(consecutiveFailures: number): Promise<void>;
|
|
154
|
+
protected onConnectionRestored(): Promise<void>;
|
|
148
155
|
/**
|
|
149
156
|
* Compute the currently active feed-in / production limit in Watts from the
|
|
150
157
|
* Model 121 settings (WMax) and Model 123 controls (WMaxLim_Ena, WMaxLimPct).
|
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.79';
|
|
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
|
@@ -69,6 +69,11 @@ export declare abstract class BaseSunspecDevice {
|
|
|
69
69
|
* per failed attempt with the running consecutive-failure count.
|
|
70
70
|
*/
|
|
71
71
|
protected onConnectionFailure(_consecutiveFailures: number): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Hook for subclasses to react to a successful reconnect. Called once
|
|
74
|
+
* after the appliance state has been updated to Connected.
|
|
75
|
+
*/
|
|
76
|
+
protected onConnectionRestored(): Promise<void>;
|
|
72
77
|
/**
|
|
73
78
|
* Detect a silent read failure: the SDK's per-model readers swallow modbus errors and
|
|
74
79
|
* return null/[] rather than throwing, so a readData() cycle can complete "successfully"
|
|
@@ -143,8 +148,10 @@ export declare class SunspecInverter extends BaseSunspecDevice {
|
|
|
143
148
|
private storageKey;
|
|
144
149
|
private loadErrorState;
|
|
145
150
|
private persistErrorState;
|
|
151
|
+
private removePersistedErrorState;
|
|
146
152
|
private detectAndEmitStatusTransition;
|
|
147
153
|
protected onConnectionFailure(consecutiveFailures: number): Promise<void>;
|
|
154
|
+
protected onConnectionRestored(): Promise<void>;
|
|
148
155
|
/**
|
|
149
156
|
* Compute the currently active feed-in / production limit in Watts from the
|
|
150
157
|
* Model 121 settings (WMax) and Model 123 controls (WMaxLim_Ena, WMaxLimPct).
|
package/dist/sunspec-devices.js
CHANGED
|
@@ -175,6 +175,7 @@ export class BaseSunspecDevice {
|
|
|
175
175
|
if (this.applianceId) {
|
|
176
176
|
await this.applianceManager.updateApplianceState(this.applianceId, EnyoApplianceConnectionType.Connector, EnyoApplianceStateEnum.Connected);
|
|
177
177
|
}
|
|
178
|
+
await this.onConnectionRestored();
|
|
178
179
|
const postStats = this.sunspecClient.getConnectionStats();
|
|
179
180
|
console.log(`${this.constructor.name} ${this.applianceId}: Reconnection successful after ${attempt} attempt(s) (opens=${postStats.opens}, closes=${postStats.closes}, openUnits=${postStats.openUnits})`);
|
|
180
181
|
return true;
|
|
@@ -196,6 +197,14 @@ export class BaseSunspecDevice {
|
|
|
196
197
|
async onConnectionFailure(_consecutiveFailures) {
|
|
197
198
|
// Default: no-op. SunspecInverter overrides to publish a faulted status.
|
|
198
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Hook for subclasses to react to a successful reconnect. Called once
|
|
202
|
+
* after the appliance state has been updated to Connected.
|
|
203
|
+
*/
|
|
204
|
+
async onConnectionRestored() {
|
|
205
|
+
// Default: no-op. SunspecInverter overrides to publish a healthy status
|
|
206
|
+
// when recovering from a previously emitted connection-lost fault.
|
|
207
|
+
}
|
|
199
208
|
/**
|
|
200
209
|
* Detect a silent read failure: the SDK's per-model readers swallow modbus errors and
|
|
201
210
|
* return null/[] rather than throwing, so a readData() cycle can complete "successfully"
|
|
@@ -361,9 +370,18 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
361
370
|
}
|
|
362
371
|
await this.loadErrorState();
|
|
363
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
|
+
}
|
|
364
381
|
}
|
|
365
382
|
async disconnect() {
|
|
366
383
|
this.stopDataBusListening();
|
|
384
|
+
await this.removePersistedErrorState();
|
|
367
385
|
if (this.applianceId) {
|
|
368
386
|
try {
|
|
369
387
|
await this.applianceManager.updateApplianceState(this.applianceId, EnyoApplianceConnectionType.Connector, EnyoApplianceStateEnum.Offline);
|
|
@@ -555,6 +573,15 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
555
573
|
console.error(`Inverter ${this.applianceId}: failed to persist error state: ${error}`);
|
|
556
574
|
}
|
|
557
575
|
}
|
|
576
|
+
async removePersistedErrorState() {
|
|
577
|
+
const storage = this.storage ?? this.energyApp.useStorage();
|
|
578
|
+
try {
|
|
579
|
+
await storage.remove(this.storageKey());
|
|
580
|
+
}
|
|
581
|
+
catch (error) {
|
|
582
|
+
console.error(`Inverter ${this.applianceId}: failed to remove persisted error state: ${error}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
558
585
|
async detectAndEmitStatusTransition(data, timestamp) {
|
|
559
586
|
if (!this.applianceId)
|
|
560
587
|
return undefined;
|
|
@@ -603,6 +630,20 @@ export class SunspecInverter extends BaseSunspecDevice {
|
|
|
603
630
|
console.log(`Inverter ${this.applianceId}: emitting faulted (${SUNSPEC_CONNECTION_LOST_CODE}) after ${consecutiveFailures} consecutive reconnect failures`);
|
|
604
631
|
this.dataBus.sendMessage([message]);
|
|
605
632
|
}
|
|
633
|
+
async onConnectionRestored() {
|
|
634
|
+
if (!this.applianceId || !this.dataBus)
|
|
635
|
+
return;
|
|
636
|
+
if (this.errorState.lastStatus !== 'connection_lost')
|
|
637
|
+
return;
|
|
638
|
+
const message = this.buildStatusMessage(EnyoApplianceStatusEnum.Healthy, [], new Date());
|
|
639
|
+
this.errorState = {
|
|
640
|
+
activeCodes: [],
|
|
641
|
+
lastStatus: 'healthy',
|
|
642
|
+
};
|
|
643
|
+
await this.persistErrorState();
|
|
644
|
+
console.log(`Inverter ${this.applianceId}: emitting healthy after reconnect`);
|
|
645
|
+
this.dataBus.sendMessage([message]);
|
|
646
|
+
}
|
|
606
647
|
/**
|
|
607
648
|
* Compute the currently active feed-in / production limit in Watts from the
|
|
608
649
|
* Model 121 settings (WMax) and Model 123 controls (WMaxLim_Ena, WMaxLimPct).
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED