Skip to content

Commit

Permalink
Improvement: validate accessory names against HomeKit naming rules.
Browse files Browse the repository at this point in the history
  • Loading branch information
hjdhjd committed Oct 2, 2024
1 parent 837e122 commit 5455c83
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 11 deletions.
12 changes: 7 additions & 5 deletions src/devices/protect-device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* protect-device.ts: Base class for all UniFi Protect devices.
*/
import { API, CharacteristicValue, HAP, PlatformAccessory, Service, WithUUID } from "homebridge";
import { HomebridgePluginLogging, acquireService, validService } from "homebridge-plugin-utils";
import { HomebridgePluginLogging, acquireService, validService, validateName } from "homebridge-plugin-utils";
import { PROTECT_MOTION_DURATION, PROTECT_OCCUPANCY_DURATION} from "../settings.js";
import { ProtectApi, ProtectCameraConfig, ProtectEventPacket, ProtectNvrConfig } from "unifi-protect";
import { ProtectDeviceConfigTypes, ProtectReservedNames } from "../protect-types.js";
Expand Down Expand Up @@ -222,7 +222,7 @@ export abstract class ProtectDevice extends ProtectBase {
// Sync the Protect name with HomeKit, if configured.
if(this.hints.syncName) {

this.accessoryName = this.ufp.name ?? this.ufp.marketName ?? ("Unknown Device" + (this.ufp.mac ? ": " + this.ufp.mac : ""));
this.accessoryName = this.ufp.name ?? this.ufp.marketName ?? ("Unknown Device" + (this.ufp.mac ? " " + this.ufp.mac : ""));
}

return this.setInfo(this.accessory, this.ufp);
Expand Down Expand Up @@ -679,12 +679,14 @@ export abstract class ProtectDevice extends ProtectBase {
// Utility function to set the current accessory name of this device.
public set accessoryName(name: string) {

const cleanedName = validateName(name);

// Set all the internally managed names within Homebridge to the new accessory name.
this.accessory.displayName = name;
this.accessory._associatedHAPAccessory.displayName = name;
this.accessory.displayName = cleanedName;
this.accessory._associatedHAPAccessory.displayName = cleanedName;

// Set all the HomeKit-visible names.
this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.Name, name);
this.accessory.getService(this.hap.Service.AccessoryInformation)?.updateCharacteristic(this.hap.Characteristic.Name, cleanedName);
}

// Utility to return the command to set the device status indicator light. This works for cameras and sensors, but Protect lights deal with this differently.
Expand Down
3 changes: 2 additions & 1 deletion src/devices/protect-doorbell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ProtectReservedNames, toCamelCase } from "../protect-types.js";
import { ProtectCamera } from "./protect-camera.js";
import { ProtectCameraPackage } from "./protect-camera-package.js";
import { ProtectNvr } from "../protect-nvr.js";
import { validateName } from "homebridge-plugin-utils";

