Skip to content

Commit 0b9654c

Browse files
committed
Minor updates to value handling
1 parent 3a50aea commit 0b9654c

File tree

2 files changed

+57
-8
lines changed

2 files changed

+57
-8
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
"tvoc"
3030
],
3131
"engines": {
32-
"node": ">=18.17.0 <23",
33-
"homebridge": ">=1.6.0"
32+
"homebridge": "^1.6.0 || ^2.0.0-beta.0",
33+
"node": "^18.20.4 || ^20.15.1 || ^22"
3434
},
3535
"peerDependencies": {
3636
"homebridge": ">=1.6.0"

src/index.ts

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,22 @@ class AirGradientPlatform implements DynamicPlatformPlugin {
109109
}
110110
}
111111

112+
function isAirGradientData(x: unknown): x is AirGradientData {
113+
if (x === null || typeof x !== 'object') {
114+
return false;
115+
}
116+
const o = x as Record<string, unknown>;
117+
118+
// Minimal required fields you actually rely on elsewhere
119+
return (
120+
typeof o.pm02 === 'number' &&
121+
typeof o.pm10 === 'number' &&
122+
typeof o.rco2 === 'number' &&
123+
typeof o.atmp === 'number' &&
124+
typeof o.rhum === 'number'
125+
);
126+
}
127+
112128
class AirGradientSensor {
113129
private readonly platform: AirGradientPlatform;
114130
private readonly accessory: PlatformAccessory;
@@ -200,18 +216,51 @@ class AirGradientSensor {
200216

201217
private async fetchData() {
202218
try {
203-
const response = await axios.get(this.apiUrl);
204-
this.data = response.data;
219+
// Strongly type the expected payload
220+
const response = await axios.get<AirGradientData>(this.apiUrl, {
221+
timeout: 5000, // optional: avoid hanging forever
222+
headers: { 'Accept': 'application/json' },
223+
// validateStatus: (s) => s >= 200 && s < 400, // optional: treat 3xx as ok if your devices redirect
224+
});
225+
226+
const payload = response.data;
227+
228+
// Runtime validation: ensures critical numeric fields exist
229+
if (!isAirGradientData(payload)) {
230+
this.log.error('AirGradient API returned unexpected data format:', payload);
231+
return; // keep previous this.data (so we don’t overwrite with bad data)
232+
}
233+
234+
// All good—commit and log
235+
this.data = payload;
205236
this.log.info('Data fetched successfully:', this.data);
206237

207-
// Log the full response for debugging
238+
// Optional extra debug
208239
this.log.debug('API response:', this.data);
209-
} catch (error) {
210-
this.log.error('Error fetching data from AirGradient API:', error);
211-
throw error;
240+
241+
} catch (err) {
242+
// Make axios/network errors readable without losing detail
243+
const e = err as unknown;
244+
if (axios.isAxiosError(e)) {
245+
this.log.error(
246+
`Axios error fetching AirGradient data: ${e.message}` +
247+
(e.response ? ` (status ${e.response.status})` : '') +
248+
(e.code ? ` [code ${e.code}]` : ''),
249+
);
250+
if (e.response?.data) {
251+
this.log.debug('Error response body:', e.response.data);
252+
}
253+
} else if (e instanceof Error) {
254+
this.log.error('Error fetching data from AirGradient API:', e.message);
255+
this.log.debug(e.stack || 'no stack');
256+
} else {
257+
this.log.error('Unknown error fetching data from AirGradient API:', e);
258+
}
259+
throw err; // keep existing control flow in updateData()
212260
}
213261
}
214262

263+
215264
private async updateData() {
216265
try {
217266
await this.fetchData();

0 commit comments

Comments
 (0)