diff --git a/src/data/alarm_control_panel.ts b/src/data/alarm_control_panel.ts
index 64a8d53fee..acde378a13 100644
--- a/src/data/alarm_control_panel.ts
+++ b/src/data/alarm_control_panel.ts
@@ -10,8 +10,10 @@ import {
HassEntityAttributeBase,
HassEntityBase,
} from "home-assistant-js-websocket";
-import { HomeAssistant } from "../types";
import { supportsFeature } from "../common/entity/supports-feature";
+import { showEnterCodeDialog } from "../dialogs/enter-code/show-enter-code-dialog";
+import { HomeAssistant } from "../types";
+import { getExtendedEntityRegistryEntry } from "./entity_registry";
export const FORMAT_TEXT = "text";
export const FORMAT_NUMBER = "number";
@@ -103,3 +105,50 @@ export const supportedAlarmModes = (stateObj: AlarmControlPanelEntity) =>
const feature = ALARM_MODES[mode].feature;
return !feature || supportsFeature(stateObj, feature);
});
+
+export const setProtectedAlarmControlPanelMode = async (
+ element: HTMLElement,
+ hass: HomeAssistant,
+ stateObj: AlarmControlPanelEntity,
+ mode: AlarmMode
+) => {
+ const { service } = ALARM_MODES[mode];
+
+ let code: string | undefined;
+
+ if (
+ (mode !== "disarmed" &&
+ stateObj.attributes.code_arm_required &&
+ stateObj.attributes.code_format) ||
+ (mode === "disarmed" && stateObj.attributes.code_format)
+ ) {
+ const entry = await getExtendedEntityRegistryEntry(
+ hass,
+ stateObj.entity_id
+ ).catch(() => undefined);
+ const defaultCode = entry?.options?.alarm_control_panel?.default_code;
+
+ if (!defaultCode) {
+ const disarm = mode === "disarmed";
+
+ const response = await showEnterCodeDialog(element, {
+ codeFormat: stateObj.attributes.code_format,
+ title: hass.localize(
+ `ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
+ ),
+ submitText: hass.localize(
+ `ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
+ ),
+ });
+ if (response == null) {
+ throw new Error("Code dialog closed");
+ }
+ code = response;
+ }
+ }
+
+ await hass.callService("alarm_control_panel", service, {
+ entity_id: stateObj.entity_id,
+ code,
+ });
+};
diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts
index 2ebfd15778..02b72bf477 100644
--- a/src/data/entity_registry.ts
+++ b/src/data/entity_registry.ts
@@ -96,6 +96,10 @@ export interface LockEntityOptions {
default_code?: string | null;
}
+export interface AlarmControlPanelEntityOptions {
+ default_code?: string | null;
+}
+
export interface WeatherEntityOptions {
precipitation_unit?: string | null;
pressure_unit?: string | null;
@@ -112,6 +116,7 @@ export interface SwitchAsXEntityOptions {
export interface EntityRegistryOptions {
number?: NumberEntityOptions;
sensor?: SensorEntityOptions;
+ alarm_control_panel?: AlarmControlPanelEntityOptions;
lock?: LockEntityOptions;
weather?: WeatherEntityOptions;
light?: LightEntityOptions;
@@ -134,6 +139,7 @@ export interface EntityRegistryEntryUpdateParams {
| SensorEntityOptions
| NumberEntityOptions
| LockEntityOptions
+ | AlarmControlPanelEntityOptions
| WeatherEntityOptions
| LightEntityOptions;
aliases?: string[];
diff --git a/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts b/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts
index 3a28b4f4b7..430565433f 100644
--- a/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts
+++ b/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts
@@ -4,10 +4,12 @@ import { styleMap } from "lit/directives/style-map";
import { stateColorCss } from "../../../common/entity/state_color";
import "../../../components/ha-control-button";
import "../../../components/ha-state-icon";
-import { AlarmControlPanelEntity } from "../../../data/alarm_control_panel";
+import {
+ AlarmControlPanelEntity,
+ setProtectedAlarmControlPanelMode,
+} from "../../../data/alarm_control_panel";
import "../../../state-control/alarm_control_panel/ha-state-control-alarm_control_panel-modes";
import type { HomeAssistant } from "../../../types";
-import { showEnterCodeDialog } from "../../enter-code/show-enter-code-dialog";
import "../components/ha-more-info-state-header";
import { moreInfoControlStyle } from "../components/more-info-control-style";
@@ -18,24 +20,12 @@ class MoreInfoAlarmControlPanel extends LitElement {
@property({ attribute: false }) public stateObj?: AlarmControlPanelEntity;
private async _disarm() {
- let code: string | undefined;
-
- if (this.stateObj!.attributes.code_format) {
- const response = await showEnterCodeDialog(this, {
- codeFormat: this.stateObj!.attributes.code_format,
- title: this.hass.localize("ui.card.alarm_control_panel.disarm"),
- submitText: this.hass.localize("ui.card.alarm_control_panel.disarm"),
- });
- if (response == null) {
- return;
- }
- code = response;
- }
-
- this.hass.callService("alarm_control_panel", "alarm_disarm", {
- entity_id: this.stateObj!.entity_id,
- code,
- });
+ setProtectedAlarmControlPanelMode(
+ this,
+ this.hass,
+ this.stateObj!,
+ "disarmed"
+ );
}
protected render() {
diff --git a/src/panels/config/entities/entity-registry-settings-editor.ts b/src/panels/config/entities/entity-registry-settings-editor.ts
index b4e8edd885..a63850941a 100644
--- a/src/panels/config/entities/entity-registry-settings-editor.ts
+++ b/src/panels/config/entities/entity-registry-settings-editor.ts
@@ -59,6 +59,7 @@ import {
updateDeviceRegistryEntry,
} from "../../../data/device_registry";
import {
+ AlarmControlPanelEntityOptions,
EntityRegistryEntry,
EntityRegistryEntryUpdateParams,
ExtEntityRegistryEntry,
@@ -257,6 +258,10 @@ export class EntityRegistrySettingsEditor extends LitElement {
this._defaultCode = this.entry.options?.lock?.default_code;
}
+ if (domain === "alarm_control_panel") {
+ this._defaultCode = this.entry.options?.alarm_control_panel?.default_code;
+ }
+
if (domain === "weather") {
const stateObj: HassEntity | undefined =
this.hass.states[this.entry.entity_id];
@@ -583,6 +588,19 @@ export class EntityRegistrySettingsEditor extends LitElement {
>
`
: ""}
+ ${domain === "alarm_control_panel"
+ ? html`
+
+ `
+ : ""}
${domain === "sensor" &&
this._deviceClass &&
stateObj?.attributes.unit_of_measurement &&
@@ -1071,6 +1089,15 @@ export class EntityRegistrySettingsEditor extends LitElement {
params.options = this.entry.options?.[domain] || {};
(params.options as LockEntityOptions).default_code = this._defaultCode;
}
+ if (
+ domain === "alarm_control_panel" &&
+ this.entry.options?.[domain]?.default_code !== this._defaultCode
+ ) {
+ params.options_domain = domain;
+ params.options = this.entry.options?.[domain] || {};
+ (params.options as AlarmControlPanelEntityOptions).default_code =
+ this._defaultCode;
+ }
if (
domain === "weather" &&
(stateObj?.attributes?.precipitation_unit !== this._precipitation_unit ||
diff --git a/src/panels/lovelace/card-features/hui-alarm-modes-card-feature.ts b/src/panels/lovelace/card-features/hui-alarm-modes-card-feature.ts
index 926fdcea25..9b8ef39c99 100644
--- a/src/panels/lovelace/card-features/hui-alarm-modes-card-feature.ts
+++ b/src/panels/lovelace/card-features/hui-alarm-modes-card-feature.ts
@@ -16,10 +16,10 @@ import {
ALARM_MODES,
AlarmControlPanelEntity,
AlarmMode,
+ setProtectedAlarmControlPanelMode,
supportedAlarmModes,
} from "../../../data/alarm_control_panel";
import { UNAVAILABLE } from "../../../data/entity";
-import { showEnterCodeDialog } from "../../../dialogs/enter-code/show-enter-code-dialog";
import { HomeAssistant } from "../../../types";
import { LovelaceCardFeature, LovelaceCardFeatureEditor } from "../types";
import { filterModes } from "./common/filter-modes";
@@ -115,37 +115,7 @@ class HuiAlarmModeCardFeature
}
private async _setMode(mode: AlarmMode) {
- const { service } = ALARM_MODES[mode];
-
- let code: string | undefined;
-
- if (
- (mode !== "disarmed" &&
- this.stateObj!.attributes.code_arm_required &&
- this.stateObj!.attributes.code_format) ||
- (mode === "disarmed" && this.stateObj!.attributes.code_format)
- ) {
- const disarm = mode === "disarmed";
-
- const response = await showEnterCodeDialog(this, {
- codeFormat: this.stateObj!.attributes.code_format,
- title: this.hass!.localize(
- `ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
- ),
- submitText: this.hass!.localize(
- `ui.card.alarm_control_panel.${disarm ? "disarm" : "arm"}`
- ),
- });
- if (response == null) {
- throw new Error("cancel");
- }
- code = response;
- }
-
- await this.hass!.callService("alarm_control_panel", service, {
- entity_id: this.stateObj!.entity_id,
- code,
- });
+ setProtectedAlarmControlPanelMode(this, this.hass!, this.stateObj!, mode);
}
protected render(): TemplateResult | null {
diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts
index ecfce5fac2..225f30cea6 100644
--- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts
+++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts
@@ -1,4 +1,4 @@
-import { HassEntity } from "home-assistant-js-websocket";
+import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
CSSResultGroup,
LitElement,
@@ -30,6 +30,11 @@ import type { HomeAssistant } from "../../../types";
import { findEntities } from "../common/find-entities";
import { createEntityNotFoundWarning } from "../components/hui-warning";
import type { LovelaceCard } from "../types";
+import {
+ ExtEntityRegistryEntry,
+ getExtendedEntityRegistryEntry,
+ subscribeEntityRegistry,
+} from "../../../data/entity_registry";
import { AlarmPanelCardConfig, AlarmPanelCardConfigState } from "./types";
const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"];
@@ -99,8 +104,22 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
@state() private _config?: AlarmPanelCardConfig;
+ @state() private _entry?: ExtEntityRegistryEntry | null;
+
@query("#alarmCode") private _input?: HaTextField;
+ private _unsubEntityRegistry?: UnsubscribeFunc;
+
+ public connectedCallback() {
+ super.connectedCallback();
+ this._subscribeEntityEntry();
+ }
+
+ public disconnectedCallback() {
+ super.disconnectedCallback();
+ this._unsubscribeEntityRegistry();
+ }
+
public async getCardSize(): Promise {
if (!this._config || !this.hass) {
return 9;
@@ -123,6 +142,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
}
this._config = { ...config };
+ this._subscribeEntityEntry();
}
protected updated(changedProps: PropertyValues): void {
@@ -165,6 +185,36 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
);
}
+ private async _unsubscribeEntityRegistry() {
+ if (this._unsubEntityRegistry) {
+ this._unsubEntityRegistry();
+ this._unsubEntityRegistry = undefined;
+ }
+ }
+
+ private async _subscribeEntityEntry() {
+ if (!this._config?.entity) {
+ return;
+ }
+ try {
+ this._unsubEntityRegistry = subscribeEntityRegistry(
+ this.hass!.connection,
+ async (entries) => {
+ if (
+ entries.some((entry) => entry.entity_id === this._config!.entity)
+ ) {
+ this._entry = await getExtendedEntityRegistryEntry(
+ this.hass!,
+ this._config!.entity
+ );
+ }
+ }
+ );
+ } catch (e) {
+ this._entry = null;
+ }
+ }
+
protected render() {
if (!this._config || !this.hass) {
return nothing;
@@ -184,6 +234,8 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
const stateLabel = this._stateDisplay(stateObj.state);
+ const defaultCode = this._entry?.options?.alarm_control_panel?.default_code;
+
return html`