Add support for users and numeric_conditions.

This commit is contained in:
Dermot Duffy
2024-03-10 14:30:45 -07:00
parent 219191e869
commit ff78cc51a1
7 changed files with 522 additions and 281 deletions
+28 -4
View File
@@ -1,3 +1,4 @@
import { CurrentUser } from '@dermotduffy/custom-card-helpers';
import { HassEntities } from 'home-assistant-js-websocket';
import merge from 'lodash-es/merge';
import { copyConfig } from '../config-mgmt';
@@ -22,6 +23,7 @@ interface ConditionState {
triggered?: Set<string>;
interaction?: boolean;
microphone?: MicrophoneConditionState;
user?: CurrentUser;
}
export class ConditionEvaluateRequestEvent extends Event {
@@ -174,7 +176,10 @@ export class ConditionsManager {
const conditions = getAllConditions();
this._hasHAStateConditions = conditions.some(
(condition) => !!condition.state?.length,
(condition) =>
!!condition.state?.length ||
!!condition.numeric_state?.length ||
!!condition.users?.length,
);
conditions.forEach((condition) => {
if (condition.media_query) {
@@ -192,7 +197,7 @@ export class ConditionsManager {
};
this._triggerChange();
}
public getState(): ConditionState {
return this._state;
}
@@ -235,11 +240,30 @@ export class ConditionsManager {
((!stateTest.state && !stateTest.state_not) ||
(stateTest.entity in state.state &&
(!stateTest.state ||
state.state[stateTest.entity].state === stateTest.state) &&
(Array.isArray(stateTest.state)
? stateTest.state.includes(state.state[stateTest.entity].state)
: stateTest.state === state.state[stateTest.entity].state)) &&
(!stateTest.state_not ||
state.state[stateTest.entity].state !== stateTest.state_not)));
(Array.isArray(stateTest.state_not)
? !stateTest.state_not.includes(state.state[stateTest.entity].state)
: stateTest.state_not !== state.state[stateTest.entity].state))));
}
}
if (condition.numeric_state?.length) {
for (const stateTest of condition.numeric_state) {
result &&=
!!state.state &&
stateTest.entity in state.state &&
state.state[stateTest.entity].state !== undefined &&
(stateTest.above === undefined ||
Number(state.state[stateTest.entity].state) > stateTest.above) &&
(stateTest.below === undefined ||
Number(state.state[stateTest.entity].state) < stateTest.below);
}
}
if (condition.users?.length) {
result &&= !!state.user && condition.users.includes(state.user.id);
}
if (condition.media_loaded !== undefined) {
result &&=
state.media_loaded !== undefined &&
+4 -1
View File
@@ -66,7 +66,10 @@ export class HASSManager {
}
if (this._api.getConditionsManager().hasHAStateConditions()) {
this._api.getConditionsManager().setState({ state: this._hass.states });
this._api.getConditionsManager().setState({
state: this._hass.states,
user: this._hass.user,
});
}
// Dark mode may depend on HASS.
+41 -12
View File
@@ -400,20 +400,47 @@ const imageSchema = elementsBaseSchema.extend({
aspect_ratio: z.string().optional(),
});
// This state condition is used both for the Picture elements conditional
// schema, and also in frigateCardConditionSchema.
const stateConditions = z
.object({
entity: z.string(),
state: z.string().optional(),
state_not: z.string().optional(),
})
.array();
// https://www.home-assistant.io/dashboards/conditional/#state
const stateCondition = z.object({
condition: z.literal('state'),
entity: z.string(),
state: z.string().or(z.string().array()).optional(),
state_not: z.string().or(z.string().array()).optional(),
});
// https://www.home-assistant.io/dashboards/conditional/#numeric-state
const numericCondition = z.object({
condition: z.literal('numeric_state'),
entity: z.string(),
above: z.number().optional(),
below: z.number().optional(),
});
const mediaQuerySchema = z.string();
// https://www.home-assistant.io/dashboards/conditional/#screen
const screenCondition = z.object({
condition: z.literal('screen'),
media_query: mediaQuerySchema,
});
// https://www.home-assistant.io/dashboards/conditional/#user
const usersCondition = z.object({
condition: z.literal('user'),
users: z.string().array().min(1),
});
const stockCondition = z.union([
stateCondition,
numericCondition,
screenCondition,
usersCondition,
]);
// https://www.home-assistant.io/lovelace/picture-elements/#image-element
export const conditionalSchema = z.object({
type: z.literal('conditional'),
conditions: stateConditions,
conditions: stockCondition.array(),
elements: z.lazy(() => pictureElementsSchema),
});
@@ -501,12 +528,14 @@ export const frigateCardConditionSchema = z.object({
expand: z.boolean().optional(),
camera: z.string().array().optional(),
media_loaded: z.boolean().optional(),
state: stateConditions.optional(),
media_query: z.string().optional(),
state: stateCondition.array().optional(),
numeric_state: numericCondition.array().optional(),
media_query: mediaQuerySchema.optional(),
display_mode: viewDisplayModeSchema.optional(),
triggered: z.string().array().optional(),
interaction: z.boolean().optional(),
microphone: microphoneConditionSchema.optional(),
users: z.string().array().optional()
});
export type FrigateCardCondition = z.infer<typeof frigateCardConditionSchema>;