Add support for perform-action calls.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
Call a service. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/).
|
||||
|
||||
!> Home Assistant has deprecated the `call-service` action, please use [`perform-action`](#perform-action) instead.
|
||||
|
||||
```yaml
|
||||
action: call-service
|
||||
# [...]
|
||||
@@ -27,6 +29,15 @@ action: navigate
|
||||
# [...]
|
||||
```
|
||||
|
||||
## `perform-action`
|
||||
|
||||
Perform a Home Assistant action. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/).
|
||||
|
||||
```yaml
|
||||
action: perform-action
|
||||
# [...]
|
||||
```
|
||||
|
||||
## `toggle`
|
||||
|
||||
Toggle an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/).
|
||||
@@ -117,4 +128,15 @@ elements:
|
||||
tap_action:
|
||||
action: fire-dom-event
|
||||
key: value
|
||||
- type: icon
|
||||
icon: mdi:numeric-8-box
|
||||
title: Perform action
|
||||
style:
|
||||
left: 200px
|
||||
top: 400px
|
||||
tap_action:
|
||||
action: perform-action
|
||||
perform_action: homeassistant.toggle
|
||||
target:
|
||||
entity_id: light.office_main_lights
|
||||
```
|
||||
|
||||
@@ -210,8 +210,8 @@ the integration currently offers.
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for relative movements. |
|
||||
| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. |
|
||||
| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [perform-action](../actions/stock/README.md?id=perform-action) action that will be called for each PTZ action for relative movements. |
|
||||
| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [perform-action](../actions/stock/README.md?id=perform-action) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. |
|
||||
| `c2r_delay_between_calls_seconds` | `0.2` | When the camera is configured with continuous actions only (e.g. `left_start` and `left_stop`, but not `left`), if something requests a relative action (e.g. a manually configured [action](../actions/README.md)), then `start` will be called, followed by a delay of this number of seconds and finally `stop` will be called. Cameras / integrations that are slower to respond to continuous steps may need to increase this value to avoid the continuous motion being too small. Cameras / integrations that are rapid to respond may need to decrease this value to avoid the "relative step" being too large. |
|
||||
| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for relative actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). |
|
||||
| `data_left_start`, `data_left_stop`, `data_right_start`, `data_right_stop`, `data_up_start`, `data_up_stop`, `data_down_start`, `data_down_stop`, `data_zoom_in_start`, `data_zoom_in_stop`, `data_zoom_out_start`, `data_zoom_out_stop` | | Shorthand for continuous actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]_start` and `actions_[action]_stop`. If both `actions_X_*` and `data_X_*` are specified, `actions_X_*` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). Both a `_start` and `_stop` variety must be provided for an action to be usable. |
|
||||
@@ -232,7 +232,7 @@ cameras:
|
||||
? [action]
|
||||
```
|
||||
|
||||
`[action]` is any [call-service](../actions/stock/README.md?id=call-service) action.
|
||||
`[action]` is any [perform-action](../actions/stock/README.md?id=perform-action) action.
|
||||
|
||||
## `triggers`
|
||||
|
||||
@@ -382,22 +382,22 @@ cameras:
|
||||
r2c_delay_between_calls_seconds: 0.5
|
||||
# Relative action (only `left` shown)
|
||||
actions_left:
|
||||
action: call-service
|
||||
service: service.of_your_choice
|
||||
action: perform-action
|
||||
perform_action: service.of_your_choice
|
||||
data:
|
||||
device: '048123'
|
||||
cmd: left
|
||||
# Continuous action (only `right` shown)
|
||||
actions_right_start:
|
||||
action: call-service
|
||||
service: service.of_your_choice
|
||||
action: perform-action
|
||||
perform_action: service.of_your_choice
|
||||
data:
|
||||
device: '048123'
|
||||
cmd: right
|
||||
phase: start
|
||||
actions_right_stop:
|
||||
action: call-service
|
||||
service: service.of_your_choice
|
||||
action: perform-action
|
||||
perform_action: service.of_your_choice
|
||||
data:
|
||||
device: '048123'
|
||||
phase: stop
|
||||
@@ -419,8 +419,8 @@ cameras:
|
||||
presets:
|
||||
# Preset using long form.
|
||||
armchair:
|
||||
action: call-service
|
||||
service: service.of_your_choice
|
||||
action: perform-action
|
||||
perform_action: service.of_your_choice
|
||||
data:
|
||||
device: '048123'
|
||||
cmd: preset
|
||||
|
||||
+4
-4
@@ -205,7 +205,7 @@ elements:
|
||||
right: 25px
|
||||
bottom: 50px
|
||||
tap_action:
|
||||
action: call-service
|
||||
action: perform-action
|
||||
service: amcrest.ptz_control
|
||||
data:
|
||||
entity_id: camera.kitchen
|
||||
@@ -252,9 +252,9 @@ elements:
|
||||
style:
|
||||
color: red
|
||||
tap_action:
|
||||
action: call-service
|
||||
service: homeassistant.toggle
|
||||
data:
|
||||
action: perform-action
|
||||
perform_action: homeassistant.toggle
|
||||
target:
|
||||
entity_id: siren.siren
|
||||
conditions:
|
||||
- condition: triggered
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@cycjimmy/jsmpeg-player": "^6.0.5",
|
||||
"@dermotduffy/custom-card-helpers": "^1.9.0",
|
||||
"@dermotduffy/custom-card-helpers": "^1.9.1",
|
||||
"@dermotduffy/panzoom": "^4.5.1",
|
||||
"@egjs/hammerjs": "^2.0.17",
|
||||
"@graphiteds/core": "^1.9.21",
|
||||
@@ -29,7 +29,7 @@
|
||||
"date-fns-tz": "^3.1.3",
|
||||
"embla-carousel": "^8.1.4",
|
||||
"embla-carousel-wheel-gestures": "^8.0.1",
|
||||
"home-assistant-js-websocket": "^8.2.0",
|
||||
"home-assistant-js-websocket": "^9.4.0",
|
||||
"keycharm": "^0.4.0",
|
||||
"lit": "^3.1.4",
|
||||
"lodash-es": "^4.17.21",
|
||||
|
||||
@@ -101,7 +101,6 @@ const config = {
|
||||
moduleContext: {
|
||||
'./node_modules/@formatjs/intl-utils/lib/src/diff.js': 'window',
|
||||
'./node_modules/@formatjs/intl-utils/lib/src/resolve-locale.js': 'window',
|
||||
'./node_modules/flatpickr/dist/esm/index.js': 'window',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay
|
||||
this._cachedValueController?.clearValue();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return !this.hasUpdated;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -229,12 +229,14 @@ export class FrigateCardSubmenuSelect extends LitElement {
|
||||
title: title || option,
|
||||
...((entityID.startsWith('select.') || entityID.startsWith('input_select.')) && {
|
||||
tap_action: {
|
||||
action: 'call-service',
|
||||
service: entityID.startsWith('select.')
|
||||
action: 'perform-action',
|
||||
perform_action: entityID.startsWith('select.')
|
||||
? 'select.select_option'
|
||||
: 'input_select.select_option',
|
||||
data: {
|
||||
target: {
|
||||
entity_id: entityID,
|
||||
},
|
||||
data: {
|
||||
option: option,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -446,6 +446,21 @@ const conditionToConditionsTransform = (data: unknown): boolean => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const callServiceToPerformActionTransform = (data: unknown): boolean => {
|
||||
if (
|
||||
typeof data !== 'object' ||
|
||||
!data ||
|
||||
data['action'] !== 'call-service' ||
|
||||
typeof data['service'] !== 'string'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
data['action'] = 'perform-action';
|
||||
data['perform_action'] = data['service'];
|
||||
delete data['service'];
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform service_data -> data
|
||||
* See: https://github.com/dermotduffy/frigate-hass-card/issues/1103
|
||||
@@ -849,4 +864,18 @@ const UPGRADES = [
|
||||
}),
|
||||
deleteWithOverrides('live.controls.title'),
|
||||
deleteWithOverrides('media_viewer.controls.title'),
|
||||
|
||||
// Upgrade call-service calls throughout the card config. They could show up
|
||||
// attached to any element, any automation, or any card/view action (i.e. very
|
||||
// broadly across the config), so it's challenging to better target this
|
||||
// upgrade. As written, this will convert things that look like call-service
|
||||
// calls recurseively throughout the whole card config, but this could
|
||||
// conceivably be an overreach if (e.g.) some totally unrelated object has {
|
||||
// action: 'call-service', service: '<any string>' } that means something
|
||||
// different.
|
||||
(data: unknown): boolean => {
|
||||
return upgradeObjectRecursively(callServiceToPerformActionTransform)(
|
||||
typeof data === 'object' && data ? (data as RawFrigateCardConfig) : {},
|
||||
);
|
||||
},
|
||||
];
|
||||
|
||||
+47
-21
@@ -4,9 +4,11 @@ import {
|
||||
MoreInfoActionConfig,
|
||||
NavigateActionConfig,
|
||||
NoActionConfig,
|
||||
PerformActionActionConfig,
|
||||
ToggleActionConfig,
|
||||
UrlActionConfig,
|
||||
} from '@dermotduffy/custom-card-helpers';
|
||||
import { HassServiceTarget } from 'home-assistant-js-websocket';
|
||||
import { z } from 'zod';
|
||||
import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js';
|
||||
import { capabilityKeys } from '../types.js';
|
||||
@@ -168,6 +170,28 @@ const toggleActionSchema = schemaForType<
|
||||
}),
|
||||
);
|
||||
|
||||
const targetSchema = schemaForType<HassServiceTarget>()(
|
||||
z.object({
|
||||
entity_id: z.string().optional(),
|
||||
device_id: z.string().optional(),
|
||||
area_id: z.string().optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
const performActionActionSchema = schemaForType<
|
||||
PerformActionActionConfig & ExtendedConfirmationRestrictionConfig
|
||||
>()(
|
||||
actionBaseSchema.extend({
|
||||
action: z.literal('perform-action'),
|
||||
perform_action: z.string(),
|
||||
data: z.object({}).passthrough().optional(),
|
||||
target: targetSchema.optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
// Note: call-service is deprecated and will eventually go away. Please use
|
||||
// perform-action instead.
|
||||
// See: https://www.home-assistant.io/blog/2024/08/07/release-20248/#goodbye-service-calls-hello-actions-
|
||||
const callServiceActionSchema = schemaForType<
|
||||
CallServiceActionConfig & ExtendedConfirmationRestrictionConfig
|
||||
>()(
|
||||
@@ -175,6 +199,7 @@ const callServiceActionSchema = schemaForType<
|
||||
action: z.literal('call-service'),
|
||||
service: z.string(),
|
||||
data: z.object({}).passthrough().optional(),
|
||||
target: targetSchema.optional(),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -391,6 +416,7 @@ export type FrigateCardCustomAction = z.infer<typeof frigateCardCustomActionSche
|
||||
export const actionSchema = z.union([
|
||||
toggleActionSchema,
|
||||
callServiceActionSchema,
|
||||
performActionActionSchema,
|
||||
navigateActionSchema,
|
||||
urlActionSchema,
|
||||
moreInfoActionSchema,
|
||||
@@ -814,8 +840,8 @@ const dataPTZFormatToFullFormat = function (suffix: string): (data: unknown) =>
|
||||
const name = match?.[1];
|
||||
if (name && !(`${suffix}${name}` in data)) {
|
||||
out[`${suffix}${name}`] = {
|
||||
action: 'call-service',
|
||||
service: data['service'],
|
||||
action: 'perform-action',
|
||||
perform_action: data['service'],
|
||||
data: data[key],
|
||||
};
|
||||
delete out[key];
|
||||
@@ -830,29 +856,29 @@ const ptzCameraConfigSchema = z.preprocess(
|
||||
dataPTZFormatToFullFormat('actions_'),
|
||||
z
|
||||
.object({
|
||||
actions_left: callServiceActionSchema.optional(),
|
||||
actions_left_start: callServiceActionSchema.optional(),
|
||||
actions_left_stop: callServiceActionSchema.optional(),
|
||||
actions_left: performActionActionSchema.optional(),
|
||||
actions_left_start: performActionActionSchema.optional(),
|
||||
actions_left_stop: performActionActionSchema.optional(),
|
||||
|
||||
actions_right: callServiceActionSchema.optional(),
|
||||
actions_right_start: callServiceActionSchema.optional(),
|
||||
actions_right_stop: callServiceActionSchema.optional(),
|
||||
actions_right: performActionActionSchema.optional(),
|
||||
actions_right_start: performActionActionSchema.optional(),
|
||||
actions_right_stop: performActionActionSchema.optional(),
|
||||
|
||||
actions_up: callServiceActionSchema.optional(),
|
||||
actions_up_start: callServiceActionSchema.optional(),
|
||||
actions_up_stop: callServiceActionSchema.optional(),
|
||||
actions_up: performActionActionSchema.optional(),
|
||||
actions_up_start: performActionActionSchema.optional(),
|
||||
actions_up_stop: performActionActionSchema.optional(),
|
||||
|
||||
actions_down: callServiceActionSchema.optional(),
|
||||
actions_down_start: callServiceActionSchema.optional(),
|
||||
actions_down_stop: callServiceActionSchema.optional(),
|
||||
actions_down: performActionActionSchema.optional(),
|
||||
actions_down_start: performActionActionSchema.optional(),
|
||||
actions_down_stop: performActionActionSchema.optional(),
|
||||
|
||||
actions_zoom_in: callServiceActionSchema.optional(),
|
||||
actions_zoom_in_start: callServiceActionSchema.optional(),
|
||||
actions_zoom_in_stop: callServiceActionSchema.optional(),
|
||||
actions_zoom_in: performActionActionSchema.optional(),
|
||||
actions_zoom_in_start: performActionActionSchema.optional(),
|
||||
actions_zoom_in_stop: performActionActionSchema.optional(),
|
||||
|
||||
actions_zoom_out: callServiceActionSchema.optional(),
|
||||
actions_zoom_out_start: callServiceActionSchema.optional(),
|
||||
actions_zoom_out_stop: callServiceActionSchema.optional(),
|
||||
actions_zoom_out: performActionActionSchema.optional(),
|
||||
actions_zoom_out_start: performActionActionSchema.optional(),
|
||||
actions_zoom_out_stop: performActionActionSchema.optional(),
|
||||
|
||||
// The number of seconds between subsequent relative calls when converting a
|
||||
// relative request into a continuous request.
|
||||
@@ -870,7 +896,7 @@ const ptzCameraConfigSchema = z.preprocess(
|
||||
.preprocess(
|
||||
dataPTZFormatToFullFormat(''),
|
||||
z.union([
|
||||
z.record(callServiceActionSchema),
|
||||
z.record(performActionActionSchema),
|
||||
|
||||
// This is used by the data_ style of action.
|
||||
z.object({ service: z.string().optional() }),
|
||||
|
||||
@@ -1120,8 +1120,8 @@ describe('CameraManager', async () => {
|
||||
const hass = createHASS();
|
||||
vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass);
|
||||
const action = {
|
||||
action: 'call-service' as const,
|
||||
service: 'service',
|
||||
action: 'perform-action' as const,
|
||||
perform_action: 'action',
|
||||
};
|
||||
const manager = createCameraManager(api, engine, [
|
||||
{
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
getConfiguredPTZAction,
|
||||
getConfiguredPTZMovementType,
|
||||
getPTZCapabilitiesFromCameraConfig,
|
||||
} from '../../../src/camera-manager/utils/ptz';
|
||||
import { createCameraConfig } from '../../test-utils';
|
||||
import { PTZAction } from '../../../src/config/ptz';
|
||||
import { createCameraConfig } from '../../test-utils';
|
||||
|
||||
const action = {
|
||||
action: 'call-service' as const,
|
||||
service: 'service',
|
||||
action: 'perform-action' as const,
|
||||
perform_action: 'action',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: 'preset',
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { PTZControlAction } from '../../src/config/ptz';
|
||||
import {
|
||||
Actions,
|
||||
PerformActionActionConfig,
|
||||
RawFrigateCardConfig,
|
||||
frigateCardConfigSchema,
|
||||
} from '../../src/config/types';
|
||||
@@ -752,8 +753,8 @@ describe('should handle version specific upgrades', () => {
|
||||
color: 'white',
|
||||
},
|
||||
tap_action: {
|
||||
action: 'call-service',
|
||||
service: 'notify.persistent_notification',
|
||||
action: 'perform-action',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
@@ -773,15 +774,15 @@ describe('should handle version specific upgrades', () => {
|
||||
view: {
|
||||
actions: {
|
||||
double_tap_action: {
|
||||
action: 'call-service',
|
||||
service: 'notify.persistent_notification',
|
||||
action: 'perform-action',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
data: {
|
||||
message: 'Hello 2',
|
||||
},
|
||||
},
|
||||
hold_action: {
|
||||
action: 'call-service',
|
||||
service: 'notify.persistent_notification',
|
||||
action: 'perform-action',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
data: {
|
||||
message: 'Hello 3',
|
||||
},
|
||||
@@ -812,7 +813,7 @@ describe('should handle version specific upgrades', () => {
|
||||
});
|
||||
|
||||
describe('should move PTZ elements to live', () => {
|
||||
it('case with 1 element', () => {
|
||||
it('xxx case with 1 element', () => {
|
||||
const config = {
|
||||
type: 'custom:frigate-card',
|
||||
cameras: [{ camera_entity: 'camera.office' }],
|
||||
@@ -843,11 +844,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -907,11 +908,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1000,11 +1001,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1073,11 +1074,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1160,11 +1161,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Hello 1',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1237,11 +1238,11 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
action: 'call-service',
|
||||
action: 'perform-action',
|
||||
data: {
|
||||
message: 'Original',
|
||||
},
|
||||
service: 'notify.persistent_notification',
|
||||
perform_action: 'notify.persistent_notification',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -2855,7 +2856,7 @@ describe('should handle version specific upgrades', () => {
|
||||
});
|
||||
|
||||
describe('split live.ptz', () => {
|
||||
const getAction = (action: PTZControlAction): CallServiceActionConfig => ({
|
||||
const getActionBefore = (action: PTZControlAction): CallServiceActionConfig => ({
|
||||
action: 'call-service',
|
||||
service: 'service',
|
||||
data: {
|
||||
@@ -2863,8 +2864,16 @@ describe('should handle version specific upgrades', () => {
|
||||
},
|
||||
});
|
||||
|
||||
const getActionAfter = (action: PTZControlAction): PerformActionActionConfig => ({
|
||||
action: 'perform-action',
|
||||
perform_action: 'service',
|
||||
data: {
|
||||
arg: action,
|
||||
},
|
||||
});
|
||||
|
||||
const getTapAction = (action: PTZControlAction): Actions => ({
|
||||
tap_action: getAction(action),
|
||||
tap_action: getActionBefore(action),
|
||||
});
|
||||
|
||||
it('with action_ format', () => {
|
||||
@@ -2882,7 +2891,7 @@ describe('should handle version specific upgrades', () => {
|
||||
actions_zoom_out: getTapAction('zoom_out'),
|
||||
actions_home: {
|
||||
...getTapAction('home'),
|
||||
double_tap_action: getAction('up'),
|
||||
double_tap_action: getActionBefore('up'),
|
||||
},
|
||||
|
||||
mode: 'auto' as const,
|
||||
@@ -2907,14 +2916,14 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras: [{}],
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_left: getAction('left'),
|
||||
actions_right: getAction('right'),
|
||||
actions_up: getAction('up'),
|
||||
actions_down: getAction('down'),
|
||||
actions_zoom_in: getAction('zoom_in'),
|
||||
actions_zoom_out: getAction('zoom_out'),
|
||||
actions_left: getActionAfter('left'),
|
||||
actions_right: getActionAfter('right'),
|
||||
actions_up: getActionAfter('up'),
|
||||
actions_down: getActionAfter('down'),
|
||||
actions_zoom_in: getActionAfter('zoom_in'),
|
||||
actions_zoom_out: getActionAfter('zoom_out'),
|
||||
presets: {
|
||||
home: getAction('home'),
|
||||
home: getActionAfter('home'),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3052,7 +3061,7 @@ describe('should handle version specific upgrades', () => {
|
||||
controls: {
|
||||
ptz: {
|
||||
actions_up: {
|
||||
double_tap_action: getAction('up'),
|
||||
double_tap_action: getActionBefore('up'),
|
||||
},
|
||||
actions_down: getTapAction('down'),
|
||||
},
|
||||
@@ -3065,7 +3074,7 @@ describe('should handle version specific upgrades', () => {
|
||||
expect.objectContaining({
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
actions_down: getAction('down'),
|
||||
actions_down: getActionAfter('down'),
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -3081,8 +3090,8 @@ describe('should handle version specific upgrades', () => {
|
||||
controls: {
|
||||
ptz: {
|
||||
presets: {
|
||||
home: getAction('left'),
|
||||
other: getAction('right'),
|
||||
home: getActionBefore('left'),
|
||||
other: getActionBefore('right'),
|
||||
},
|
||||
actions_home: getTapAction('home'),
|
||||
},
|
||||
@@ -3096,8 +3105,8 @@ describe('should handle version specific upgrades', () => {
|
||||
cameras_global: {
|
||||
ptz: {
|
||||
presets: {
|
||||
other: getAction('right'),
|
||||
home: getAction('home'),
|
||||
other: getActionAfter('right'),
|
||||
home: getActionAfter('home'),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -3303,5 +3312,60 @@ describe('should handle version specific upgrades', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('call-service -> perform-action', () => {
|
||||
const config = {
|
||||
type: 'custom:frigate-card',
|
||||
cameras: [{ camera_entity: 'camera.office' }],
|
||||
elements: [
|
||||
{
|
||||
type: 'icon',
|
||||
icon: 'mdi:cow',
|
||||
tap_action: {
|
||||
action: 'call-service',
|
||||
service: 'foo',
|
||||
},
|
||||
},
|
||||
],
|
||||
view: {
|
||||
actions: {
|
||||
double_tap_action: {
|
||||
action: 'call-service',
|
||||
service: 'bar',
|
||||
data: {
|
||||
key: 'value',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(upgradeConfig(config)).toBeTruthy();
|
||||
expect(config).toEqual({
|
||||
type: 'custom:frigate-card',
|
||||
cameras: [{ camera_entity: 'camera.office' }],
|
||||
elements: [
|
||||
{
|
||||
type: 'icon',
|
||||
icon: 'mdi:cow',
|
||||
tap_action: {
|
||||
action: 'perform-action',
|
||||
perform_action: 'foo',
|
||||
},
|
||||
},
|
||||
],
|
||||
view: {
|
||||
actions: {
|
||||
double_tap_action: {
|
||||
action: 'perform-action',
|
||||
perform_action: 'bar',
|
||||
data: {
|
||||
key: 'value',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
postUpgradeChecks(config);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+10
-10
@@ -423,8 +423,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => {
|
||||
expect.objectContaining({
|
||||
ptz: expect.objectContaining({
|
||||
[`actions_${action}`]: {
|
||||
action: 'call-service',
|
||||
service: 'foo',
|
||||
action: 'perform-action',
|
||||
perform_action: 'foo',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: action,
|
||||
@@ -465,8 +465,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => {
|
||||
expect.objectContaining({
|
||||
ptz: expect.objectContaining({
|
||||
[`actions_${action}_start`]: {
|
||||
action: 'call-service',
|
||||
service: 'foo',
|
||||
action: 'perform-action',
|
||||
perform_action: 'foo',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: action,
|
||||
@@ -474,8 +474,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => {
|
||||
},
|
||||
},
|
||||
[`actions_${action}_stop`]: {
|
||||
action: 'call-service',
|
||||
service: 'foo',
|
||||
action: 'perform-action',
|
||||
perform_action: 'foo',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: action,
|
||||
@@ -511,16 +511,16 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => {
|
||||
ptz: expect.objectContaining({
|
||||
presets: {
|
||||
home: {
|
||||
action: 'call-service',
|
||||
service: 'service_inner',
|
||||
action: 'perform-action',
|
||||
perform_action: 'service_inner',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: 'home',
|
||||
},
|
||||
},
|
||||
another: {
|
||||
action: 'call-service',
|
||||
service: 'service_inner',
|
||||
action: 'perform-action',
|
||||
perform_action: 'service_inner',
|
||||
data: {
|
||||
device: '048123',
|
||||
cmd: 'another',
|
||||
|
||||
@@ -603,18 +603,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@dermotduffy/custom-card-helpers@npm:^1.9.0":
|
||||
version: 1.9.0
|
||||
resolution: "@dermotduffy/custom-card-helpers@npm:1.9.0"
|
||||
"@dermotduffy/custom-card-helpers@npm:^1.9.1":
|
||||
version: 1.9.1
|
||||
resolution: "@dermotduffy/custom-card-helpers@npm:1.9.1"
|
||||
dependencies:
|
||||
"@formatjs/intl-utils": "npm:^3.8.4"
|
||||
home-assistant-js-websocket: "npm:^6.0.1"
|
||||
home-assistant-js-websocket: "npm:^9.4.0"
|
||||
intl-messageformat: "npm:^9.11.1"
|
||||
lit: "npm:^2.1.1"
|
||||
rollup: "npm:^2.63.0"
|
||||
superstruct: "npm:^0.15.3"
|
||||
typescript: "npm:^4.5.4"
|
||||
checksum: 10c0/312a31a9abe6ddc37109ffe2725df30e72213b4fa2cceacbb4bdb3712b46a73e49b9fb7fab69dc521050538e882d7180e3d7434011f637a34f2bc9098b880e97
|
||||
checksum: 10c0/e42073e00682195c3d253f9b36dc091f7329a5e2a5cdd395bf0988ec2c8585db887ef772975894e4a1126653a2f3cb348a4ea4c1fbe8ce739002fd0f8461da40
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4075,7 +4075,7 @@ __metadata:
|
||||
"@babel/plugin-proposal-decorators": "npm:^7.24.7"
|
||||
"@babel/plugin-transform-class-properties": "npm:^7.24.7"
|
||||
"@cycjimmy/jsmpeg-player": "npm:^6.0.5"
|
||||
"@dermotduffy/custom-card-helpers": "npm:^1.9.0"
|
||||
"@dermotduffy/custom-card-helpers": "npm:^1.9.1"
|
||||
"@dermotduffy/panzoom": "npm:^4.5.1"
|
||||
"@egjs/hammerjs": "npm:^2.0.17"
|
||||
"@graphiteds/core": "npm:^1.9.21"
|
||||
@@ -4106,7 +4106,7 @@ __metadata:
|
||||
eslint-config-airbnb-base: "npm:^15.0.0"
|
||||
eslint-config-prettier: "npm:^9.1.0"
|
||||
eslint-plugin-import: "npm:^2.29.1"
|
||||
home-assistant-js-websocket: "npm:^8.2.0"
|
||||
home-assistant-js-websocket: "npm:^9.4.0"
|
||||
jsdom: "npm:^21.1.2"
|
||||
keycharm: "npm:^0.4.0"
|
||||
lit: "npm:^3.1.4"
|
||||
@@ -4559,17 +4559,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"home-assistant-js-websocket@npm:^6.0.1":
|
||||
version: 6.1.1
|
||||
resolution: "home-assistant-js-websocket@npm:6.1.1"
|
||||
checksum: 10c0/fe00b8d7a681d39b31ac5078b79fa1ef67cccd37df2c7ec31b1ad9ded33c899570b453c9439db71c3bda24df6d0c1e3d9d040583b0717f4630476ab528120a9f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"home-assistant-js-websocket@npm:^8.2.0":
|
||||
version: 8.2.0
|
||||
resolution: "home-assistant-js-websocket@npm:8.2.0"
|
||||
checksum: 10c0/9a1f1f5cb39ce0629653347d5ae31a14f14742596c15fea7bd72f4c0ee4ce4613b1172b4f4df52f293b4e5aeb3b5ead75f395d5fe5c4785193e7d00f8355ef5a
|
||||
"home-assistant-js-websocket@npm:^9.4.0":
|
||||
version: 9.4.0
|
||||
resolution: "home-assistant-js-websocket@npm:9.4.0"
|
||||
checksum: 10c0/9c8a5ff903648ebe7856f62a58af53e3d89dd24a30c600a2145ed518cd5f5f2218345048cfc42bdc3ee5d6f2994da3948765c77b6012ed56cf4546173a1a1de1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user