Skip to content

Commit

Permalink
v7.2.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
hjdhjd committed Sep 15, 2024
1 parent 9e92347 commit aaad3a5
Show file tree
Hide file tree
Showing 29 changed files with 1,492 additions and 1,342 deletions.
11 changes: 11 additions & 0 deletions docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

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

## 7.2.0 (2024-09-14)
* Behavior change: API livestreaming is now the default. You can revert to the former method, using RTSP streams if you prefer. **I intend to deprecate RTSP streaming at some future point.**
* Behavior change: The timeshift buffer is now mandatory in HBUP for HKSV. Latency issues make the legacy RTSP method extremely unreliable and I've decided to simplify and focus on a great HKSV experience at the expense of supporting low-power/limited CPU environments.
* Removed feature: The HKSV maximum recording duration feature option has been removed. With recent changes to the Protect API make this extremely unreliable.
* New feature: on Protect cameras that support it, an ambient light sensor will be added, reporting the current light level.
* New feature: for automation use cases, an optional switch can be enabled to control the status indicator light on Protect devices that support it. This feature is supported on all UniFi Protect device types that have a status indicator light (currently cameras, lights, and sensors) Find it under device feature options. Disabled by default.
* New feature: the status indicator light on Protect cameras can be used to automatically reflect when an HKSV event is being recorded. With this enabled, the status indicator light will switch on when an event is being actively recorded and off once it stops. Find it under HKSV feature options. Disabled by default. Thanks to @kevinwestby for the suggestion and enhancement request.
* Improvement: further refinements to API livestreaming and HKSV.
* Improvement: Protect-based smart motion detection (not to be confused with HKSV) has been refined to support the changes introduced by Ubiquiti in Protect firmware 4.1 and beyond. **HBUP now requires v4.1 or later, as of this release, as a result. As a reminder, non-GA/official firmware releases are explicitly unsupported by HBUP.**
* Housekeeping and refinements. Lots of them...subtle and not.

## 7.1.2 (2024-06-16)
* Improvement: additional refinements to API livestreaming.
* Housekeeping.
Expand Down
8 changes: 4 additions & 4 deletions docs/FeatureOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ These option(s) apply to: all Protect device types.
| Option | Description
|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| `Device` | Make this device available in HomeKit. **(default: enabled)**.
| `Device.StatusLed` | Enable the status LED for this device in HomeKit. **(default: disabled)**. <BR>*Supported on Protect devices that have a status LED.*
| `Device.StatusLed` | Enable the status indicator light for this device in HomeKit. **(default: disabled)**. <BR>*Supported on Protect devices that have a status indicator light.*
| `Device.StatusLed.Switch` | Add a switch accessory to control the status indicator light in HomeKit. **(default: disabled)**. <BR>*Supported on Protect devices that have a status indicator light.*
| `Device.Standalone` | Make this a standalone device in HomeKit that will need to be added to HomeKit through the Home app. **(default: disabled)**.
| `Device.SyncName` | Synchronize the UniFi Protect name of this device with HomeKit. Synchronization is one-way only, syncing the device name from UniFi Protect to HomeKit. **(default: disabled)**.

Expand Down Expand Up @@ -150,17 +151,16 @@ These option(s) apply to: Protect cameras.
| `Video.Crop.Y<I>.Value</I>` | Top offset of the crop window, as a percentage of the original image height. **(default: 0)**.
| `Video.Crop.Width<I>.Value</I>` | Width of the crop window, as a percentage of original image width. **(default: 100)**.
| `Video.Crop.Height<I>.Value</I>` | Height of the crop window, as a percentage of original image height. **(default: 100)**.
| `Video.HighResSnapshots` | Enable higher quality snapshots using the timeshift buffer or the livestream. **(default: enabled)**.
| `Video.HighResSnapshots` | Enable higher quality snapshots. **(default: enabled)**.

#### <A NAME="video.hksv"></A>HomeKit Secure Video feature options.

These option(s) apply to: Protect cameras.

