import type { Merge, UnionToIntersection } from '@matter/general'; import type { AnyMxRecord } from 'dns'; import { on, type EventEmitterAsyncResourceOptions, EventEmitter as BaseEventEmitter } from 'events'; import type { EventType } from '../../Events/EventType.js'; import { ISYEvent } from '../../Events/ISYEvent.js'; import type { ISY } from '../../ISY.js'; import type { ISYNode } from '../../ISYNode.js'; import type { UnitOfMeasure } from './UOM.js'; import type { ObjectToUnion, StringKeys } from '../../Utils.js'; import type { Command } from './Commands.js'; import { Driver } from './Drivers.js'; import type { Base } from '../../Devices/ZWave/index.js'; import { EventEmitter } from 'stream'; import type { RelayLampSwitch } from '../../Devices/Insteon/index.js'; //import { ISYNoCommandSignatures, DriverSignatures } from '../../ISYNode.js'; export namespace Event { export type Signature = | { name: string; driver: string; value: any; uom: UnitOfMeasure } | { name: string; command: string } | { name: any }; export type Signatures = { [x: string]: Signature }; export type DriverToEvent = { name: `${D['name']}Changed` | `${D['name']}Initialized`; value: D['value']; uom: D['uom']; }; export type CommandToEvent = { name: `${C['name']}Triggered` }; export type HandlerSignature = S extends { name: string; driver: string; value: any; uom: UnitOfMeasure; } ? { on( eventName: S['name'], listener: ( driver: S['driver'], newValue: S['value'], oldValue: S['value'], formatted: string, uom: S['uom'] ) => void ): N; } : S extends { name: string; command: string } ? { on(eventName: S['name'], listener: (command: S['command']) => void): N } : { on(eventName: S['name'], listener: (...args: any[]) => void): N }; export type ForAll< E extends ISYNode.EventSignatures, D extends ISYNode.DriverSignatures, C extends ISYNode.CommandSignatures, > = { [x in keyof E | keyof D]: x extends keyof D ? { name: `${D[x]['name']}Changed`; driver: x; value: D[x]['value']; uom: UnitOfMeasure } : x extends keyof C ? { name: `${C[x]['name']}Triggered`; command: x } : { name: x }; }; /*type ChangeEvents> = N extends ISYNode ? { [x in E]: N['events'][x] extends { driver } ? N['events'][x] : never } : never;*/ type TriggerEvents> = { [x in keyof N['events']]: x extends { command } ? N['events'][x] : never; }; type FunctionSignatureFor = UnionToIntersection< N extends ISYNode ? HandlerSignature, R> : never > & R; //& {on(eventName: keyof TriggerEvents, command: TriggerEvents[keyof TriggerEvents]): unksown} : never; export type FunctionSigFor = UnionToIntersection, N>>; type test1 = ForAll< { ST; '' }, Driver.Signatures< { ST: { name: 'Status'; label: 'Status'; uom: UnitOfMeasure; value: boolean; formatted: string } } | 'RR' >, any >; type test = FunctionSigFor & Omit; export type EventMapFor = { [x in StringKeys as `${D[x]['name']}Changed`]: [ newValue: D[x]['value'], oldValue: D[x]['value'], formatted: string, uom: D[x]['uom'], ]; } & { [x in keyof E as `${E[x]['name']}Triggered`]: any[]; }; //& Record; export type SafeEventMapFor = EventMapFor extends Record, any[]> ? EventMapFor : never; type test2 = EventMapFor; const c = new BaseEventEmitter() as BaseEventEmitter; export type EventEmitter< D extends ISYNode.DriverSignatures = {}, E extends ISYNode.EventSignatures = {}, > = BaseEventEmitter>; /*& { [x in keyof D]: { on: ( listener: (newValue: D[x]['value'], oldValue: D[x]['value'], formatted: string, uom: UnitOfMeasure) => void ) => BaseEventEmitter>; emit: (newValue: D[x]['value'], oldValue: D[x]['value'], formatted: string, uom: UnitOfMeasure) => boolean; }; } & { [x in keyof E]: { on: (listener: (...args: any[]) => void) => BaseEventEmitter>; emit: (...args: any[]) => boolean; }; }*/ export class NodeEventEmitter< N extends ISYNode, D extends ISYNode.DriverSignatures, C extends ISYNode.CommandSignatures, E extends ISYNode.EventSignatures, > extends BaseEventEmitter> { // #region Constructors (1) /** * Creates a new NodeEventEmitter for the given ISYNode. * @param node The ISYNode to create the event emitter for. */ constructor(node: N, events?: E) { super({ captureRejections: true }); for (let evt in node.drivers) { this[evt] = { on: (listener: (newValue: any, oldValue: any, formatted: string, uom: UnitOfMeasure) => void) => { //@ts-ignore return this.on(`${node.drivers[evt].name}Changed`, listener); }, emit: (newValue: any, oldValue: any, formatted: string, uom: UnitOfMeasure) => { // @ts-ignore return this.emit(`${node.drivers[evt].name}Changed`, newValue, oldValue, formatted, uom); }, }; } if (events) { this.map(events); } // #endregion Constructors (1) } public map(events: E) { for (let ev in events) { this[ev as string] = { on: (listener: (...args: any[]) => void) => { //@ts-ignore return this.on(`${events[ev].name}Triggered`, listener); }, emit: (...args: any[]) => { // @ts-ignore return this.emit(`${events[ev].name}Triggered`, ...args); }, }; } } public expects(eventName: string): boolean { return eventName in this; } } export function createEmitter< N extends ISYNode, D extends ISYNode.DriverSignatures, C extends ISYNode.CommandSignatures, E extends ISYNode.EventSignatures, >(node: N, events: E): NodeEventEmitter { var f = new NodeEventEmitter(node, events); return f; } export class ISYEvent { // #region Properties (2) public action: TAction; public eventInfo: any; // #endregion Properties (2) // #region Constructors (1) constructor(eventData: any) { this.action = eventData.action; this.eventInfo = eventData.eventInfo; } // #endregion Constructors (1) } export class NodeEvent extends ISYEvent { // #region Properties (1) public nodeAddress: string; // #endregion Properties (1) // #region Constructors (1) constructor(eventData: any) { super(eventData); this.nodeAddress = eventData.node; } // #endregion Constructors (1) } export class VariableEvent extends ISYEvent { // #region Properties (1) public variableName: string; // #endregion Properties (1) // #region Constructors (1) constructor(eventData: any) { super(eventData); this.variableName = eventData.variable; } // #endregion Constructors (1) } export class SystemEvent extends ISYEvent { // #region Constructors (1) constructor(eventData: any) { super(eventData); } // #endregion Constructors (1) } export class DeviceEvent extends ISYEvent { // #region Properties (1) public deviceAddress: string; // #endregion Properties (1) // #region Constructors (1) constructor(eventData: any) { super(eventData); this.deviceAddress = eventData.device; } // #endregion Constructors (1) } }