// A doorbell message entry.
interface MessageInterface {
Expand Down Expand Up @@ -196,7 +197,7 @@ export class ProtectDoorbell extends ProtectCamera {
if(!packageCameraAccessory) {

// We will use the NVR MAC address + ".NVRSystemInfo" to create our UUID. That should provide the guaranteed uniqueness we need.
packageCameraAccessory = new this.api.platformAccessory(this.accessoryName + " Package Camera", uuid);
packageCameraAccessory = new this.api.platformAccessory(validateName(this.accessoryName + " Package Camera"), uuid);

if(!packageCameraAccessory) {

Expand Down
5 changes: 3 additions & 2 deletions src/devices/protect-liveviews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ProtectBase } from "./protect-device.js";
import { ProtectNvr } from "../protect-nvr.js";
import { ProtectNvrLiveviewConfig } from "unifi-protect";
import { ProtectSecuritySystem } from "./protect-securitysystem.js";
import { validateName } from "homebridge-plugin-utils";

export class ProtectLiveviews extends ProtectBase {

Expand Down Expand Up @@ -84,7 +85,7 @@ export class ProtectLiveviews extends ProtectBase {
if((this.securityAccessory = this.platform.accessories.find(x => x.UUID === uuid)) === undefined) {

// We will use the NVR MAC address + ".Security" to create our UUID. That should provide the guaranteed uniqueness we need.
this.securityAccessory = new this.api.platformAccessory(this.ufpApi.bootstrap.nvr.name, uuid);
this.securityAccessory = new this.api.platformAccessory(validateName(this.ufpApi.bootstrap.nvr.name), uuid);

// Register this accessory with homebridge and add it to the platform accessory array so we can track it.
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [ this.securityAccessory ]);
Expand Down Expand Up @@ -184,7 +185,7 @@ export class ProtectLiveviews extends ProtectBase {

if((newAccessory = this.platform.accessories.find(x => x.UUID === uuid)) === undefined) {

newAccessory = new this.api.platformAccessory(this.ufpApi.bootstrap.nvr.name + " " + viewName, uuid);
newAccessory = new this.api.platformAccessory(validateName(this.ufpApi.bootstrap.nvr.name + " " + viewName), uuid);

// Register this accessory with homebridge and add it to the platform accessory array so we can track it.
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [ newAccessory ]);
Expand Down
3 changes: 2 additions & 1 deletion src/devices/protect-nvr-systeminfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PlatformAccessory } from "homebridge";
import { ProtectBase } from "./protect-device.js";
import { ProtectEventPacket } from "unifi-protect";
import { ProtectNvr } from "../protect-nvr.js";
import { validateName } from "homebridge-plugin-utils";

export class ProtectNvrSystemInfo extends ProtectBase {

Expand Down Expand Up @@ -75,7 +76,7 @@ export class ProtectNvrSystemInfo extends ProtectBase {
if(!this.accessory) {

// We will use the NVR MAC address + ".NVRSystemInfo" to create our UUID. That should provide the guaranteed uniqueness we need.
this.accessory = new this.api.platformAccessory(this.nvr.ufp.name ?? this.nvr.ufp.marketName, uuid);
this.accessory = new this.api.platformAccessory(validateName(this.nvr.ufp.name ?? this.nvr.ufp.marketName), uuid);

if(!this.accessory) {

Expand Down
4 changes: 2 additions & 2 deletions src/protect-nvr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* protect-nvr.ts: NVR device class for UniFi Protect.
*/
import { API, APIEvent, HAP, PlatformAccessory } from "homebridge";
import { HomebridgePluginLogging, MqttClient, retry, sleep } from "homebridge-plugin-utils";
import { HomebridgePluginLogging, MqttClient, retry, sleep, validateName } from "homebridge-plugin-utils";
import { PLATFORM_NAME, PLUGIN_NAME, PROTECT_CONTROLLER_REFRESH_INTERVAL, PROTECT_CONTROLLER_RETRY_INTERVAL, PROTECT_M3U_PLAYLIST_PORT } from "./settings.js";
import { ProtectApi, ProtectCameraConfig, ProtectChimeConfig, ProtectLightConfig, ProtectNvrBootstrap, ProtectNvrConfig, ProtectSensorConfig,
ProtectViewerConfig } from "unifi-protect";
Expand Down Expand Up @@ -341,7 +341,7 @@ export class ProtectNvr {
// See if we already know about this accessory or if it's truly new. If it is new, add it to HomeKit.
if((accessory = this.platform.accessories.find(x => x.UUID === uuid)) === undefined) {

accessory = new this.api.platformAccessory(device.name ?? device.marketName ?? ("Unknown Device" + (device.mac ? ": " + device.mac : "")), uuid);
accessory = new this.api.platformAccessory(validateName(device.name ?? device.marketName ?? ("Unknown Device" + (device.mac ? " " + device.mac : ""))), uuid);

this.log.info("%s: Adding %s to HomeKit%s.", this.ufpApi.getDeviceName(device), device.modelKey,
this.hasFeature("Device.Standalone", device) ? " as a standalone device" : "");
Expand Down

0 comments on commit 5455c83

Please sign in to comment.