| Option | Description
|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| `Video.HKSV.TimeshiftBuffer` | Enable the timeshift buffer for HomeKit Secure Video. **(default: enabled)**.
| `Video.HKSV.StatusLedIndicator` | Use the camera status indicator light to show when an HKSV event is being recorded. **(default: disabled)**.
| `Video.HKSV.Recording.Switch` | Add a switch accessory to enable or disable HKSV event recording. **(default: disabled)**.
| `Video.HKSV.Recording.MaxDuration<I>.Value</I>` | Maximum HomeKit Secure Video event duration, in seconds. **(default: 0)**.
| `Video.HKSV.Record.Only.High` | When recording HomeKit Secure Video events, force the use of the high quality video stream from the Protect controller. **(default: disabled)**.
| `Video.HKSV.Record.Only.Medium` | When recording HomeKit Secure Video events, force the use of the medium quality video stream from the Protect controller. **(default: disabled)**.
| `Video.HKSV.Record.Only.Low` | When recording HomeKit Secure Video events, force the use of the low quality video stream from the Protect controller. **(default: disabled)**.
Expand Down
6 changes: 2 additions & 4 deletions docs/HomeKitSecureVideo.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ HomeKit Secure Video has been a feature in HomeKit since the launch of iOS 13. I
* **Important note: You must configure HomeKit Secure Video in the Home app before it will start recording any events of any kind. [Instructions for doing so](https://support.apple.com/guide/iphone/set-up-security-cameras-iph7bc5df9d9/ios) are well beyond the scope of this documentation. Please look it up in the infinite guides online or ask a friend.**
* On a technical level, HKSV asks `homebridge-unifi-protect` to maintain a buffer using the UniFi Protect livestream API. This isn't quite the same thing as RTSP, which you may be familiar with, but rather an **actual UniFi Protect API** that allows direct access to the raw livestream on the Protect controller. That video buffer is a few seconds in length - in practice, HomeKit seems to always request four seconds of history. Think of this buffer like a timeshifting DVR that's constantly keeping a small buffer of live video. When a motion event occurs, we send the buffer to HomeKit, and continue to do so as long as HomeKit requests it. Using the livestream API significantly lowers the resource demands on the Protect controller, particularly when you get beyond a few cameras. It also lowers the resource demand on the machine running HBUP, since the additional overhead of processing an RTSP stream through FFmpeg is avoided.
* It's important to note: **HomeKit decides how long each event will be, by default**. In practice, I've seen events as long 5 or 10 minutes in high-traffic areas. HomeKit continues to record an event for as long as it thinks there's some motion of interest to the user.
* If you place a camera in a very high traffic area, say a kitchen or a family room, and enable HKSV, you're likely going to get long motion events captured in HomeKit. It's not a bug, it's the way HomeKit Secure Video is designed. :smile: You can modify this behavior in the HBUP feature options webUI under the HomeKit Secure Video section, allowing you to set an upward limit on how long each HKSV event recording can be.
* If you place a camera in a very high traffic area, say a kitchen or a family room, and enable HKSV, you're likely going to get long motion events captured in HomeKit. It's not a bug, it's the way HomeKit Secure Video is designed. :smile:

#### Interactions With UniFi Protect Smart Motion Detection
UniFi Protect has it's own smart motion detection capabilities that [can be used](https://github.com/hjdhjd/homebridge-unifi-protect/blob/main/docs/BestPractices.md#motion-sensors-motion-switches-and-push-notifications) with `homebridge-unifi-protect`. When you have smart motion detection enabled and you have HomeKit Secure Video is enabled **and** configured in the Home app to record events, `homebridge-unifi-protect` is faced with a dilemma: when do I notify a user of a motion detection event?
Expand All @@ -52,7 +52,7 @@ Apple created an elegant secure-by-default system that leverages it's home-based
* That stream is analyzed based on what HKSV is looking for (people, animals, etc.) and continues to capture video until HKSV feels it's got nothing *interesting* left in the video. So, someone walking past the camera, for instance, may trigger a recording of 20-30 seconds, but a group of people moving around in front of the camera may generate a much longer recorded clip.
* That recorded video event is then sent to iCloud in an encrypted form and the alert notifications are sent to your iPhone, etc. based on whatever your notification settings.

In essence, Apple's Home hub devices are doing object recognition to decide what to alert you about. Given their realtime performance requirements and the need to scale, Apple has imposed very rigid requirements on the incoming video stream in order to get things working with a good Apple-y user experience. That allows your Apple TV to be able to analyze a motion video event while displaying that shiny 4K HDR video on your fancy television without stuttering. Why do I use that example? Because I made my Apple TV stutter constantly while developing and testing HKSV support for `homebridge-unifi-protect`. The reason we need to transcode video is because Home hubs are so very particular about what they receive when it comes to those video event clips - anything above a bitrate of 2000kbps and you quickly degrade Home hub performance. Anything that's not exactly the amount of timeshifted buffer (four seconds!) it's looking for, and suddenly timestamps are wrong within the Home app UI when you review a recorded event.
In essence, Apple's Home hub devices are doing object recognition to decide what to alert you about. Given their realtime performance requirements and the need to scale, Apple has imposed very rigid requirements on the incoming video stream in order to get things working with a good Apple-y user experience. That allows your Apple TV to be able to analyze a motion video event while displaying that shiny 4K HDR video on your fancy television without stuttering. Why do I use that example? Because I made my Apple TV stutter constantly while developing and testing HKSV support for `homebridge-unifi-protect`. The reason we need to transcode video is because Home hubs are so very particular about what they receive when it comes to those video event clips - anything above a bitrate of 2000kbps and you quickly degrade Home hub performance. Anything that's not exactly the amount of the timeshifted buffer (four seconds!) it's looking for, and suddenly timestamps are wrong within the Home app UI when you review a recorded event.

All of the above is based on observed behavior and conversations with other people. I'm sure someone much smarter than I may eventually find more definitive or better insights into the inner workings of the black box that is HomeKit Secure Video, but I doubt Apple is going to tell us much anytime soon. 😄

Expand All @@ -65,8 +65,6 @@ HKSV in `homebridge-unifi-protect` works well by default if you have a decently

If you're struggling to get HKSV working in HBUP, try the following, in this order and see if it helps:

* Try disabling the timeshift buffer. This will have a small implication to HKSV event viewing - specifically, the few seconds of video before a motion event will not be available to send to HKSV for analysis, but with the benefit of significantly lowering the CPU consumption of `homebridge-unifi-protect` due to the continuous maintenance of that timeshift buffer. You can disable the timeshift buffer by looking under the HomeKit Secure Video section of the HBUP feature options webUI.

* Try forcing HBUP to only use the lowest quality video stream as a starting point. You do this by looking for the option under the HomeKit Secure Video section of the HBUP feature options webUI.

The above recommendations should help you get up and running in most lower-powered environments.
Expand Down
10 changes: 8 additions & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ export default ts.config(
parserOptions: {

ecmaVersion: "latest",
project: "./tsconfig.json"
project: "./tsconfig.json",

projectService: {

allowDefaultProject: [ "eslint.config.mjs", "homebridge-ui/*.@(js|mjs)", "homebridge-ui/public/*.@(js|mjs)", "homebridge-ui/public/lib/*.@(js|mjs)" ],
defaultProject: "./tsconfig.json"
}
},

sourceType: "module"
Expand All @@ -66,7 +72,7 @@ export default ts.config(

{

files: [ "homebridge-ui/public/lib/webUi.mjs", "homebridge-ui/public/lib/webUi-featureoptions.mjs" ],
files: [ "homebridge-ui/public/lib/webUi.mjs", "homebridge-ui/public/lib/webUi-featureoptions.mjs", "homebridge-ui/public/ui.mjs" ],

languageOptions: {

Expand Down
11 changes: 6 additions & 5 deletions homebridge-ui/public/ui.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const firstRunIsRequired = () => {
}

return true;
}
};

// Initialize our first run screen with any information from our existing configuration.
const firstRunOnStart = () => {
Expand Down Expand Up @@ -48,12 +48,13 @@ const firstRunOnSubmit = async () => {
return false;
}

const ufpDevices = await homebridge.request("/getDevices", { address: address, username: username, password: password });
const ufpDevices = await homebridge.request("/getDevices", { address: address, password: password, username: username });

// Couldn't connect to the Protect controller for some reason.
if(!ufpDevices?.length) {

tdLoginError.innerHTML = "Unable to login to the UniFi Protect controller.<br>Please check your controller address, username, and password.<br><code class=\"text-danger\">" + (await homebridge.request("/getErrorMessage")) + "</code>";
tdLoginError.innerHTML = "Unable to login to the UniFi Protect controller.<br>Please check your controller address, username, and password.<br>" +
"<code class=\"text-danger\">" + (await homebridge.request("/getErrorMessage")) + "</code>";
homebridge.hideSpinner();

return false;
Expand Down Expand Up @@ -84,7 +85,7 @@ const getDevices = async (controller) => {
}

// Retrieve the current list of devices from the Protect controller.
let devices = await homebridge.request("/getDevices", { address: controller.address, username: controller.username, password: controller.password });
let devices = await homebridge.request("/getDevices", { address: controller.address, password: controller.password, username: controller.username });

// Add the fields that the webUI framework is looking for to render.
devices = devices.map(device => ({
Expand Down Expand Up @@ -212,7 +213,7 @@ const showProtectDetails = (device) => {
document.getElementById("device_model").classList.remove("text-center");
document.getElementById("device_model").colSpan = 1;
document.getElementById("device_model").style.fontWeight = "normal";
document.getElementById("device_model").innerHTML = "N/A"
document.getElementById("device_model").innerHTML = "N/A";
document.getElementById("device_mac").innerHTML = "N/A";
document.getElementById("device_address").innerHTML = "N/A";
document.getElementById("device_online").innerHTML = "N/A";
Expand Down
Loading

0 comments on commit aaad3a5

Please sign in to comment.