mirror of
https://github.com/koush/scrypted.git
synced 2026-05-06 14:10:28 +01:00
Support v2 UI for sip and bticino plugins (#1521)
* Fix an undefined error that might occur when sip debug is off Slight cleanup Add support for v2 UI * Decouple voicemail lock device from camera device and only add it for c300x models (c100x doesn't have voicemail) Add support for v2 UI Allow changing devaddr setting from UI * Fix an undefined error that might occur when sip debug is off Slight cleanup Add support for v2 UI
This commit is contained in:
991
plugins/bticino/package-lock.json
generated
991
plugins/bticino/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/bticino",
|
||||
"version": "0.0.16",
|
||||
"version": "0.0.17",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
"prescrypted-setup-project": "scrypted-package-json",
|
||||
@@ -23,6 +23,8 @@
|
||||
"name": "BTicino SIP Plugin",
|
||||
"type": "DeviceProvider",
|
||||
"interfaces": [
|
||||
"ScryptedSystemDevice",
|
||||
"ScryptedDeviceCreator",
|
||||
"DeviceProvider",
|
||||
"DeviceCreator"
|
||||
],
|
||||
@@ -32,14 +34,14 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@slyoldfox/sip": "^0.0.6-1",
|
||||
"sdp": "^3.0.3",
|
||||
"stun": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/node": "^16.9.6",
|
||||
"@types/node": "^20.11.30",
|
||||
"cross-env": "^7.0.3",
|
||||
"ts-node": "^10.9.1"
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ import { VoicemailHandler } from "./bticino-voicemailHandler";
|
||||
|
||||
export class BticinoAswmSwitch extends ScryptedDeviceBase implements OnOff, HttpRequestHandler {
|
||||
private timeout : NodeJS.Timeout
|
||||
private voicemailHandler : VoicemailHandler
|
||||
|
||||
constructor(private camera: BticinoSipCamera, private voicemailHandler : VoicemailHandler) {
|
||||
constructor(private camera: BticinoSipCamera) {
|
||||
super( camera.nativeId + "-aswm-switch")
|
||||
this.voicemailHandler = new VoicemailHandler(camera)
|
||||
camera.requestHandlers.add(this.voicemailHandler)
|
||||
this.timeout = setTimeout( () => this.syncStatus() , 5000 )
|
||||
}
|
||||
|
||||
@@ -29,6 +32,7 @@ export class BticinoAswmSwitch extends ScryptedDeviceBase implements OnOff, Http
|
||||
if( this.timeout ) {
|
||||
clearTimeout(this.timeout)
|
||||
}
|
||||
this.voicemailHandler?.cancelTimer()
|
||||
}
|
||||
|
||||
public async onRequest(request: HttpRequest, response: HttpResponse): Promise<void> {
|
||||
|
||||
@@ -29,7 +29,6 @@ import { ControllerApi } from './c300x-controller-api';
|
||||
import { BticinoAswmSwitch } from './bticino-aswm-switch';
|
||||
import { BticinoMuteSwitch } from './bticino-mute-switch';
|
||||
|
||||
const STREAM_TIMEOUT = 65000;
|
||||
const { mediaManager } = sdk;
|
||||
const BTICINO_CLIPS = path.join(process.env.SCRYPTED_PLUGIN_VOLUME, 'bticino-clips');
|
||||
|
||||
@@ -42,7 +41,6 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
public requestHandlers: CompositeSipMessageHandler = new CompositeSipMessageHandler()
|
||||
public incomingCallRequest : SipRequest
|
||||
private settingsStorage: BticinoStorageSettings = new BticinoStorageSettings( this )
|
||||
private voicemailHandler : VoicemailHandler = new VoicemailHandler(this)
|
||||
private inviteHandler : InviteHandler = new InviteHandler(this)
|
||||
private controllerApi : ControllerApi = new ControllerApi(this)
|
||||
private muteSwitch : BticinoMuteSwitch
|
||||
@@ -60,7 +58,7 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
|
||||
constructor(nativeId: string, public provider: BticinoSipPlugin) {
|
||||
super(nativeId)
|
||||
this.requestHandlers.add( this.voicemailHandler ).add( this.inviteHandler )
|
||||
this.requestHandlers.add( this.inviteHandler )
|
||||
this.persistentSipManager = new PersistentSipManager( this );
|
||||
(async() => {
|
||||
this.doorbellWebhookUrl = await this.doorbellWebhookEndpoint()
|
||||
@@ -349,19 +347,13 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
this.forwarder = undefined
|
||||
}
|
||||
|
||||
resetStreamTimeout() {
|
||||
this.log.d('starting/refreshing stream')
|
||||
clearTimeout(this.refreshTimeout)
|
||||
this.refreshTimeout = setTimeout(() => this.stopSession(), STREAM_TIMEOUT)
|
||||
}
|
||||
|
||||
hasActiveCall() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
stopSession() {
|
||||
if (this.session) {
|
||||
this.log.d('ending sip session')
|
||||
this.console.log('ending sip session')
|
||||
this.session.stop()
|
||||
this.session = undefined
|
||||
}
|
||||
@@ -406,7 +398,7 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
if (this.session === sip)
|
||||
this.session = undefined
|
||||
try {
|
||||
this.log.d('cleanup(): stopping sip session.')
|
||||
this.console.log('cleanup(): stopping sip session.')
|
||||
sip?.stop()
|
||||
this.currentMediaObject = undefined
|
||||
}
|
||||
@@ -617,7 +609,7 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
|
||||
async getDevice(nativeId: string) : Promise<any> {
|
||||
if( nativeId && nativeId.endsWith('-aswm-switch')) {
|
||||
this.aswmSwitch = new BticinoAswmSwitch(this, this.voicemailHandler)
|
||||
this.aswmSwitch = new BticinoAswmSwitch(this)
|
||||
return this.aswmSwitch
|
||||
} else if( nativeId && nativeId.endsWith('-mute-switch') ) {
|
||||
this.muteSwitch = new BticinoMuteSwitch(this)
|
||||
@@ -633,7 +625,6 @@ export class BticinoSipCamera extends ScryptedDeviceBase implements MotionSensor
|
||||
this.muteSwitch.cancelTimer()
|
||||
} else {
|
||||
this.stopIntercom()
|
||||
this.voicemailHandler.cancelTimer()
|
||||
this.persistentSipManager.cancelTimer()
|
||||
this.controllerApi.cancelTimer()
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ export class ControllerApi {
|
||||
res.on("end", () => {
|
||||
try {
|
||||
let parsedBody = JSON.parse( body )
|
||||
if( !parsedBody["model"] ) {
|
||||
reject( new Error("Cannot determine model, update your c300x-controller.") )
|
||||
}
|
||||
if( parsedBody["errors"].length > 0 ) {
|
||||
reject( new Error( parsedBody["errors"][0] ) )
|
||||
} else {
|
||||
|
||||
@@ -9,6 +9,13 @@ export class BticinoSipPlugin extends ScryptedDeviceBase implements DeviceProvid
|
||||
|
||||
devices = new Map<string, BticinoSipCamera>()
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.systemDevice = {
|
||||
deviceCreator: 'Bticino Doorbell',
|
||||
};
|
||||
}
|
||||
|
||||
async getCreateDeviceSettings(): Promise<Setting[]> {
|
||||
return [
|
||||
{
|
||||
@@ -76,17 +83,18 @@ export class BticinoSipPlugin extends ScryptedDeviceBase implements DeviceProvid
|
||||
name: name + ' Muted',
|
||||
type: ScryptedDeviceType.Switch,
|
||||
interfaces: [ScryptedInterface.OnOff, ScryptedInterface.HttpRequestHandler],
|
||||
}
|
||||
}
|
||||
const devices = setupData["model"] === 'c100x' ? [lockDevice, muteSwitchDevice] : [lockDevice, aswmSwitchDevice, muteSwitchDevice]
|
||||
|
||||
await deviceManager.onDevicesChanged({
|
||||
providerNativeId: nativeId,
|
||||
devices: [lockDevice, aswmSwitchDevice, muteSwitchDevice],
|
||||
devices: devices
|
||||
})
|
||||
|
||||
let sipCamera : BticinoSipCamera = await this.getDevice(nativeId)
|
||||
|
||||
sipCamera.putSetting("sipfrom", "scrypted-" + sipCamera.id + "@127.0.0.1")
|
||||
sipCamera.putSetting("sipto", "c300x@" + setupData["ipAddress"] )
|
||||
sipCamera.putSetting("sipto", setupData["model"] + "@" + setupData["ipAddress"] )
|
||||
sipCamera.putSetting("sipdomain", setupData["domain"])
|
||||
sipCamera.putSetting("sipdebug", true )
|
||||
|
||||
|
||||
@@ -49,11 +49,23 @@ export class BticinoStorageSettings {
|
||||
description: 'Enable SIP debugging',
|
||||
placeholder: 'true or false',
|
||||
},
|
||||
DEVADDR: {
|
||||
title: 'Device address (DEVADDR)',
|
||||
type: 'string',
|
||||
description: 'Only specify if this is different than 20. For c100x this is a UUID, see: tcpdump -i lo port 5060',
|
||||
defaultValue: '20',
|
||||
placeholder: '20',
|
||||
},
|
||||
notifyVoicemail: {
|
||||
title: 'Notify on new voicemail messages',
|
||||
type: 'boolean',
|
||||
description: 'Enable voicemail alerts',
|
||||
placeholder: 'true or false',
|
||||
onGet: async () => {
|
||||
return {
|
||||
hide: this.storageSettings.values.sipto.indexOf('c100x') == 0,
|
||||
}
|
||||
}
|
||||
},
|
||||
doorbellWebhookUrl: {
|
||||
title: 'Doorbell Sensor Webhook',
|
||||
|
||||
6716
plugins/sip/package-lock.json
generated
6716
plugins/sip/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/sip",
|
||||
"version": "0.0.10",
|
||||
"version": "0.0.11",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
"prescrypted-setup-project": "scrypted-package-json",
|
||||
@@ -23,6 +23,8 @@
|
||||
"name": "SIP Plugin",
|
||||
"type": "DeviceProvider",
|
||||
"interfaces": [
|
||||
"ScryptedSystemDevice",
|
||||
"ScryptedDeviceCreator",
|
||||
"DeviceProvider",
|
||||
"DeviceCreator"
|
||||
],
|
||||
@@ -32,6 +34,8 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@slyoldfox/sip": "^0.0.6-1",
|
||||
"pick-port": "^1.0.0",
|
||||
"rxjs": "^7.8.1",
|
||||
@@ -39,9 +43,7 @@
|
||||
"stun": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/node": "^16.9.6",
|
||||
"@types/node": "^20.11.30",
|
||||
"cross-env": "^7.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { closeQuiet, createBindZero, listenZero } from '@scrypted/common/src/listen-cluster';
|
||||
import { StorageSettings } from '@scrypted/sdk/storage-settings';
|
||||
import sdk, { BinarySensor, Camera, Device, DeviceProvider, DeviceCreator, DeviceCreatorSettings, FFmpegInput, Intercom, MediaObject, MediaStreamUrl, PictureOptions, RequestMediaStreamOptions, RequestPictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera } from '@scrypted/sdk';
|
||||
import sdk, { BinarySensor, Camera, DeviceProvider, DeviceCreator, DeviceCreatorSettings, FFmpegInput, Intercom, MediaObject, PictureOptions, ResponseMediaStreamOptions, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface, ScryptedMimeTypes, Setting, Settings, SettingValue, VideoCamera } from '@scrypted/sdk';
|
||||
import child_process, { ChildProcess } from 'child_process';
|
||||
import { ffmpegLogInitialOutput, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
|
||||
import dgram from 'dgram';
|
||||
@@ -430,7 +430,9 @@ export class SipCamProvider extends ScryptedDeviceBase implements DeviceProvider
|
||||
|
||||
constructor(nativeId?: string) {
|
||||
super(nativeId);
|
||||
|
||||
this.systemDevice = {
|
||||
deviceCreator: 'SIP Camera',
|
||||
};
|
||||
for (const camId of deviceManager.getNativeIds()) {
|
||||
if (camId)
|
||||
this.getDevice(camId);
|
||||
|
||||
@@ -232,7 +232,8 @@ export class SipManager {
|
||||
}
|
||||
} else if( m.method == 'ACK' || m.method == 'BYE' ) {
|
||||
m.headers.to.uri = toWithDomain
|
||||
m.uri = this.registrarContact
|
||||
if(this.registrarContact)
|
||||
m.uri = this.registrarContact
|
||||
} else if( (m.method == undefined && m.status) && m.headers.cseq ) {
|
||||
if( m.status == '200' ) {
|
||||
// Response on invite
|
||||
|
||||
Reference in New Issue
Block a user