feat: Add event-based automation triggers (#2537)

This commit is contained in:
Dermot Duffy
2026-06-30 17:45:13 -07:00
committed by dermotduffy
parent b701366762
commit a31816c168
109 changed files with 4607 additions and 1623 deletions
+2 -7
View File
@@ -4,6 +4,7 @@ import { mediaLayoutConfigSchema } from './camera/media-layout';
import { ptzCameraConfigDefaults, ptzCameraConfigSchema } from './camera/ptz';
import { aspectRatioSchema } from './common/aspect-ratio';
import { eventsMediaTypeSchema } from './common/events-media';
import { haEventSchema } from './common/ha-event';
import { imageBaseConfigDefault, imageBaseConfigSchema } from './common/image';
import { proxyBaseConfigDefault, proxyBaseConfigSchema } from './common/proxy';
import { severitySchema } from './common/severity';
@@ -219,12 +220,6 @@ const cameraMediaConfigSchema = z.object({
.default(cameraMediaConfigDefault.reviewed),
});
const triggerEventSchema = z.object({
event_type: z.string().min(1),
event_data: z.record(z.string(), z.unknown()).optional(),
});
export type TriggerEvent = z.infer<typeof triggerEventSchema>;
export const cameraConfigSchema = z
.looseObject({
camera_entity: z.string().optional(),
@@ -259,7 +254,7 @@ export const cameraConfigSchema = z
occupancy: z.boolean().default(cameraConfigDefault.triggers.occupancy),
doorbell: z.boolean().default(cameraConfigDefault.triggers.doorbell),
entities: z.string().array().default(cameraConfigDefault.triggers.entities),
events: triggerEventSchema.array().default(cameraConfigDefault.triggers.events),
events: haEventSchema.array().default(cameraConfigDefault.triggers.events),
media_events: z
.enum(CAMERA_TRIGGER_MEDIA_EVENT_TYPES)
.array()
+30
View File
@@ -0,0 +1,30 @@
import { z } from 'zod';
import { stringOrArray } from './string-or-array';
// Filter on the event's `context` (HA's three fixed fields). Each defined field
// is equality-matched against a scalar or membership-matched against a list.
// `.strict()` rejects unknown keys at parse time so a typo (e.g. `user:` vs
// `user_id:`) surfaces instead of silently collapsing to "match everything".
const eventContextFilterSchema = z
.object({
id: stringOrArray.optional(),
user_id: stringOrArray.optional(),
parent_id: stringOrArray.optional(),
})
.strict();
export type HAEventContextFilter = z.infer<typeof eventContextFilterSchema>;
// A Home Assistant bus event filter: `event_type` (one type, or a list to match
// any of them) plus optional payload (`event_data`) and context (`context`)
// filters. `event_data` mirrors HA's matching exactly: listed keys (top-level
// and nested) must be present and extra keys are ignored -- see `event-match.ts`
// for the precise nested-object/array semantics. `context` is field-level
// equality or list-membership. Field names mirror HA's native event trigger
// exactly so the same YAML works in either place.
// https://www.home-assistant.io/docs/automation/trigger/#event-trigger
export const haEventSchema = z.object({
event_type: stringOrArray,
event_data: z.record(z.string(), z.unknown()).optional(),
context: eventContextFilterSchema.optional(),
});
export type HAEvent = z.infer<typeof haEventSchema>;
@@ -0,0 +1,11 @@
import { z } from 'zod';
import { haEventSchema } from '../../../common/ha-event';
import { triggerBaseSchema } from '../base';
// Subscribes to one or more Home Assistant bus event types and fires every time
// a matching event arrives. `event_type`, `event_data` and `context` filters
// mirror HA's native fields exactly.
// https://www.home-assistant.io/docs/automation/trigger/#event-trigger
export const eventTriggerSchema = triggerBaseSchema.extend(haEventSchema.shape).extend({
trigger: z.literal('event'),
});
@@ -13,12 +13,14 @@ import { microphoneTriggerSchema } from './custom/microphone';
import { screenTriggerSchema } from './custom/screen';
import { triggeredTriggerSchema } from './custom/triggered';
import { viewTriggerSchema } from './custom/view';
import { eventTriggerSchema } from './stock/event';
import { numericStateTriggerSchema } from './stock/numeric-state';
import { stateTriggerSchema } from './stock/state';
import { templateTriggerSchema } from './stock/template';
export const triggerSchema = z.union([
// Stock triggers (HA automation triggers):
eventTriggerSchema,
numericStateTriggerSchema,
stateTriggerSchema,
templateTriggerSchema,