Skip to content

Commit

Permalink
camera
Browse files Browse the repository at this point in the history
  • Loading branch information
zoe-codez committed May 26, 2024
1 parent a70bb22 commit 2d79f37
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 38 deletions.
175 changes: 175 additions & 0 deletions src/extensions/domains/camera.extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { is, TServiceParams } from "@digital-alchemy/core";

import {
CameraConfiguration,
RemovableCallback,
SynapseCameraParams,
SynapseVirtualCamera,
VIRTUAL_ENTITY_BASE_KEYS,
} from "../../helpers";
import { TRegistry } from "../registry.extension";

export function VirtualCamera({ context, synapse }: TServiceParams) {
const registry = synapse.registry.create<SynapseVirtualCamera>({
context,
// @ts-expect-error it's fine
domain: "fan",
});

// #MARK: create
return function <
STATE extends string = string,
ATTRIBUTES extends object = object,
>(entity: SynapseCameraParams) {
const proxy = new Proxy({} as SynapseVirtualCamera, {
// #MARK: get
// eslint-disable-next-line sonarjs/cognitive-complexity
get(_, property: keyof SynapseVirtualCamera) {
// > common
// * name
if (property === "name") {
return entity.name;
}
// * unique_id
if (property === "unique_id") {
return unique_id;
}
// * onUpdate
if (property === "onUpdate") {
return loader.onUpdate();
}
// * _rawConfiguration
if (property === "_rawConfiguration") {
return loader.configuration;
}
// * _rawAttributes
if (property === "_rawAttributes") {
return loader.attributes;
}
// * attributes
if (property === "attributes") {
return loader.attributesProxy();
}
// * configuration
if (property === "configuration") {
return loader.configurationProxy();
}
// * state
if (property === "state") {
return loader.state;
}
// > domain specific
// * onTurnOn
if (property === "onTurnOn") {
return (callback: RemovableCallback) =>
synapse.registry.removableListener(TURN_ON, callback);
}
// * onTurnOff
if (property === "onTurnOff") {
return (callback: RemovableCallback) =>
synapse.registry.removableListener(TURN_OFF, callback);
}
// * onEnableMotionDetection
if (property === "onEnableMotionDetection") {
return (callback: RemovableCallback) =>
synapse.registry.removableListener(
ENABLE_MOTION_DETECTION,
callback,
);
}
// * onDisableMotionDetection
if (property === "onDisableMotionDetection") {
return (callback: RemovableCallback) =>
synapse.registry.removableListener(
DISABLE_MOTION_DETECTION,
callback,
);
}
return undefined;
},

ownKeys: () => [...VIRTUAL_ENTITY_BASE_KEYS, "onSetValue"],

// #MARK: set
set(_, property: string, value: unknown) {
// > common
// * state
if (property === "state") {
loader.setState(value as STATE);
return true;
}
// * attributes
if (property === "attributes") {
loader.setAttributes(value as ATTRIBUTES);
return true;
}
return false;
},
});

// - Add to registry
const unique_id = registry.add(proxy, entity);

// - Initialize value storage
const loader = synapse.storage.wrapper<
STATE,
ATTRIBUTES,
CameraConfiguration
>({
load_keys: [
"brand",
"frame_interval",
"frontend_stream_type",
"is_on",
"is_recording",
"is_streaming",
"model",
"motion_detection_enabled",
"use_stream_for_stills",
"supported_features",
],
name: entity.name,
registry: registry as TRegistry<unknown>,
unique_id,
});

// - Attach bus events
const TURN_ON = synapse.registry.busTransfer({
context,
eventName: "turn_on",
unique_id,
});
const TURN_OFF = synapse.registry.busTransfer({
context,
eventName: "turn_off",
unique_id,
});
const ENABLE_MOTION_DETECTION = synapse.registry.busTransfer({
context,
eventName: "enable_motion_detection",
unique_id,
});
const DISABLE_MOTION_DETECTION = synapse.registry.busTransfer({
context,
eventName: "disable_motion_detection",
unique_id,
});

// - Attach static listener
if (is.function(entity.turn_on)) {
proxy.onTurnOn(entity.turn_on);
}
if (is.function(entity.turn_off)) {
proxy.onTurnOff(entity.turn_off);
}
if (is.function(entity.enable_motion_detection)) {
proxy.onEnableMotionDetection(entity.enable_motion_detection);
}
if (is.function(entity.disable_motion_detection)) {
proxy.onDisableMotionDetection(entity.disable_motion_detection);
}

// - Done
return proxy;
};
}
1 change: 1 addition & 0 deletions src/extensions/domains/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from "./alarm-control-panel.extension";
export * from "./binary-sensor.extension";
export * from "./button.extension";
export * from "./camera.extension";
export * from "./climate.extension";
export * from "./cover.extension";
export * from "./date.extension";
Expand Down
71 changes: 34 additions & 37 deletions src/helpers/domains/camera.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
import { TContext } from "@digital-alchemy/core";
import {
BaseEntityParams,
BaseVirtualEntity,
CreateRemovableCallback,
RemovableCallback,
} from "../base-domain.helper";
import { EntityConfigCommon } from "../common-config.helper";

