mirror of
https://github.com/koush/scrypted.git
synced 2026-07-05 23:30:26 +01:00
alexa: doorbells
This commit is contained in:
@@ -2,10 +2,9 @@ import axios from 'axios';
|
||||
import sdk, { HttpRequest, HttpRequestHandler, HttpResponse, MixinProvider, ScryptedDevice, ScryptedDeviceBase, ScryptedDeviceType, ScryptedInterface } from '@scrypted/sdk';
|
||||
import { StorageSettings } from '@scrypted/common/src/settings';
|
||||
import { AutoenableMixinProvider } from '@scrypted/common/src/autoenable-mixin-provider';
|
||||
import crypto from 'crypto';
|
||||
import { isSupported } from './types';
|
||||
import { DiscoveryEndpoint, DiscoverEvent } from 'alexa-smarthome-ts';
|
||||
import { AlexaHandler, capabilityHandlers } from './types/common';
|
||||
import { AlexaHandler, capabilityHandlers, supportedTypes } from './types/common';
|
||||
import { createMessageId } from './message';
|
||||
|
||||
const { systemManager, deviceManager } = sdk;
|
||||
@@ -35,6 +34,44 @@ class AlexaPlugin extends AutoenableMixinProvider implements HttpRequestHandler,
|
||||
this.handlers.set('Alexa.Discovery', this.alexaDiscovery);
|
||||
|
||||
this.syncDevices();
|
||||
|
||||
systemManager.listen(async (eventSource, eventDetails, eventData) => {
|
||||
if (!this.storageSettings.values.syncedDevices.includes(eventSource.id))
|
||||
return;
|
||||
|
||||
const supportedType = supportedTypes.get(eventSource.type);
|
||||
if (!supportedType) {
|
||||
this.console.warn(`${eventSource.name} no longer supported type?`);
|
||||
return;
|
||||
}
|
||||
|
||||
const report = await supportedType.reportState(eventSource, eventDetails, eventData);
|
||||
|
||||
if (report?.type === 'event') {
|
||||
const accessToken = await this.getAccessToken();
|
||||
const data = {
|
||||
"context": {},
|
||||
"event": {
|
||||
"header": {
|
||||
"messageId": createMessageId(),
|
||||
"namespace": report.namespace,
|
||||
"name": report.name,
|
||||
"payloadVersion": "3"
|
||||
},
|
||||
"endpoint": {
|
||||
"scope": {
|
||||
"type": "BearerToken",
|
||||
"token": accessToken,
|
||||
},
|
||||
"endpointId": eventSource.id,
|
||||
},
|
||||
payload: report.payload,
|
||||
}
|
||||
}
|
||||
|
||||
await this.postEvent(accessToken, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getMixin(mixinDevice: any, mixinDeviceInterfaces: ScryptedInterface[], mixinDeviceState: { [key: string]: any; }): Promise<any> {
|
||||
@@ -237,7 +274,7 @@ class AlexaPlugin extends AutoenableMixinProvider implements HttpRequestHandler,
|
||||
}
|
||||
|
||||
async saveEndpoints(endpoints: DiscoveryEndpoint<any>[]) {
|
||||
const existingEndpoints: string[] = this.storageSettings.values.syncedDevices;
|
||||
const existingEndpoints: string[] = this.storageSettings.values.syncedDevices;
|
||||
const newEndpoints = endpoints.map(endpoint => endpoint.endpointId);
|
||||
const deleted = new Set(existingEndpoints);
|
||||
|
||||
|
||||
@@ -25,6 +25,9 @@ addSupportedType(ScryptedDeviceType.Camera, {
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
async reportState() {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
import { HttpRequest, HttpResponse, ScryptedDevice, ScryptedDeviceType } from "@scrypted/sdk";
|
||||
import { EventDetails, HttpRequest, HttpResponse, ScryptedDevice, ScryptedDeviceType } from "@scrypted/sdk";
|
||||
import {DiscoveryEndpoint, Directive} from 'alexa-smarthome-ts';
|
||||
|
||||
export type AlexaHandler = (request: HttpRequest, response: HttpResponse, directive: Directive) => Promise<void>
|
||||
export type AlexaCapabilityHandler<T> = (request: HttpRequest, response: HttpResponse, directive: Directive, device: ScryptedDevice & T) => Promise<void>
|
||||
|
||||
const supportedTypes = new Map<ScryptedDeviceType, SupportedType>();
|
||||
export const supportedTypes = new Map<ScryptedDeviceType, SupportedType>();
|
||||
export const capabilityHandlers = new Map<string, AlexaCapabilityHandler<any>>();
|
||||
|
||||
export interface EventReport {
|
||||
type: 'event';
|
||||
payload: any;
|
||||
namespace: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface StateReport {
|
||||
type: 'state';
|
||||
payload: any;
|
||||
}
|
||||
|
||||
export interface SupportedType {
|
||||
probe(device: ScryptedDevice): Partial<DiscoveryEndpoint<any>>;
|
||||
reportState(eventSource: ScryptedDevice, eventDetails: EventDetails, eventData: any): Promise<EventReport | StateReport>;
|
||||
}
|
||||
|
||||
export function addSupportedType(type: ScryptedDeviceType, supportedType: SupportedType) {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import sdk, { ScryptedDeviceType, ScryptedInterface } from "@scrypted/sdk";
|
||||
import { addSupportedType } from "./common";
|
||||
import sdk, { BinarySensor, ScryptedDevice, ScryptedDeviceType, ScryptedInterface } from "@scrypted/sdk";
|
||||
import { addSupportedType, EventReport } from "./common";
|
||||
|
||||
addSupportedType(ScryptedDeviceType.Doorbell, {
|
||||
probe(device) {
|
||||
if (!device.interfaces.includes(ScryptedInterface.VideoCamera))
|
||||
if (!device.interfaces.includes(ScryptedInterface.VideoCamera) || !device.interfaces.includes(ScryptedInterface.BinarySensor))
|
||||
return;
|
||||
|
||||
return {
|
||||
displayCategories: ['DOORBELL'],
|
||||
displayCategories: ['CAMERA'],
|
||||
capabilities: [
|
||||
{
|
||||
"type": "AlexaInterface",
|
||||
@@ -17,7 +17,28 @@ addSupportedType(ScryptedDeviceType.Doorbell, {
|
||||
"isFullDuplexAudioSupported": false,
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "AlexaInterface",
|
||||
"interface": "Alexa.DoorbellEventSource",
|
||||
"version": "3",
|
||||
"proactivelyReported": true
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
async reportState(eventSource: ScryptedDevice & BinarySensor, eventDetails, eventData): Promise<EventReport> {
|
||||
if (!eventSource.binaryState)
|
||||
return undefined;
|
||||
return {
|
||||
type: 'event',
|
||||
namespace: 'Alexa.DoorbellEventSource',
|
||||
name: 'DoorbellPress',
|
||||
payload: {
|
||||
"cause": {
|
||||
"type": "PHYSICAL_INTERACTION"
|
||||
},
|
||||
"timestamp": new Date().toISOString(),
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import './camera';
|
||||
import './doorbell';
|
||||
|
||||
export { isSupported} from './common';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user