Skip to content

Commit 6e31c21

Browse files
committed
v7.21.0.
1 parent 83cc796 commit 6e31c21

23 files changed

+564
-500
lines changed

docs/Changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22

33
All notable changes to this project will be documented in this file. This project uses [semantic versioning](https://semver.org/).
44

5+
## 7.21.0 (2025-08-08)
6+
* New feature: the ability to mute HomeKit doorbell chimes. It's available as a feature option under the `Doorbell` category. This will allow you to turn off having your HomePod chimes ring when someone rings your doorbell, selectively. Defaults to off.
7+
* Improvement: complete overhaul of feature option webUI. Improved the user interface, added the ability to search for feature options, filter on what's changed, and reset options.
8+
* Improvement: added additional resiliency to the livestream API connection to cameras. When cameras are continuously misbehaving, HBUP will attempt to restart them if their livestream API connection keeps timing out continuously. This should very rarely occur unless Ubiquiti releases a particularly problematic firmware release.
9+
* Improvement: The occupancy sensor feature option will now use both person and face to detect presence now, by default, on cameras that support it. As always, you can adjust these to your heart's content.
10+
* Housekeeping.
11+
512
## 7.20.1 (2025-07-15)
613
* Fix: address livestreaming regressions.
714
* Housekeeping.

docs/FeatureOptions.md

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ Feature options provide a rich mechanism for tailoring your `homebridge-unifi-pr
3737
* [Device](#device): Device feature options.
3838
* [Doorbell](#doorbell): Doorbell feature options.
3939
* [Log](#log): Logging feature options.
40-
* [Motion](#motion): Motion detection feature options.
40+
* [Motion](#motion): Motion feature options.
4141
* [Nvr](#nvr): NVR feature options.
42-
* [SecuritySystem](#securitysystem): Security system feature options.
43-
* [UniFi.Access](#unifi.access): UniFi Access options.
42+
* [SecuritySystem](#securitysystem): Security System feature options.
43+
* [UniFi.Access](#unifi.access): UniFi Access feature options.
4444
* [Video](#video): Video feature options.
4545
* [Video.HKSV](#video.hksv): HomeKit Secure Video feature options.
4646

@@ -79,12 +79,13 @@ These option(s) apply to: Protect cameras.
7979
| Option | Description
8080
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------
8181
| <A NAME="Doorbell.AuthSensor"></A>`Doorbell.AuthSensor` | Add a contact sensor that gets activates when a fingerprint or NFC successfully authenticates on a Protect doorbell. **(default: disabled)**. <BR>*Supported on Protect doorbells that have a fingerprint sensor.*
82+
| <A NAME="Doorbell.Mute"></A>`Doorbell.Mute` | Add a switch accessory to control whether HomeKit will chime when the doorbell is pressed. **(default: disabled)**.
8283
| <A NAME="Doorbell.Messages"></A>`Doorbell.Messages` | Enable the doorbell messages feature. **(default: disabled)**. <BR>*Supported on Protect devices that have a doorbell.*
8384
| <A NAME="Doorbell.Messages.FromDoorbell"></A>`Doorbell.Messages.FromDoorbell` | Use messages saved to the Protect NVR as message switches. **(default: enabled)**. <BR>*Supported on Protect devices that have a doorbell.*
8485
| <A NAME="Doorbell.Volume.Dimmer"></A>`Doorbell.Volume.Dimmer` | Add a dimmer accessory to control the Protect chime volume in HomeKit. **(default: disabled)**. <BR>*Supported on Protect devices that have a doorbell.*
8586
| <A NAME="Doorbell.PhysicalChime"></A>`Doorbell.PhysicalChime` | Add switch accessories to control the physical chimes attached to a Protect doorbell. **(default: disabled)**. <BR>*Supported on Protect doorbells that have a physical chime.*
86-
| <A NAME="Doorbell.PackageCamera.Flashlight"></A>`Doorbell.PackageCamera.Flashlight` | Add a light accessory to control the flashlight on a Protect doorbell package camera. **(default: enabled)**. <BR>*Supported on Protect doorbells that have a package camera.*
8787
| <A NAME="Doorbell.PhysicalChime.Duration.Digital"></A><CODE>Doorbell.PhysicalChime.Duration.Digital<I>.Value</I></CODE> | Chime duration, in milliseconds, of a digital physical chime attached to a Protect doorbell. **(default: 1000)**. <BR>*Supported on Protect doorbells that have a physical chime.*
88+
| <A NAME="Doorbell.PackageCamera.Flashlight"></A>`Doorbell.PackageCamera.Flashlight` | Add a light accessory to control the flashlight on a Protect doorbell package camera. **(default: enabled)**. <BR>*Supported on Protect doorbells that have a package camera.*
8889
| <A NAME="Doorbell.Trigger"></A>`Doorbell.Trigger` | Add a switch accessory to trigger doorbell ring events on a Protect camera or doorbell. **(default: disabled)**.
8990

9091
#### <A NAME="log"></A>Logging feature options.
@@ -97,7 +98,7 @@ These option(s) apply to: Protect cameras, Protect lights, and Protect sensors.
9798
| <A NAME="Log.HKSV"></A>`Log.HKSV` | Log HomeKit Secure Video recording events in Homebridge. **(default: disabled)**. <BR>*Supported on Protect cameras.*
9899
| <A NAME="Log.Motion"></A>`Log.Motion` | Log motion events in Homebridge. **(default: disabled)**. <BR>*Supported on Protect devices that have a motion sensor.*
99100

100-
#### <A NAME="motion"></A>Motion detection feature options.
101+
#### <A NAME="motion"></A>Motion feature options.
101102

102103
These option(s) apply to: Protect cameras, Protect lights, and Protect sensors.
103104

@@ -107,7 +108,7 @@ These option(s) apply to: Protect cameras, Protect lights, and Protect sensors.
107108
| <A NAME="Motion.OccupancySensor"></A>`Motion.OccupancySensor` | Add an occupancy sensor accessory using motion sensor activity to determine occupancy. By default, any motion will trigger occupancy. If the smart detection feature option is enabled, it will be used instead. **(default: disabled)**. <BR>*Supported on Protect devices that have a motion sensor.*
108109
| <A NAME="Motion.OccupancySensor.Duration"></A><CODE>Motion.OccupancySensor.Duration<I>.Value</I></CODE> | Duration, in seconds, to wait without receiving a motion event to determine when occupancy is no longer detected. **(default: 300)**.
109110
| <A NAME="Motion.OccupancySensor.Animal"></A>`Motion.OccupancySensor.Animal` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's animal detection to trigger occupancy. **(default: disabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
110-
| <A NAME="Motion.OccupancySensor.Face"></A>`Motion.OccupancySensor.Face` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's face detection to trigger occupancy. **(default: disabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
111+
| <A NAME="Motion.OccupancySensor.Face"></A>`Motion.OccupancySensor.Face` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's face detection to trigger occupancy. **(default: enabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
111112
| <A NAME="Motion.OccupancySensor.LicensePlate"></A>`Motion.OccupancySensor.LicensePlate` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's license plate detection to trigger occupancy. **(default: disabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
112113
| <A NAME="Motion.OccupancySensor.Package"></A>`Motion.OccupancySensor.Package` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's package detection to trigger occupancy. **(default: disabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
113114
| <A NAME="Motion.OccupancySensor.Person"></A>`Motion.OccupancySensor.Person` | When using both the occupancy sensor and smart detection feature options, use UniFi Protect's person detection to trigger occupancy. **(default: enabled)**. <BR>*Supported on Protect devices that support smart motion detection (e.g. G4-series cameras and better).*
@@ -140,15 +141,15 @@ These option(s) apply to: Protect cameras and Protect controllers.
140141
| <A NAME="Nvr.Recording.Switch"></A>`Nvr.Recording.Switch` | Add switch accessories to control the native recording capabilities of the UniFi Protect NVR. **(default: disabled)**. <BR>*Supported on Protect cameras.*
141142
| <A NAME="Nvr.SystemInfo"></A>`Nvr.SystemInfo` | Add sensor accessories to display the Protect controller system information (currently only the temperature). **(default: disabled)**. <BR>*Supported on Protect controllers.*
142143

143-
#### <A NAME="securitysystem"></A>Security system feature options.
144+
#### <A NAME="securitysystem"></A>Security System feature options.
144145

145146
These option(s) apply to: Protect controllers.
146147

147148
| Option | Description
148149
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------
149150
| <A NAME="SecuritySystem.Alarm"></A>`SecuritySystem.Alarm` | Add a switch accessory to trigger the security system accessory, when using the liveview feature option. **(default: disabled)**.
150151

151-
#### <A NAME="unifi.access"></A>UniFi Access options.
152+
#### <A NAME="unifi.access"></A>UniFi Access feature options.
152153

153154
These option(s) apply to: Protect cameras.
154155

eslint.config.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default ts.config(
3333

3434
files: [ "src/**.ts", "src/devices/**.ts", "homebridge-ui/*.@(js|mjs)", "homebridge-ui/public/**/*.@(js|mjs)", "eslint.config.mjs" ],
3535

36-
ignores: [ "dist" ],
36+
ignores: ["dist"],
3737

3838
languageOptions: {
3939

@@ -85,7 +85,7 @@ export default ts.config(
8585

8686
{
8787

88-
files: [ "homebridge-ui/server.js" ],
88+
files: ["homebridge-ui/server.js"],
8989

9090
languageOptions: {
9191

homebridge-ui/public/index.html

Lines changed: 54 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,17 @@
1616
<table class="table table-sm table-borderless text-center">
1717
<tr>
1818
<td>
19-
<input type="test" placeholder="Protect controller hostname or IP address" size="40" id="address"></input>
19+
<input type="text" autocomplete="off" placeholder="Protect controller hostname or IP address" size="40" id="address" />
2020
</td>
2121
</tr>
2222
<tr>
2323
<td>
24-
<input type="username" placeholder="Protect controller username" size="40" id="username"></input>
24+
<input type="text" autocomplete="username" placeholder="Protect controller username" size="40" id="username" />
2525
</td>
2626
</tr>
2727
<tr>
2828
<td>
29-
<input type="password" placeholder="Protect controller password" size="40" id="password"></input>
29+
<input type="password" autocomplete="current-password" placeholder="Protect controller password" size="40" id="password" />
3030
</td>
3131
</tr>
3232
<tr>
@@ -56,48 +56,33 @@
5656
<button type="button" class="btn btn-primary" id="menuFeatureOptions">Feature Options</button>
5757
<button type="button" class="btn btn-primary mr-0" id="menuHome">Support</button>
5858
</div>
59-
<div id="pageFeatureOptions" class="mt-2" style="display: none;">
60-
<div id="deviceInfo">
61-
<table class="table table-sm table-borderless">
62-
<tr class="align-center">
63-
<td id="headerInfo" colspan="2" class="m-0 p-2 text-center font-weight-bold"></td>
64-
</tr>
65-
<tr class="align-top">
66-
<td rowspan="3" class="w-25">
67-
<table id="sidebar" class="table table-sm table-bordered m-0 p-0">
68-
<tr>
69-
<td>
70-
<table class="table table-sm table-borderless m-0 p-0" id="controllersTable"></table>
71-
</td>
72-
</tr>
73-
<tr>
74-
<td>
75-
<table class="table table-sm table-borderless m-0 p-0" id="devicesTable"></table>
76-
</td>
77-
</tr>
78-
</table>
79-
</td>
80-
<td id="deviceStatsTable">
81-
<table class="table table-sm table-borderless border-bottom m-0 p-0">
82-
<tr id="deviceStatsHeader">
83-
<th class="m-0 p-0" style="font-weight: bold; width: 30%;">Model</th>
84-
<th class="m-0 p-0 w-25" style="font-weight: bold;">IP Address</th>
85-
<th class="m-0 p-0" style="font-weight: bold; width: 20%;">MAC Address</th>
86-
<th class="m-0 p-0 w-25" style="font-weight: bold;">Status</th>
87-
</tr>
88-
<tr>
89-
<td id="device_model" class="m-0 p-0"></td>
90-
<td id="device_address" class="m-0 p-0"></td>
91-
<td id="device_mac" class="m-0 p-0"></td>
92-
<td id="device_online" class="m-0 p-0"></td>
93-
</tr>
94-
</table>
95-
</td>
96-
</tr>
97-
<tr>
98-
<td id="configTable" class="w-100"></td>
99-
</tr>
100-
</table>
59+
<div id="pageFeatureOptions" class="mt-2" style="display: none;" tabindex="0">
60+
<!-- Header information bar -->
61+
<div id="headerInfo" class="alert alert-info bg-transparent py-2 px-3 mb-2"></div>
62+
63+
<!-- Main content area -->
64+
<div class="feature-main-content">
65+
<!-- Sidebar -->
66+
<aside id="sidebar" class="me-3">
67+
<div class="sidebar-content">
68+
<nav id="controllersContainer" class="p-2"></nav>
69+
<nav id="devicesContainer" class="p-2"></nav>
70+
</div>
71+
</aside>
72+
73+
<!-- Main content -->
74+
<main class="feature-content">
75+
<!-- Device stats using CSS Grid -->
76+
<div id="deviceStatsContainer"></div>
77+
78+
<!-- Search panel -->
79+
<div id="search" class="mb-3"></div>
80+
81+
<!-- Options content area -->
82+
<div id="optionsContainer" class="options-content alert-info rounded p-3">
83+
<div id="configTable"></div>
84+
</div>
85+
</main>
10186
</div>
10287
</div>
10388
<div id="pageSupport" class="mt-4" style="display: none;">
@@ -181,16 +166,34 @@ <h5>Support</h5>
181166
</ul>
182167
</div>
183168
<script type="module">
184-
185169
/* Copyright(C) 2017-2025, HJD (https://github.com/hjdhjd). All rights reserved.
186170
*
187171
* Plugin webUI script loader.
188172
*/
189173
"use strict";
190174

191-
// Ensure we load the webUI dynamically so it isn't cached on each load.
192-
const script = document.createElement('script');
193-
script.src = "./ui.mjs?v=" + Date.now().toString();
194-
script.type = "module";
195-
document.body.appendChild(script);
175+
// Compute a timestamp for cache-busting so each URL appears unique.
176+
const timestamp = Date.now();
177+
178+
// Next, set up an import map that will append a cache-busting query string to our modules.
179+
const importMap = {
180+
181+
imports: {
182+
183+
"./ui.mjs": new URL("./ui.mjs", import.meta.url).href + "?cb=" + timestamp,
184+
"./lib/featureOptions.js": new URL("./lib/featureOptions.js", import.meta.url).href + "?cb=" + timestamp,
185+
"./lib/webUi.mjs": new URL("./lib/webUi.mjs", import.meta.url).href + "?cb=" + timestamp,
186+
"./lib/webUi-featureOptions.mjs": new URL("./lib/webUi-featureOptions.mjs", import.meta.url).href + "?cb=" + timestamp
187+
}
188+
};
189+
190+
// Append the import map script to the document head so the browser applies it.
191+
const mapScript = document.createElement("script");
192+
193+
mapScript.type = "importmap";
194+
mapScript.textContent = JSON.stringify(importMap);
195+
document.head.appendChild(mapScript);
196+
197+
// Finally, import the UI entry point so we always load a fresh copy.
198+
await import("./ui.mjs");
196199
</script>

0 commit comments

Comments
 (0)