Skip to content

Commit 504efa2

Browse files
committed
Add cache and reuse
1 parent 4c63d35 commit 504efa2

File tree

3 files changed

+73
-41
lines changed

3 files changed

+73
-41
lines changed

.changeset/big-showers-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@teslemetry/api": patch
3+
---
4+
5+
Add energy cache and reuse

packages/api/src/TeslemetryEnergyApi.ts

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,31 @@ import {
1313
GetApi1EnergySitesByIdSiteInfoResponse,
1414
GetApi1EnergySitesByIdLiveStatusResponse,
1515
} from "./client/index.js";
16+
import { reuse } from "./reuse.js";
17+
18+
// Interface for event type safety
19+
type TeslemetryEnergyEventMap = {
20+
siteInfo: GetApi1EnergySitesByIdSiteInfoResponse;
21+
liveStatus: GetApi1EnergySitesByIdLiveStatusResponse;
22+
};
1623

1724
// TypeScript interface for event type safety
1825
export declare interface TeslemetryEnergyApi {
19-
on(
20-
event: "siteInfo",
21-
listener: (data: GetApi1EnergySitesByIdSiteInfoResponse) => void,
22-
): this;
23-
on(
24-
event: "liveStatus",
25-
listener: (data: GetApi1EnergySitesByIdLiveStatusResponse) => void,
26+
on<K extends keyof TeslemetryEnergyEventMap>(
27+
event: K,
28+
listener: (data: TeslemetryEnergyEventMap[K]) => void,
2629
): this;
27-
28-
off(
29-
event: "siteInfo",
30-
listener: (data: GetApi1EnergySitesByIdSiteInfoResponse) => void,
30+
off<K extends keyof TeslemetryEnergyEventMap>(
31+
event: K,
32+
listener: (data: TeslemetryEnergyEventMap[K]) => void,
3133
): this;
32-
off(
33-
event: "liveStatus",
34-
listener: (data: GetApi1EnergySitesByIdLiveStatusResponse) => void,
34+
once<K extends keyof TeslemetryEnergyEventMap>(
35+
event: K,
36+
listener: (data: TeslemetryEnergyEventMap[K]) => void,
3537
): this;
36-
37-
once(
38-
event: "siteInfo",
39-
listener: (data: GetApi1EnergySitesByIdSiteInfoResponse) => void,
40-
): this;
41-
once(
42-
event: "liveStatus",
43-
listener: (data: GetApi1EnergySitesByIdLiveStatusResponse) => void,
44-
): this;
45-
46-
emit(
47-
event: "siteInfo",
48-
data: GetApi1EnergySitesByIdSiteInfoResponse,
49-
): boolean;
50-
emit(
51-
event: "liveStatus",
52-
data: GetApi1EnergySitesByIdLiveStatusResponse,
38+
emit<K extends keyof TeslemetryEnergyEventMap>(
39+
event: K,
40+
data: TeslemetryEnergyEventMap[K],
5341
): boolean;
5442
}
5543

@@ -58,6 +46,13 @@ type PollingEndpoints = "siteInfo" | "liveStatus";
5846
export class TeslemetryEnergyApi extends EventEmitter {
5947
private root: Teslemetry;
6048
public siteId: number;
49+
public cache: {
50+
siteInfo: GetApi1EnergySitesByIdSiteInfoResponse | null;
51+
liveStatus: GetApi1EnergySitesByIdLiveStatusResponse | null;
52+
} = {
53+
siteInfo: null,
54+
liveStatus: null,
55+
};
6156
public refreshDelay: number = 30_000;
6257
private refreshInterval: {
6358
[endpoint in PollingEndpoints]: NodeJS.Timeout | null;
@@ -83,6 +78,17 @@ export class TeslemetryEnergyApi extends EventEmitter {
8378
root.api.energySites.set(siteId, this);
8479
}
8580

81+
public on<K extends keyof TeslemetryEnergyEventMap>(
82+
event: K,
83+
listener: (data: TeslemetryEnergyEventMap[K]) => void,
84+
): this {
85+
const cached = this.cache[event];
86+
if (cached) {
87+
listener(cached as TeslemetryEnergyEventMap[K]);
88+
}
89+
return super.on(event, listener);
90+
}
91+
8692
/**
8793
* Adjust the site's backup reserve.
8894
* @param backup_reserve_percent The backup reserve percentage
@@ -145,30 +151,38 @@ export class TeslemetryEnergyApi extends EventEmitter {
145151
return data;
146152
}
147153

154+
private getLiveStatusReuse = reuse(1000);
148155
/**
149156
* Returns the live status of the site (power, state of energy, grid status, storm mode).
150157
* @return Promise to an object with response containing current live status of the energy site
151158
*/
152159
public async getLiveStatus() {
153-
const { data } = await getApi1EnergySitesByIdLiveStatus({
154-
path: { id: this.siteId },
155-
client: this.root.client,
160+
return this.getLiveStatusReuse(async () => {
161+
const { data } = await getApi1EnergySitesByIdLiveStatus({
162+
path: { id: this.siteId },
163+
client: this.root.client,
164+
});
165+
this.cache.liveStatus = data;
166+
this.emit("liveStatus", data);
167+
return data;
156168
});
157-
this.emit("liveStatus", data);
158-
return data;
159169
}
160170

171+
private getSiteInfoReuse = reuse(1000);
161172
/**
162173
* Returns information about the site. Things like assets (has solar, etc), settings (backup reserve, etc), and features (storm_mode_capable, etc).
163174
* @return Promise to an object with response containing detailed information about the energy site
164175
*/
165176
public async getSiteInfo() {
166-
const { data } = await getApi1EnergySitesByIdSiteInfo({
167-
path: { id: this.siteId },
168-
client: this.root.client,
177+
return this.getSiteInfoReuse(async () => {
178+
const { data } = await getApi1EnergySitesByIdSiteInfo({
179+
path: { id: this.siteId },
180+
client: this.root.client,
181+
});
182+
this.cache.siteInfo = data;
183+
this.emit("siteInfo", data);
184+
return data;
169185
});
170-
this.emit("siteInfo", data);
171-
return data;
172186
}
173187

174188
/**

packages/api/src/reuse.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export const reuse = (linger: number = 0) => {
2+
let promise: Promise<any> | null = null;
3+
4+
return async <U>(func: () => Promise<U>) => {
5+
if (promise) return promise;
6+
try {
7+
promise = func();
8+
return await promise;
9+
} finally {
10+
setTimeout(() => (promise = null), linger);
11+
}
12+
};
13+
};

0 commit comments

Comments
 (0)