homebridge-withings-environment-data 0.3.3 → 1.1.0
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/CHANGELOG.md +106 -0
- package/README.md +8 -4
- package/config.schema.json +28 -0
- package/index.js +30 -8
- package/package.json +16 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
## [1.1.0] - 2026-07-27
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- Air Quality threshold config fields (`airQualityExcellentMaxPpm`,
|
|
13
|
+
`airQualityGoodMaxPpm`, `airQualityFairMaxPpm`,
|
|
14
|
+
`airQualityInferiorMaxPpm`) to make the AirQualitySensor's ppm
|
|
15
|
+
boundaries configurable instead of hardcoded
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- ntfy notifications for an authentication failure now use a fixed,
|
|
19
|
+
generic message instead of the raw internal error text; other poll
|
|
20
|
+
failures still send the raw error message. The Homebridge log still
|
|
21
|
+
always shows the detailed error either way.
|
|
22
|
+
|
|
23
|
+
## [1.0.0] - 2026-07-26
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- README's license/changelog links now point to full GitHub URLs instead
|
|
27
|
+
of relative paths
|
|
28
|
+
- package.json now sets `author`, `homepage`, `bugs`, and `repository`, and
|
|
29
|
+
includes README/LICENSE/CHANGELOG in `files`
|
|
30
|
+
|
|
31
|
+
## [0.3.3] - 2026-07-26
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- CHANGELOG.md (this file)
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
- README restructured to match project conventions (versioned title,
|
|
38
|
+
Requirements/Usage sections, license/changelog links, Configuration/How
|
|
39
|
+
authentication works/When it stops working/Getting the trust cookie
|
|
40
|
+
nested under Usage)
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- LICENSE copyright name typo
|
|
44
|
+
|
|
45
|
+
## [0.3.2] - 2026-07-26
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
- Removed an inaccurate claim from the ntfy notification body about the
|
|
49
|
+
Home app continuing to show the last known reading
|
|
50
|
+
|
|
51
|
+
## [0.3.1] - 2026-07-25
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- Optional `ntfyTopic` config field: sends a push notification via
|
|
55
|
+
ntfy.sh the first time a poll fails, not repeated on every failure in
|
|
56
|
+
the same streak
|
|
57
|
+
|
|
58
|
+
### Changed
|
|
59
|
+
- Broadened package.json keywords for discoverability
|
|
60
|
+
- Simplified the README's authentication section wording
|
|
61
|
+
|
|
62
|
+
## [0.2.0] - 2026-07-25
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
- CO2/AirQuality/Temperature characteristics now use `onGet` handlers
|
|
66
|
+
backed by a cached last-known reading; the Home app shows "No Response"
|
|
67
|
+
once consecutive failures exceed a configurable threshold
|
|
68
|
+
(`noResponseAfterMissedPolls`, default 2, minimum 0), instead of relying
|
|
69
|
+
on `StatusFault`, which isn't reliably surfaced by the stock Home app
|
|
70
|
+
|
|
71
|
+
### Changed
|
|
72
|
+
- Replaced per-poll email/password login with a long-lived `session_key`
|
|
73
|
+
reused across polls and persisted across Homebridge restarts, falling
|
|
74
|
+
back to a full login only when that session actually expires (fixes an
|
|
75
|
+
account lockout caused by logging in fresh every 30 minutes)
|
|
76
|
+
|
|
77
|
+
## [0.1.5] - 2026-07-23
|
|
78
|
+
|
|
79
|
+
### Changed
|
|
80
|
+
- Replaced `.npmignore` with an explicit `"files"` whitelist in
|
|
81
|
+
package.json
|
|
82
|
+
|
|
83
|
+
## [0.1.4] - 2026-07-23
|
|
84
|
+
|
|
85
|
+
### Added
|
|
86
|
+
- `.npmignore` to keep editor/session folders and repo-only files out of
|
|
87
|
+
the published npm package
|
|
88
|
+
|
|
89
|
+
## [0.1.3] - 2026-07-23
|
|
90
|
+
|
|
91
|
+
### Added
|
|
92
|
+
- Homebridge platform plugin exposing CO2 (CarbonDioxideSensor +
|
|
93
|
+
AirQualitySensor) and room temperature (TemperatureSensor) as HomeKit
|
|
94
|
+
sensors, replacing the standalone scraper script
|
|
95
|
+
- Config UI based configuration instead of a `.env` file
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
- Simplified required config: dropped `w_uuid`, `deviceId`, `userId`, and
|
|
99
|
+
`appliver`; device/user IDs are now auto-discovered after login
|
|
100
|
+
- README cleaned up: deduplicated trust-cookie capture instructions,
|
|
101
|
+
added a plain-text credential storage warning, updated install
|
|
102
|
+
instructions for npm
|
|
103
|
+
|
|
104
|
+
### Fixed
|
|
105
|
+
- Corrected the real "trusted device" marker to the `2fa_token_<hash>`
|
|
106
|
+
cookie instead of `w_uuid`
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Homebridge Withings Environment Data
|
|
1
|
+
# Homebridge Withings Environment Data v1.1.0
|
|
2
2
|
|
|
3
3
|
**This Homebridge plugin has been 100% vibe coded with Claude.**
|
|
4
4
|
|
|
@@ -41,7 +41,8 @@ accessory:
|
|
|
41
41
|
- **CarbonDioxideSensor**: precise CO2 level in ppm, plus a normal/abnormal
|
|
42
42
|
detected alert based on a configurable threshold.
|
|
43
43
|
- **AirQualitySensor**: the same CO2 reading mapped to HomeKit's
|
|
44
|
-
Excellent/Good/Fair/Inferior/Poor category
|
|
44
|
+
Excellent/Good/Fair/Inferior/Poor category, based on configurable ppm
|
|
45
|
+
thresholds.
|
|
45
46
|
- **TemperatureSensor**: room temperature in °C.
|
|
46
47
|
|
|
47
48
|
These appear automatically in the Home app after Homebridge restarts, no
|
|
@@ -68,6 +69,9 @@ Fields:
|
|
|
68
69
|
matching the scale's own upload cadence).
|
|
69
70
|
- **CO2 Detected Threshold (ppm)**: ppm above which the CarbonDioxideSensor
|
|
70
71
|
reports "abnormal" (default 1000).
|
|
72
|
+
- **Air Quality: Excellent/Good/Fair/Inferior below (ppm)**: the four ppm
|
|
73
|
+
boundaries the AirQualitySensor category is based on (defaults 800, 1000,
|
|
74
|
+
1500, 2000).
|
|
71
75
|
- **ntfy Topic (optional)**: if set, sends a push notification via
|
|
72
76
|
[ntfy.sh](https://ntfy.sh) to this topic the first time a poll fails
|
|
73
77
|
(not repeated on every subsequent failure in the same streak; only once
|
|
@@ -126,5 +130,5 @@ it once via DevTools:
|
|
|
126
130
|
|
|
127
131
|
## License and changelog
|
|
128
132
|
|
|
129
|
-
- [LICENSE](LICENSE)
|
|
130
|
-
- [CHANGELOG](CHANGELOG.md)
|
|
133
|
+
- [LICENSE](https://github.com/LuudJacobs/homebridge-withings-environment-data/blob/main/LICENSE)
|
|
134
|
+
- [CHANGELOG](https://github.com/LuudJacobs/homebridge-withings-environment-data/blob/main/CHANGELOG.md)
|
package/config.schema.json
CHANGED
|
@@ -49,6 +49,34 @@
|
|
|
49
49
|
"default": 1000,
|
|
50
50
|
"minimum": 400
|
|
51
51
|
},
|
|
52
|
+
"airQualityExcellentMaxPpm": {
|
|
53
|
+
"title": "Air Quality: Excellent below (ppm)",
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"default": 800,
|
|
56
|
+
"minimum": 1,
|
|
57
|
+
"description": "CO2 readings below this are reported as Excellent air quality."
|
|
58
|
+
},
|
|
59
|
+
"airQualityGoodMaxPpm": {
|
|
60
|
+
"title": "Air Quality: Good below (ppm)",
|
|
61
|
+
"type": "integer",
|
|
62
|
+
"default": 1000,
|
|
63
|
+
"minimum": 1,
|
|
64
|
+
"description": "CO2 readings below this are reported as Good."
|
|
65
|
+
},
|
|
66
|
+
"airQualityFairMaxPpm": {
|
|
67
|
+
"title": "Air Quality: Fair below (ppm)",
|
|
68
|
+
"type": "integer",
|
|
69
|
+
"default": 1500,
|
|
70
|
+
"minimum": 1,
|
|
71
|
+
"description": "CO2 readings below this are reported as Fair."
|
|
72
|
+
},
|
|
73
|
+
"airQualityInferiorMaxPpm": {
|
|
74
|
+
"title": "Air Quality: Inferior below (ppm)",
|
|
75
|
+
"type": "integer",
|
|
76
|
+
"default": 2000,
|
|
77
|
+
"minimum": 1,
|
|
78
|
+
"description": "CO2 readings below this are reported as Inferior. Anything above is reported as Poor."
|
|
79
|
+
},
|
|
52
80
|
"noResponseAfterMissedPolls": {
|
|
53
81
|
"title": "No Response After Missed Polls",
|
|
54
82
|
"type": "integer",
|
package/index.js
CHANGED
|
@@ -63,11 +63,11 @@ async function fetchLatest({ cookieHeader, sessionToken, deviceId, userId }) {
|
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
function mapCo2ToAirQuality(ppm, AirQuality) {
|
|
67
|
-
if (ppm <
|
|
68
|
-
if (ppm <
|
|
69
|
-
if (ppm <
|
|
70
|
-
if (ppm <
|
|
66
|
+
function mapCo2ToAirQuality(ppm, AirQuality, thresholds) {
|
|
67
|
+
if (ppm < thresholds.excellentMaxPpm) return AirQuality.EXCELLENT;
|
|
68
|
+
if (ppm < thresholds.goodMaxPpm) return AirQuality.GOOD;
|
|
69
|
+
if (ppm < thresholds.fairMaxPpm) return AirQuality.FAIR;
|
|
70
|
+
if (ppm < thresholds.inferiorMaxPpm) return AirQuality.INFERIOR;
|
|
71
71
|
return AirQuality.POOR;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -216,7 +216,13 @@ class WithingsEnvironmentDataPlatform {
|
|
|
216
216
|
|
|
217
217
|
async poll() {
|
|
218
218
|
try {
|
|
219
|
-
|
|
219
|
+
let cookieHeader, sessionToken;
|
|
220
|
+
try {
|
|
221
|
+
({ cookieHeader, sessionToken } = await this.authenticate());
|
|
222
|
+
} catch (err) {
|
|
223
|
+
err.isAuthFailure = true;
|
|
224
|
+
throw err;
|
|
225
|
+
}
|
|
220
226
|
|
|
221
227
|
if (!this.deviceId || !this.userId) {
|
|
222
228
|
const discovered = await discoverDevice(cookieHeader);
|
|
@@ -252,7 +258,10 @@ class WithingsEnvironmentDataPlatform {
|
|
|
252
258
|
|
|
253
259
|
if (!this.hasNotifiedFailure) {
|
|
254
260
|
this.hasNotifiedFailure = true;
|
|
255
|
-
|
|
261
|
+
const notificationMessage = err.isAuthFailure
|
|
262
|
+
? 'Authentication for Withings account failed. Check the Homebridge logs for details.'
|
|
263
|
+
: err.message;
|
|
264
|
+
await this.sendNtfyNotification(notificationMessage);
|
|
256
265
|
}
|
|
257
266
|
}
|
|
258
267
|
}
|
|
@@ -282,6 +291,19 @@ class WithingsEnvironmentDataPlatform {
|
|
|
282
291
|
return Number.isFinite(threshold) && threshold >= 0 ? threshold : 2;
|
|
283
292
|
}
|
|
284
293
|
|
|
294
|
+
getAirQualityThresholds() {
|
|
295
|
+
const excellentMaxPpm = Number(this.config.airQualityExcellentMaxPpm);
|
|
296
|
+
const goodMaxPpm = Number(this.config.airQualityGoodMaxPpm);
|
|
297
|
+
const fairMaxPpm = Number(this.config.airQualityFairMaxPpm);
|
|
298
|
+
const inferiorMaxPpm = Number(this.config.airQualityInferiorMaxPpm);
|
|
299
|
+
return {
|
|
300
|
+
excellentMaxPpm: Number.isFinite(excellentMaxPpm) && excellentMaxPpm > 0 ? excellentMaxPpm : 800,
|
|
301
|
+
goodMaxPpm: Number.isFinite(goodMaxPpm) && goodMaxPpm > 0 ? goodMaxPpm : 1000,
|
|
302
|
+
fairMaxPpm: Number.isFinite(fairMaxPpm) && fairMaxPpm > 0 ? fairMaxPpm : 1500,
|
|
303
|
+
inferiorMaxPpm: Number.isFinite(inferiorMaxPpm) && inferiorMaxPpm > 0 ? inferiorMaxPpm : 2000,
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
285
307
|
isStale() {
|
|
286
308
|
return !this.hasEverSucceeded || this.missedCycles > this.getNoResponseThreshold();
|
|
287
309
|
}
|
|
@@ -306,7 +328,7 @@ class WithingsEnvironmentDataPlatform {
|
|
|
306
328
|
|
|
307
329
|
getAirQualityOrThrow() {
|
|
308
330
|
this.throwIfStale();
|
|
309
|
-
return mapCo2ToAirQuality(this.lastReading.co2, this.Characteristic.AirQuality);
|
|
331
|
+
return mapCo2ToAirQuality(this.lastReading.co2, this.Characteristic.AirQuality, this.getAirQualityThresholds());
|
|
310
332
|
}
|
|
311
333
|
|
|
312
334
|
getTemperatureOrThrow() {
|
package/package.json
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-withings-environment-data",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Homebridge plugin exposing ambient CO2/air-quality and room temperature readings from a Withings WS-50 scale as HomeKit sensors",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"index.js",
|
|
8
8
|
"lib",
|
|
9
|
-
"config.schema.json"
|
|
9
|
+
"config.schema.json",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE",
|
|
12
|
+
"CHANGELOG.md"
|
|
10
13
|
],
|
|
11
14
|
"keywords": [
|
|
12
15
|
"homebridge-plugin",
|
|
@@ -18,9 +21,18 @@
|
|
|
18
21
|
"air-quality",
|
|
19
22
|
"homekit"
|
|
20
23
|
],
|
|
24
|
+
"author": "Luud Jacobs",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"homepage": "https://github.com/LuudJacobs/homebridge-withings-environment-data#readme",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/LuudJacobs/homebridge-withings-environment-data/issues"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/LuudJacobs/homebridge-withings-environment-data.git"
|
|
33
|
+
},
|
|
21
34
|
"engines": {
|
|
22
35
|
"homebridge": ">=1.6.0",
|
|
23
36
|
"node": ">=18"
|
|
24
|
-
}
|
|
25
|
-
"license": "MIT"
|
|
37
|
+
}
|
|
26
38
|
}
|