homebridge-powerview-universal 4.3.2
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 +338 -0
- package/LICENSE +18 -0
- package/README.md +129 -0
- package/RELEASE_NOTES.md +257 -0
- package/config.schema.json +131 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/hubCapabilities.d.ts +21 -0
- package/dist/hubCapabilities.js +78 -0
- package/dist/hubCapabilities.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/platform.d.ts +113 -0
- package/dist/platform.js +797 -0
- package/dist/platform.js.map +1 -0
- package/dist/platformAccessory.d.ts +52 -0
- package/dist/platformAccessory.js +410 -0
- package/dist/platformAccessory.js.map +1 -0
- package/dist/powerviewHub.d.ts +133 -0
- package/dist/powerviewHub.js +459 -0
- package/dist/powerviewHub.js.map +1 -0
- package/dist/settings.d.ts +102 -0
- package/dist/settings.js +75 -0
- package/dist/settings.js.map +1 -0
- package/dist/shadeUtils.d.ts +138 -0
- package/dist/shadeUtils.js +292 -0
- package/dist/shadeUtils.js.map +1 -0
- package/package.json +58 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
## [4.3.2] - 2026-09-04
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Lint error in the test suite that failed the release build (`no-unused-vars`). No runtime change.
|
|
10
|
+
|
|
11
|
+
## [4.3.1] - 2026-09-04
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Scene activation no longer reports a shade count it does not have.** `activateScene` defaulted
|
|
16
|
+
a missing `shadeIds` to an empty list, so a gen1 hub — which answers an activation without that
|
|
17
|
+
field — produced `Scene 4102 activated (0 shade(s))` while five shades were visibly moving. The
|
|
18
|
+
count is now logged only when the hub supplies one.
|
|
19
|
+
|
|
20
|
+
### Notes
|
|
21
|
+
|
|
22
|
+
- Scene activation is no longer unverified: it was confirmed end to end against a live scene on a
|
|
23
|
+
gen1 hub (build 827), activated from the HomeKit switch, moving five shades to the scene's
|
|
24
|
+
position.
|
|
25
|
+
|
|
26
|
+
## [4.3.0] - 2026-09-04
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Hub scenes are exposed as HomeKit switches** (`exposeScenes`, default on). Activating one is a
|
|
31
|
+
single hub call that the hub expands itself, so every motor gets its RF command at once. Driving
|
|
32
|
+
the same shades individually costs one serialised write each and they visibly stagger — this is
|
|
33
|
+
why a Pebble remote closes a group in unison and the plugin could not. Nothing appears unless
|
|
34
|
+
scenes are defined in the PowerView app. Switches are stateless: they fire and reset.
|
|
35
|
+
- Scene accessories survive restarts, and are never removed on an empty scene list — the same
|
|
36
|
+
rule that stopped a partial response destroying shade accessories in 4.1.2.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **Shades are reported as moving rather than arrived.** `setPosition` fed the hub's PUT reply
|
|
41
|
+
into `CurrentPosition`, and that reply echoes the target, so a shade with seconds of travel left
|
|
42
|
+
read as already there; `PositionState` was hardcoded to `STOPPED`, the only value it ever took.
|
|
43
|
+
`TargetPosition` is now the commanded value, `CurrentPosition` stays where the shade is, and the
|
|
44
|
+
state reports `INCREASING`/`DECREASING` until the estimated travel elapses. A re-target
|
|
45
|
+
mid-travel cancels the previous arrival, which would otherwise land later and park the shade at
|
|
46
|
+
a position it had been steered away from.
|
|
47
|
+
- **Startup no longer waits on the position sync.** It does an RF read per shade the hub has no
|
|
48
|
+
position for — five motors and 82 seconds from init to ready in one observed startup. It now
|
|
49
|
+
runs behind launch and abandons itself on shutdown.
|
|
50
|
+
|
|
51
|
+
### Notes
|
|
52
|
+
|
|
53
|
+
- Arrival is estimated from `SHADE_FULL_TRAVEL_MS` (20s for the full range) rather than polled.
|
|
54
|
+
Confirming it would mean an RF round-trip that wakes the motor again the instant it stopped. Any
|
|
55
|
+
later refresh corrects the value.
|
|
56
|
+
- Scene **activation** is implemented against the documented PowerView v2 API but has not been
|
|
57
|
+
verified against a live scene, because the hub it was developed on has none defined.
|
|
58
|
+
|
|
59
|
+
## [4.2.0] - 2026-09-04
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- **HomeKit position reads no longer wait on the hub.** The non-blocking work in 1061351 removed
|
|
64
|
+
only the RF refresh from the read path; every read still awaited a cached hub round-trip. Those
|
|
65
|
+
are serialised, so opening the Home app — which reads every characteristic of every shade at
|
|
66
|
+
once — queued them and the later ones exceeded HomeKit's budget, logging "read handler was slow
|
|
67
|
+
to respond" (15 in one startup on a five-shade system). A read with a cached position now
|
|
68
|
+
answers immediately and refreshes behind the answer. `refreshShades` and `strictErrors` both opt
|
|
69
|
+
into hitting the hub and keep the blocking path.
|
|
70
|
+
- **Background refreshes no longer wake the motor.** `scheduleBackgroundRefresh` always passed
|
|
71
|
+
`refresh=true`, an RF round-trip that spins the shade and takes seconds. That is now reserved
|
|
72
|
+
for the case it was meant for — the hub having no position at all. Servicing an ordinary read
|
|
73
|
+
uses the cheap cached read, rate limited to one per shade per
|
|
74
|
+
`BACKGROUND_REFRESH_INTERVAL_MS` (10s) so a burst of reads cannot stack up.
|
|
75
|
+
|
|
76
|
+
## [4.1.2] - 2026-09-04
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **A partial hub response no longer destroys HomeKit accessories.** `updateShades()`
|
|
81
|
+
unregistered any accessory missing from a *single* `/api/shades` response. Upstream guarded
|
|
82
|
+
against the list request outright failing, but not against it coming back short — and a gen1
|
|
83
|
+
hub under load does answer short. Observed live: three of five shades were unregistered in one
|
|
84
|
+
poll, taking their rooms and automations with them, and "close all" then moved only the two
|
|
85
|
+
that survived. A shade must now be absent from `SHADE_REMOVAL_THRESHOLD` (3) consecutive lists
|
|
86
|
+
before its accessory is removed, each miss is logged, and an empty list never prunes anything.
|
|
87
|
+
|
|
88
|
+
## [4.1.1] - 2026-09-04
|
|
89
|
+
|
|
90
|
+
### Fixed
|
|
91
|
+
|
|
92
|
+
- **A dropped connection no longer loses the command outright.** Only HTTP 423 was retried, so a
|
|
93
|
+
bare `fetch failed` — which is what a gen1 hub gives you when it drops a TCP connection while
|
|
94
|
+
its radio is transmitting — threw immediately and the shade never moved. Transient network
|
|
95
|
+
failures now retry three times, 500ms apart.
|
|
96
|
+
|
|
97
|
+
### Changed
|
|
98
|
+
|
|
99
|
+
- **`requestIntervalMs` returns to a 100ms default**, reverting the 25ms introduced in 4.1.0. The
|
|
100
|
+
probe behind that number ran cached reads, which never engage the hub's radio; writes do. In
|
|
101
|
+
practice a five-shade group move at 25ms lost two shades to dropped connections. The option
|
|
102
|
+
stays, so the spacing can still be retuned — against writes, not just reads.
|
|
103
|
+
|
|
104
|
+
## [4.1.0] - 2026-09-04
|
|
105
|
+
|
|
106
|
+
### Added
|
|
107
|
+
|
|
108
|
+
- `requestIntervalMs` (default `25`), exposed in the Homebridge UI schema. Spacing between
|
|
109
|
+
serialised hub requests, so a hub that struggles under load can be given more room without a
|
|
110
|
+
code change.
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- **HomeKit writes now overtake background reads.** The request queue was strictly FIFO, so a
|
|
115
|
+
shade command issued while a refresh was in flight waited for that refresh and for every read
|
|
116
|
+
queued ahead of it. Writes now run first, FIFO within a priority, still one request at a time
|
|
117
|
+
because the hub cannot do better.
|
|
118
|
+
- **Request spacing drops from 100ms to 25ms.** Measured, not guessed: 30 serialised reads
|
|
119
|
+
against a gen1 hub on build 827 at 100/50/25/10/0ms spacing returned 30/30 valid responses in
|
|
120
|
+
every condition — no bad status, no malformed JSON, no timeouts — with response times flat at
|
|
121
|
+
~70ms. 25ms keeps headroom rather than removing the guard.
|
|
122
|
+
- The spacing delay no longer runs after the final request, only between requests.
|
|
123
|
+
|
|
124
|
+
### Notes
|
|
125
|
+
|
|
126
|
+
- This takes roughly 375ms off a five-shade group move, but does not make shades move in unison.
|
|
127
|
+
Five sequential round-trips are ~350ms of irreducible spread. Only a hub scene, which is one
|
|
128
|
+
call the hub expands itself, can move a group together — scene support is not implemented yet.
|
|
129
|
+
|
|
130
|
+
## [4.0.0] - 2026-09-04
|
|
131
|
+
|
|
132
|
+
First release under the name **homebridge-powerview-universal**. Consolidates the
|
|
133
|
+
`3.1.4-local.1` … `3.1.4-local.8` working versions, none of which were published.
|
|
134
|
+
All hub behaviour below was verified against a PowerView hub on firmware build 827.
|
|
135
|
+
|
|
136
|
+
Major rather than minor: the npm package is renamed, so this does not upgrade in
|
|
137
|
+
place — the old package must be uninstalled and this one installed. `PLUGIN_NAME`
|
|
138
|
+
changes with it, which migrates the cached accessories. Battery polling also
|
|
139
|
+
changes from on-by-default to off-by-default.
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- `batteryPolling` (boolean, default `false`) and `batteryPollAt` (`"HH:MM"`, default `14:00`)
|
|
144
|
+
config options, both exposed in the Homebridge UI schema.
|
|
145
|
+
- `syncPositionsOnStart` (boolean, default `true`) and `quietHours` (default 21:00–08:00).
|
|
146
|
+
Homebridge can restart unattended, so the startup position sync is skipped inside the quiet
|
|
147
|
+
window rather than being free to wake every motor at 03:00.
|
|
148
|
+
- `PowerViewHub.stopShade()`; `jogShade` and `stopShade` now share one `motionRequest` path.
|
|
149
|
+
- An ISC `LICENSE` file, naming the full copyright chain from 2018 onward.
|
|
150
|
+
|
|
151
|
+
### Changed
|
|
152
|
+
|
|
153
|
+
- **Battery polling is now opt-in and off by default.** It previously ran every 6 hours on a
|
|
154
|
+
timer anchored to plugin start, with no config option. `updateBatteryLevel=true` is an RF
|
|
155
|
+
round-trip that wakes the shade motor — 3.73s against 0.08s for a cached read, audible, and it
|
|
156
|
+
nudges the shade. On a 6-hour period at least one poll always landed overnight regardless of
|
|
157
|
+
restart time; observed waking a household at 05:54 (5 shades). The hub already refreshes
|
|
158
|
+
battery weekly on its own, which is what makes off-by-default correct rather than merely quiet.
|
|
159
|
+
- Polling, when enabled, runs **once per day at a configurable local time** instead of on an
|
|
160
|
+
interval. The next deadline is recomputed from the current time after every run, so the poll
|
|
161
|
+
stays pinned to the same wall-clock time across DST changes. Runs are logged at `info`; the old
|
|
162
|
+
poll logged nothing on success, which is why the shade movement could not be attributed.
|
|
163
|
+
- **Shade behaviour is resolved from ShadeCapabilities, not from a hand-picked type list.** The
|
|
164
|
+
old `SHADE_TYPE_IDS` knew 6 shade types; the PowerView Hub REST API v2 appendix
|
|
165
|
+
(jlaur/hdpowerview-doc v1.0.4) documents **26**, mapped onto 10 capability classes. That left
|
|
166
|
+
20 types falling through to "unknown type, assuming roller", and for 17 of them roller is
|
|
167
|
+
wrong. Capability now comes from the hub's own `capabilities` field when it reports one, and
|
|
168
|
+
from the documented type table otherwise — older hubs, including build 827, omit the field.
|
|
169
|
+
- **Unsupported capabilities are stated rather than silently mistreated.** Capability 6 runs its
|
|
170
|
+
primary rail *reversed*, 2 and 5 tilt through 180 degrees rather than the 90 the tilt maths
|
|
171
|
+
assumes, and 8/9 have overlapped panels. These are still driven as rollers, but now warn once
|
|
172
|
+
per shade that position or tilt may be wrong instead of reporting a confident wrong number.
|
|
173
|
+
Implementing their maths needs hardware to verify against, so it is not guessed at here.
|
|
174
|
+
- **Every hub request is serialised through one promise chain** with `REQUEST_INTERVAL_MS`
|
|
175
|
+
spacing. Legacy hubs answer one request at a time, but only shade requests went through the
|
|
176
|
+
existing queue — capability probes and `/api/shades` called `fetchJson` directly and raced it,
|
|
177
|
+
which made the hub time out and return truncated JSON mid-response.
|
|
178
|
+
- **HomeKit position reads answer from cache immediately** and refresh in the background, deduped
|
|
179
|
+
per shade. The old blocking refresh inside the read handler routinely exceeded HomeKit's read
|
|
180
|
+
budget and logged "read handler didn't respond at all". `strictErrors` keeps the old blocking
|
|
181
|
+
behaviour, since that option exists to surface hub failures.
|
|
182
|
+
- Positions are logged only when they change, and the message says what it is. `Set for <id>`
|
|
183
|
+
fired at `info` on every read — four identical lines in twelve seconds during one restart — and
|
|
184
|
+
read like a write when it was a read.
|
|
185
|
+
- Errors preserve the underlying failure as `cause`, and timeouts are distinguished from
|
|
186
|
+
unreachable hosts instead of every failure reporting as Unreachable.
|
|
187
|
+
- `PositionMap` is defined once in `shadeUtils.ts` instead of being redeclared in `platform.ts`.
|
|
188
|
+
- **A poll costs half the hub requests it did.** `/api/shades` already returns each shade, but the
|
|
189
|
+
loop then called `getShade(id)` for every one, so N shades meant 2N serialised requests per
|
|
190
|
+
cycle. The per-shade fetch now runs only when the list entry carried no positions.
|
|
191
|
+
- Package renamed to `homebridge-powerview-universal`; repository, bugs, and homepage links now
|
|
192
|
+
point at this fork rather than upstream's tracker.
|
|
193
|
+
|
|
194
|
+
### Fixed
|
|
195
|
+
|
|
196
|
+
- **Hub requests still overlapped after being serialised.** `serialize()` wrapped only the
|
|
197
|
+
`fetch()` call, and `fetch()` settles when response headers arrive, not when the body is
|
|
198
|
+
consumed — so `response.json()` ran after the chain had already advanced, streaming one
|
|
199
|
+
request's body while the next request was already in flight. That is the overlap that makes a
|
|
200
|
+
legacy hub time out and return truncated JSON. The body is now read inside the serialised
|
|
201
|
+
section.
|
|
202
|
+
- **A tilt report no longer forces the shade to read as fully closed.** Both vanes branches
|
|
203
|
+
called `applyCoveringPosition(service, 0)`, so `posKind1` set the real position and `posKind2`
|
|
204
|
+
immediately overwrote it with 0 in the same loop. Every tilt-capable shade reported itself
|
|
205
|
+
closed while the cache held the true value.
|
|
206
|
+
- **Restarts no longer report a shade as fully closed.** `configure()` seeded `CurrentPosition`
|
|
207
|
+
to 0 unconditionally, running on every restart immediately after the cache was restored — so
|
|
208
|
+
the persisted position was overwritten before HomeKit could read it. It now seeds from the
|
|
209
|
+
cache for both rails.
|
|
210
|
+
- **The shade poll no longer survives shutdown.** Its `setTimeout` handle was never stored, so
|
|
211
|
+
the shutdown listener could not clear it; with `pollShadesForUpdate` enabled, shutdown left a
|
|
212
|
+
30s loop hitting the hub and holding the event loop open.
|
|
213
|
+
- **A position set for a removed shade reports an error instead of crashing.** `setPosition` read
|
|
214
|
+
`this.accessories[shadeId].context` unguarded, before its `try`, so the throw escaped the
|
|
215
|
+
HomeKit handler as an unhandled rejection.
|
|
216
|
+
- **Every reported position kind is read.** The loop terminated at the first absent `posKind` and
|
|
217
|
+
silently dropped every kind after a gap.
|
|
218
|
+
- **An unusable position value is skipped rather than cached as `NaN`.** HAP rejected the
|
|
219
|
+
characteristic write, but the `NaN` still reached the position map, where it defeats
|
|
220
|
+
`positionMapsEqual` — `NaN !== NaN` — so every subsequent read rewrote the accessory cache file.
|
|
221
|
+
- **Requests could hang forever.** Node's `fetch` has no default timeout and the hub serialises
|
|
222
|
+
every call through one queue, so a half-open socket stalled all later requests indefinitely.
|
|
223
|
+
Every hub request now carries a 15s `AbortController` timeout.
|
|
224
|
+
- **A throw during shade URL construction wedged the queue**, leaving pending HomeKit requests
|
|
225
|
+
unresolved. The URL is built inside the `try` and the queue advances in a `finally`.
|
|
226
|
+
- **Battery percentage was wrong above 100.** `batteryStrength` is tenths of a volt against an
|
|
227
|
+
18.0V nominal pack (matching aiopvapi), not a 0–100 percentage. Any Gen 1/2 reading above 100
|
|
228
|
+
fell through to a four-value `batteryStatus` lookup, so a pack at 67% and one at 98% both
|
|
229
|
+
reported 90%.
|
|
230
|
+
- **`batteryStrength` 0 is treated as unknown rather than empty.** The hub reports 0 for shades it
|
|
231
|
+
has not polled, which raised a false low-battery warning.
|
|
232
|
+
- **`StatusLowBattery` is no longer set on `AccessoryInformation`**, where it is not a valid
|
|
233
|
+
characteristic and logged a warning per shade per refresh.
|
|
234
|
+
- **Hub generation is derived from the firmware revision.** Both Gen 1 and Gen 2 report
|
|
235
|
+
`mainProcessor.name` as "PowerView Hub", so the name never matched.
|
|
236
|
+
- **`Invalid position value received` no longer fires on the happy path.** This hub returns no
|
|
237
|
+
`positions` object at all on a cached read — positions exist only after a `refresh=true` read or
|
|
238
|
+
a set — so the key was absent on *every* HomeKit position read and the warning fired 77 times in
|
|
239
|
+
one day. Absent is now `debug` plus a once-per-shade `info`; only a key present with unusable
|
|
240
|
+
data still warns, and the message includes the value.
|
|
241
|
+
- **Last known positions persist across restarts**, written to accessory context via
|
|
242
|
+
`api.updatePlatformAccessories()` and restored (validated) in `configureAccessory`. A cold cache
|
|
243
|
+
no longer falls through to `resolvePositionValue()`'s `0`, which reads as "fully closed" in the
|
|
244
|
+
Home app until the background refresh lands, and sticks if that refresh times out. Writes are
|
|
245
|
+
guarded by `positionMapsEqual` so an ordinary read that changes nothing does not rewrite the
|
|
246
|
+
cache file.
|
|
247
|
+
- **Positions are re-synced once at startup** for shades the hub has no position for. Persisting
|
|
248
|
+
the cache meant `value == null` was never true, so `scheduleBackgroundRefresh` never fired and a
|
|
249
|
+
stale position could be served indefinitely.
|
|
250
|
+
- **HoldPosition jogged the shade instead of stopping it.** HomeKit's `HoldPosition` was wired to
|
|
251
|
+
`jogShade`, so asking a shade to stop made it wiggle. It now sends `motion: "stop"`, and is no
|
|
252
|
+
longer gated on `jogSupported`, which was the wrong capability.
|
|
253
|
+
- **`PLUGIN_NAME` now matches the package name.** It still read `homebridge-powerview-3` after the
|
|
254
|
+
rename, so Homebridge could not resolve the plugin when registering accessories and logged a
|
|
255
|
+
warning for every shade.
|
|
256
|
+
- `probeEndpoint` is given an absolute URL so it cannot throw if it is ever used.
|
|
257
|
+
|
|
258
|
+
### Removed
|
|
259
|
+
|
|
260
|
+
- `SHADE_TYPE_IDS`. It listed type 16, which appears nowhere in the published table, and omitted
|
|
261
|
+
the actual vertical shades (54, 55, 56).
|
|
262
|
+
|
|
263
|
+
### Notes
|
|
264
|
+
|
|
265
|
+
- Disabling the battery poll does not remove battery reporting: `batteryStrength` /
|
|
266
|
+
`batteryStatus` ride along on ordinary hub reads and still update the HomeKit Battery service.
|
|
267
|
+
The poll only forces a fresh measurement from the shade.
|
|
268
|
+
- On first start under the new package name, Homebridge re-associates cached accessories from
|
|
269
|
+
`homebridge-powerview-3` to `homebridge-powerview-universal` automatically and logs that it did
|
|
270
|
+
so. Uninstall the old package first — if both are installed, both claim the `PowerView` platform
|
|
271
|
+
name and cached accessories are dropped instead.
|
|
272
|
+
|
|
273
|
+
## [3.1.2] - 2026-05-18
|
|
274
|
+
|
|
275
|
+
### Added
|
|
276
|
+
|
|
277
|
+
- [RELEASE_NOTES.md](RELEASE_NOTES.md) for publish/GitHub release copy (see Latest section when tagging)
|
|
278
|
+
|
|
279
|
+
## [3.1.1] - 2026-05-18
|
|
280
|
+
|
|
281
|
+
### Added
|
|
282
|
+
|
|
283
|
+
- Linked HomeKit **Battery** service per shade with `BatteryLevel` (0–100%) so battery appears in the Home app, not only the low-battery flag on Accessory Information
|
|
284
|
+
|
|
285
|
+
## [3.1.0] - 2026-05-18
|
|
286
|
+
|
|
287
|
+
### Added
|
|
288
|
+
|
|
289
|
+
- Structured hub HTTP handling with retry on HTTP 423 (hub busy / maintenance)
|
|
290
|
+
- Startup capability probe for `/api/fwversion`, `/api/scenes`, and `/api/scenecollections` (logged; scenes not exposed in HomeKit yet)
|
|
291
|
+
- Position cache: refresh timeouts and transient read failures return last known values (unless `strictErrors` is enabled)
|
|
292
|
+
- `strictErrors` platform option for fail-fast HomeKit reads (debugging)
|
|
293
|
+
- Per-shade `FirmwareRevision` and `StatusLowBattery` in Accessory Information when the hub reports them
|
|
294
|
+
- Periodic battery refresh via `updateBatteryLevel` (every 6 hours)
|
|
295
|
+
- Top/bottom shade top-rail display name from hub `secondaryName`
|
|
296
|
+
- **Hold** (Hold Position) and **Identify** wired to hub jog motion where supported
|
|
297
|
+
- Vitest unit tests for HTTP classification, position parsing, and battery helpers
|
|
298
|
+
|
|
299
|
+
### Changed
|
|
300
|
+
|
|
301
|
+
- `putShade` queue merge skips invalid position kind 4 (hub position error) from PUT bodies
|
|
302
|
+
- Shade list failures during poll no longer remove existing accessories
|
|
303
|
+
|
|
304
|
+
## [3.0.0] - 2026-05-17
|
|
305
|
+
|
|
306
|
+
### Added
|
|
307
|
+
|
|
308
|
+
- Homebridge **2.x** support (ESM plugin, Node.js 22/24)
|
|
309
|
+
- TypeScript source, `config.schema.json` for Homebridge UI settings
|
|
310
|
+
- `AccessoryInformation` service on each shade (manufacturer, hub firmware model)
|
|
311
|
+
|
|
312
|
+
### Changed
|
|
313
|
+
|
|
314
|
+
- **Breaking:** npm package renamed to `homebridge-powerview-3`
|
|
315
|
+
- **Breaking:** plugin identifier for accessory cache is now `homebridge-powerview-3` (was `homebridge-powerview`)
|
|
316
|
+
- Replaced deprecated `request` with native `fetch`
|
|
317
|
+
- Replaced `getServiceByUUIDAndSubType` with `getServiceById` (Homebridge 2 API)
|
|
318
|
+
- Removed use of removed `accessory.reachable` property
|
|
319
|
+
- Modern `api.registerPlatform(PLATFORM_NAME, PowerViewPlatform)` registration
|
|
320
|
+
- Hub HTTP client uses Promises/async throughout
|
|
321
|
+
|
|
322
|
+
### Fixed
|
|
323
|
+
|
|
324
|
+
- `putShade` queue merge incorrectly deleted bottom position (`delete position[...]` → `delete positions[...]`)
|
|
325
|
+
- `jogShade` callback referenced undefined `position` variable
|
|
326
|
+
- `removeService` called when top Window Covering service did not exist
|
|
327
|
+
|
|
328
|
+
### Migration from homebridge-powerview-2
|
|
329
|
+
|
|
330
|
+
1. Uninstall `homebridge-powerview-2`, install `homebridge-powerview-3`.
|
|
331
|
+
2. Keep `"platform": "PowerView"` in `config.json`; add `"name": "PowerView"` if using the config UI schema.
|
|
332
|
+
3. Restart Homebridge. Remove duplicate shade accessories from the Home app if the cache identifier change left orphans.
|
|
333
|
+
|
|
334
|
+
Requires Homebridge **^1.8.0 || ^2.0.0** and Node **^22.12.0 || ^24.0.0**.
|
|
335
|
+
|
|
336
|
+
## [1.0.9] and earlier
|
|
337
|
+
|
|
338
|
+
See [homebridge-powerview-2](https://github.com/owenselles/homebridge-powerview-2) history.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Scott James Remnant
|
|
4
|
+
Copyright (c) 2023 Owen Selles
|
|
5
|
+
Copyright (c) 2026 squircle12
|
|
6
|
+
Copyright (c) 2026 sunnierseattle
|
|
7
|
+
|
|
8
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
10
|
+
copyright notice and this permission notice appear in all copies.
|
|
11
|
+
|
|
12
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
13
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
14
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
15
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
16
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
17
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
18
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# homebridge-powerview-universal
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/homebridge-powerview-universal)
|
|
4
|
+
[](https://www.npmjs.com/package/homebridge-powerview-universal)
|
|
5
|
+
|
|
6
|
+
Homebridge plugin for [Hunter Douglas PowerView](https://www.hunterdouglas.com/operating-systems/motorized/powerview-motorization) window shades. Compatible with **Homebridge 1.8+** and **Homebridge 2.x** (Node.js 22 or 24).
|
|
7
|
+
|
|
8
|
+
Supports Generation 1 and 2 PowerView hubs.
|
|
9
|
+
|
|
10
|
+
> **Credits.** This is a fork of [squircle12/homebridge-powerview-3](https://github.com/squircle12/homebridge-powerview-3), itself a TypeScript rewrite of [owenselles/homebridge-powerview-2](https://github.com/owenselles/homebridge-powerview-2), originally by [Scott James Remnant](https://github.com/keybuk). The full upstream commit history is preserved in this repository. This fork adds fixes to hub request serialisation, position reporting, battery scaling, and shade capability detection.
|
|
11
|
+
|
|
12
|
+
## Requirements
|
|
13
|
+
|
|
14
|
+
- [Homebridge](https://github.com/homebridge/homebridge) **1.8.0** or **2.0.0**
|
|
15
|
+
- Node.js **22** or **24**
|
|
16
|
+
|
|
17
|
+
## Supported shades
|
|
18
|
+
|
|
19
|
+
- Roller shades
|
|
20
|
+
- Horizontal vane shades (e.g. Silhouette, Pirouette) — position plus tilt in Details
|
|
21
|
+
- Vertical vane shades (e.g. Luminette) — position plus tilt in Details
|
|
22
|
+
- Top-down/bottom-up shades (e.g. Duette) — two Window Covering services per shade
|
|
23
|
+
|
|
24
|
+
Shades work in HomeKit scenes and automations.
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
1. Install and set up [Homebridge](https://github.com/homebridge/homebridge).
|
|
29
|
+
2. Install the plugin (Homebridge UI **Plugins** tab, or CLI):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g homebridge-powerview-universal
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
3. Add the **PowerView** platform via the plugin **Settings** button in the Homebridge UI, or add a platform block to `config.json`:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
"platforms": [
|
|
39
|
+
{
|
|
40
|
+
"platform": "PowerView",
|
|
41
|
+
"name": "PowerView"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The hub is contacted at `powerview-hub.local` by default.
|
|
47
|
+
|
|
48
|
+
## Configuration
|
|
49
|
+
|
|
50
|
+
| Option | Description | Default |
|
|
51
|
+
|--------|-------------|---------|
|
|
52
|
+
| `name` | Platform name in Homebridge | `PowerView` |
|
|
53
|
+
| `host` | Hub hostname or IP | `powerview-hub.local` |
|
|
54
|
+
| `refreshShades` | Request fresh positions from the hub on every HomeKit read | `false` |
|
|
55
|
+
| `pollShadesForUpdate` | Poll the hub every 30 seconds for position updates | `false` |
|
|
56
|
+
| `strictErrors` | Fail HomeKit reads on hub errors instead of returning the last known position | `false` |
|
|
57
|
+
| `forceRollerShades` | Shade IDs to treat as roller | `[]` |
|
|
58
|
+
| `forceTopBottomShades` | Shade IDs to treat as top/bottom | `[]` |
|
|
59
|
+
| `forceHorizontalShades` | Shade IDs to treat as horizontal vane | `[]` |
|
|
60
|
+
| `forceVerticalShades` | Shade IDs to treat as vertical vane | `[]` |
|
|
61
|
+
|
|
62
|
+
Example with host and polling:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"platform": "PowerView",
|
|
67
|
+
"name": "PowerView",
|
|
68
|
+
"host": "192.168.1.50",
|
|
69
|
+
"pollShadesForUpdate": true
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Unknown shade types
|
|
74
|
+
|
|
75
|
+
If the hub reports an unknown shade type, the log may show:
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Shade 12345 has unknown type 66, assuming roller
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Please [open an issue](https://github.com/sunnierseattle/homebridge-powerview-universal/issues) with the shade model. You can override detection with the `force*` arrays above.
|
|
82
|
+
|
|
83
|
+
### Hub resilience and optional features
|
|
84
|
+
|
|
85
|
+
- If the hub is busy (HTTP 423, maintenance), shade requests are retried automatically.
|
|
86
|
+
- When a position refresh times out or the hub is unreachable, HomeKit reads return the **last known position** unless `strictErrors` is enabled.
|
|
87
|
+
- **Battery** percentage appears in the Home app (via a linked HomeKit Battery service on each shade) when the hub reports `batteryStrength` or `batteryStatus`; levels are refreshed about every 6 hours. Window Covering does not expose battery directly—only the standard Battery service does.
|
|
88
|
+
- **Jog** (short nudge) is triggered from **Hold** on the shade control where supported, and when you **Identify** the accessory in the Home app while pairing.
|
|
89
|
+
- PowerView **scenes** and **multi-room scene collections** are probed at startup for future use but are **not** exposed as HomeKit accessories yet.
|
|
90
|
+
|
|
91
|
+
## Migrating from homebridge-powerview-2
|
|
92
|
+
|
|
93
|
+
1. Stop Homebridge.
|
|
94
|
+
2. Uninstall the old plugin: `npm uninstall -g homebridge-powerview-2`
|
|
95
|
+
3. Install `homebridge-powerview-universal`.
|
|
96
|
+
4. Update your config: keep `"platform": "PowerView"` and add `"name": "PowerView"` if missing.
|
|
97
|
+
5. Remove any old **PowerView** platform entry that pointed at the v2 package, then add the platform again for v3.
|
|
98
|
+
6. Restart Homebridge.
|
|
99
|
+
|
|
100
|
+
The plugin identifier changed from `homebridge-powerview` to `homebridge-powerview-universal`. Cached accessories from the old package may appear as duplicates in the Home app. Remove ghost accessories from Home if needed.
|
|
101
|
+
|
|
102
|
+
## Shade examples
|
|
103
|
+
|
|
104
|
+
Tap an accessory to open/close; long-press for a custom position.
|
|
105
|
+
|
|
106
|
+
### Horizontal and vertical vanes
|
|
107
|
+
|
|
108
|
+
Use **Details** after a long-press to adjust tilt. For scenes: use **Closed** when setting vane tilt; use **0°** tilt when setting position.
|
|
109
|
+
|
|
110
|
+
### Top-down/bottom-up
|
|
111
|
+
|
|
112
|
+
Two controls are created per shade (bottom and top), which can be used independently or in scenes.
|
|
113
|
+
|
|
114
|
+
## Releases
|
|
115
|
+
|
|
116
|
+
Version history for installers is in [RELEASE_NOTES.md](RELEASE_NOTES.md). Detailed developer notes are in [CHANGELOG.md](CHANGELOG.md).
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
npm install
|
|
122
|
+
npm run build
|
|
123
|
+
npm run lint
|
|
124
|
+
npm test
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
ISC. See [LICENSE](LICENSE) for the full text and the copyright chain.
|