homekit: watch for sps/pps parse error. show accessory mode port in settings.

This commit is contained in:
Koushik Dutta
2022-09-15 19:30:17 -07:00
parent 84abfeae5f
commit 4538767888
7 changed files with 64 additions and 53 deletions

View File

@@ -1,4 +1,4 @@
{
"scrypted.debugHost": "127.0.0.1"
"scrypted.debugHost": "koushik-mac"
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/homekit",
"version": "1.1.38",
"version": "1.1.40",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/homekit",
"version": "1.1.38",
"version": "1.1.40",
"dependencies": {
"@koush/werift-src": "file:../../external/werift",
"check-disk-space": "^3.3.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/homekit",
"version": "1.1.38",
"version": "1.1.40",
"description": "HomeKit Plugin for Scrypted",
"scripts": {
"scrypted-setup-project": "scrypted-setup-project",

View File

@@ -7,6 +7,8 @@ import { StorageSettingsDict } from '@scrypted/common/src/settings';
import crypto from 'crypto';
import { closeQuiet, createBindZero } from '@scrypted/common/src/listen-cluster';
import { once } from 'events';
import { randomPinCode } from './pincode';
import sdk from '@scrypted/sdk';
class HAPLocalStorage {
initSync() {
@@ -100,7 +102,11 @@ export function getRandomPort() {
return Math.round(30000 + Math.random() * 20000);
}
export function createHAPUsernameStorageSettingsDict(group?: string): StorageSettingsDict<'mac' | 'qrCode' | 'pincode'> {
export function createHAPUsernameStorageSettingsDict(device: { storage: Storage, name?: string }, group: string, networkGroup = group): StorageSettingsDict<'mac' | 'qrCode' | 'pincode' | 'portOverride' | 'resetAccessory'> {
const alertReload = () => {
sdk.log.a(`You must reload the HomeKit plugin for the changes to ${device.name} to take effect.`);
}
return {
qrCode: {
group,
@@ -109,9 +115,16 @@ export function createHAPUsernameStorageSettingsDict(group?: string): StorageSet
readonly: true,
description: "Scan with your iOS camera to pair this Scrypted with HomeKit.",
},
pincode: {
portOverride: {
group: networkGroup,
title: 'Bridge Port',
persistedDefaultValue: getRandomPort(),
description: 'Optional: The TCP port used by the Scrypted bridge. If none is specified, a random port will be chosen.',
type: 'number',
}, pincode: {
group,
title: "Manual Pairing Code",
persistedDefaultValue: randomPinCode(),
readonly: true,
},
mac: {
@@ -120,6 +133,22 @@ export function createHAPUsernameStorageSettingsDict(group?: string): StorageSet
title: "Username Override",
persistedDefaultValue: createHAPUsername(),
},
resetAccessory: {
group,
title: 'Reset Pairing',
description: 'Resetting the pairing will resync it to HomeKit as a new device. Bridged devices will automatically relink as a new device. Accessory devices must be manually removed from the Home app and re-paired. Enter RESET to reset the pairing.',
placeholder: 'RESET',
mapPut: (oldValue, newValue) => {
if (newValue === 'RESET') {
device.storage.removeItem('mac');
alertReload();
// generate a new reset accessory random value.
return crypto.randomBytes(8).toString('hex');
}
throw new Error('HomeKit Accessory Reset cancelled.');
},
mapGet: () => '',
},
}
}

View File

@@ -21,31 +21,19 @@ export class HomekitMixin<T> extends SettingsMixinDeviceBase<T> {
// todo: change this at some point.
persistedDefaultValue: false,
},
...createHAPUsernameStorageSettingsDict('HomeKit Pairing'),
resetAccessory: {
group: 'HomeKit Pairing',
title: 'Reset Pairing',
description: 'Resetting the pairing will resync it to HomeKit as a new device. Bridged devices will automatically relink as a new device. Accessory devices must be manually removed from the Home app and re-paired. Enter RESET to reset the pairing.',
placeholder: 'RESET',
mapPut: (oldValue, newValue) => {
if (newValue === 'RESET') {
this.storage.removeItem(this.storageSettings.keys.mac);
this.alertReload();
// generate a new reset accessory random value.
return crypto.randomBytes(8).toString('hex');
}
throw new Error('HomeKit Accessory Reset cancelled.');
},
mapGet: () => '',
},
...createHAPUsernameStorageSettingsDict(this, undefined, 'HomeKit Pairing'),
});
constructor(options: SettingsMixinDeviceOptions<T>) {
super(options);
const hideStandalone = !this.storageSettings.values.standalone;
// this may only change on reload of plugin.
this.storageSettings.settings.qrCode.hide = !this.storageSettings.values.standalone;
this.storageSettings.settings.pincode.hide = !this.storageSettings.values.standalone;
this.storageSettings.settings.qrCode.hide = hideStandalone;
this.storageSettings.settings.pincode.hide = hideStandalone;
this.storageSettings.settings.resetAccessory.hide = hideStandalone;
this.storageSettings.settings.portOverride.hide = hideStandalone;
}
alertReload() {

View File

@@ -28,27 +28,7 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider,
videoClipsId: string;
cameraMixins = new Map<string, CameraMixin>();
storageSettings = new StorageSettings(this, {
...createHAPUsernameStorageSettingsDict(),
pincode: {
title: "Manual Pairing Code",
persistedDefaultValue: randomPinCode(),
readonly: true,
},
resetAccessory: {
title: 'Reset Pairing',
description: 'This will reset the Scrypted HomeKit Bridge and all bridged devices. The previous Scrypted HomeKit Bridge must be removed from the Home app, and Scrypted must be paired with HomeKit again.',
placeholder: 'RESET',
mapPut: (oldValue, newValue) => {
if (newValue === 'RESET') {
this.storage.removeItem(this.storageSettings.keys.mac);
this.log.a(`You must reload the HomeKit plugin for the changes to take effect.`);
// generate a new reset accessory random value.
return crypto.randomBytes(8).toString('hex');
}
throw new Error('HomeKit Accessory Reset cancelled.');
},
mapGet: () => '',
},
...createHAPUsernameStorageSettingsDict(this, undefined, 'Network'),
addressOverride: {
group: 'Network',
title: 'Scrypted Server Address',
@@ -64,9 +44,9 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider,
},
portOverride: {
group: 'Network',
title: 'Bridge Port',
title: 'Server Port',
persistedDefaultValue: createRandomPort(),
description: 'Optional: The TCP port used by the Scrypted bridge. If none is specified, a random port will be chosen.',
description: 'Optional: The TCP port used by the Scrypted Server. If none is specified, a random port will be chosen.',
type: 'number',
},
advertiserOverride: {
@@ -208,7 +188,13 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider,
storage: mixinStorage,
onDeviceEvent: async () => {
}
}, createHAPUsernameStorageSettingsDict())
}, createHAPUsernameStorageSettingsDict({
storage: mixinStorage,
get name() {
return device.name
}
},
'HomeKit', 'HomeKit Pairing'));
storageSettings.settings.pincode.persistedDefaultValue = randomPinCode();
const mixinConsole = deviceManager.getMixinConsole(device.id, this.nativeId);
@@ -220,7 +206,7 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider,
published = true;
mixinConsole.log('Device is in accessory mode and is online. HomeKit services are being published.');
await this.publishAccessory(accessory, storageSettings.values.mac, storageSettings.values.pincode, standaloneCategory);
await this.publishAccessory(accessory, storageSettings.values.mac, storageSettings.values.pincode, standaloneCategory, storageSettings.values.portOverride);
if (!hasPublished) {
hasPublished = true;
storageSettings.values.qrCode = accessory.setupURI();
@@ -352,10 +338,10 @@ export class HomeKitPlugin extends ScryptedDeviceBase implements MixinProvider,
return ret;
}
async publishAccessory(accessory: Accessory, username: string, pincode: string, category: Categories) {
async publishAccessory(accessory: Accessory, username: string, pincode: string, category: Categories, port: number) {
await accessory.publish({
username,
port: 0,
port,
pincode,
category,
addIdentifyingMaterial: false,

View File

@@ -83,13 +83,21 @@ export async function startCameraStreamSrtp(media: FFmpegInput, console: Console
let opusFramesPerPacket = session.startRequest.audio.packet_time / 20;
let spsPps: ReturnType<typeof getSpsPps>;
try {
spsPps = getSpsPps(video);
}
catch (e) {
console.warn('sps/pps parse error', e);
}
const vs = createCameraStreamSender(console, session.vconfig, session.videoReturn,
session.videossrc, session.startRequest.video.pt,
session.prepareRequest.video.port, session.prepareRequest.targetAddress,
session.startRequest.video.rtcp_interval,
{
maxPacketSize: session.startRequest.video.mtu,
...getSpsPps(video),
...spsPps,
});
videoSender = vs.sendRtp;
vs.sendRtcp();