import { BASE_CONFIG_KEYS, EntityConfigCommon } from "../common-config.helper";
import { TSynapseId } from "../utility.helper";
export type SynapseCameraParams = BaseEntityParams<CameraStates> &
CameraConfiguration & {
turn_on?: RemovableCallback;
turn_off?: RemovableCallback;
enable_motion_detection?: RemovableCallback;
disable_motion_detection?: RemovableCallback;
};

export type TAlarmControlPanel<
STATE extends AlarmControlPanelValue,
ATTRIBUTES extends object = object,
> = {
context: TContext;
defaultState?: STATE;
defaultAttributes?: ATTRIBUTES;
name: string;
} & AlarmControlPanelConfiguration;
type CameraStates = "on" | "off";

export type AlarmControlPanelConfiguration = EntityConfigCommon & {
code_arm_required?: boolean;
code_format?: "text" | "number";
export type CameraConfiguration = EntityConfigCommon & {
brand?: string;
frame_interval?: number;
frontend_stream_type?: string;
is_on?: boolean;
is_recording?: boolean;
is_streaming?: boolean;
model?: string;
motion_detection_enabled?: boolean;
use_stream_for_stills?: boolean;
supported_features?: number;
changed_by?: string;
};

export type AlarmControlPanelValue =
| "disarmed"
| "armed_home"
| "armed_away"
| "armed_night"
| "armed_vacation"
| "armed_custom_bypass"
| "pending"
| "arming"
| "disarming"
| "triggered";

export const ALARM_CONTROL_PANEL_CONFIGURATION_KEYS = [
...BASE_CONFIG_KEYS,
"device_class",
] as (keyof AlarmControlPanelConfiguration)[];

export type HassAlarmControlPanelEvent = {
data: { unique_id: TSynapseId; code: string };
export type SynapseVirtualCamera = BaseVirtualEntity<
CameraStates,
object,
CameraConfiguration
> & {
onTurnOn?: CreateRemovableCallback;
onTurnOff?: CreateRemovableCallback;
onEnableMotionDetection?: CreateRemovableCallback;
onDisableMotionDetection?: CreateRemovableCallback;
};

export type RemoveReturn = { remove: () => void };
2 changes: 1 addition & 1 deletion src/helpers/domains/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from "./alarm-control-panel";
export * from "./binary-sensor";
export * from "./button";
// export * from "./camera";
export * from "./camera";
export * from "./climate";
export * from "./cover";
export * from "./date";
Expand Down
2 changes: 2 additions & 0 deletions src/synapse.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
VirtualAlarmControlPanel,
VirtualBinarySensor,
VirtualButton,
VirtualCamera,
VirtualClimate,
VirtualCover,
VirtualDate,
Expand Down Expand Up @@ -41,6 +42,7 @@ const DOMAINS = {
alarm_control_panel: VirtualAlarmControlPanel,
binary_sensor: VirtualBinarySensor,
button: VirtualButton,
camera: VirtualCamera,
climate: VirtualClimate,
cover: VirtualCover,
date: VirtualDate,
Expand Down

0 comments on commit 2d79f37

Please sign in to comment.