Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default code to alarm_control_panel #20062

Merged
51 changes: 50 additions & 1 deletion src/data/alarm_control_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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,
});
};
6 changes: 6 additions & 0 deletions src/data/entity_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -112,6 +116,7 @@ export interface SwitchAsXEntityOptions {
export interface EntityRegistryOptions {
number?: NumberEntityOptions;
sensor?: SensorEntityOptions;
alarm_control_panel?: AlarmControlPanelEntityOptions;
lock?: LockEntityOptions;
weather?: WeatherEntityOptions;
light?: LightEntityOptions;
Expand All @@ -134,6 +139,7 @@ export interface EntityRegistryEntryUpdateParams {
| SensorEntityOptions
| NumberEntityOptions
| LockEntityOptions
| AlarmControlPanelEntityOptions
| WeatherEntityOptions
| LightEntityOptions;
aliases?: string[];
Expand Down
30 changes: 10 additions & 20 deletions src/dialogs/more-info/controls/more-info-alarm_control_panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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!,
piitaya marked this conversation as resolved.
Show resolved Hide resolved
"disarmed"
);
}

protected render() {
Expand Down
27 changes: 27 additions & 0 deletions src/panels/config/entities/entity-registry-settings-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
updateDeviceRegistryEntry,
} from "../../../data/device_registry";
import {
AlarmControlPanelEntityOptions,
gjohansson-ST marked this conversation as resolved.
Show resolved Hide resolved
EntityRegistryEntry,
EntityRegistryEntryUpdateParams,
ExtEntityRegistryEntry,
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -583,6 +588,19 @@ export class EntityRegistrySettingsEditor extends LitElement {
></ha-textfield>
`
: ""}
${domain === "alarm_control_panel"
? html`
<ha-textfield
.value=${this._defaultCode == null ? "" : this._defaultCode}
.label=${this.hass.localize(
"ui.dialogs.entity_registry.editor.default_code"
)}
type="password"
.disabled=${this.disabled}
@input=${this._defaultcodeChanged}
></ha-textfield>
`
: ""}
${domain === "sensor" &&
this._deviceClass &&
stateObj?.attributes.unit_of_measurement &&
Expand Down Expand Up @@ -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 ||
Expand Down
34 changes: 2 additions & 32 deletions src/panels/lovelace/card-features/hui-alarm-modes-card-feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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 {
Expand Down
58 changes: 55 additions & 3 deletions src/panels/lovelace/cards/hui-alarm-panel-card.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HassEntity } from "home-assistant-js-websocket";
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
import {
CSSResultGroup,
LitElement,
Expand Down Expand Up @@ -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"];
Expand Down Expand Up @@ -99,8 +104,22 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {

@state() private _config?: AlarmPanelCardConfig;

@state() private _entry?: ExtEntityRegistryEntry | null;

gjohansson-ST marked this conversation as resolved.
Show resolved Hide resolved
@query("#alarmCode") private _input?: HaTextField;

private _unsubEntityRegistry?: UnsubscribeFunc;

public connectedCallback() {
super.connectedCallback();
this._subscribeEntityEntry();
}

public disconnectedCallback() {
super.disconnectedCallback();
this._unsubscribeEntityRegistry();
}

public async getCardSize(): Promise<number> {
if (!this._config || !this.hass) {
return 9;
Expand All @@ -123,6 +142,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
}

this._config = { ...config };
this._subscribeEntityEntry();
}

protected updated(changedProps: PropertyValues): void {
Expand Down Expand Up @@ -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;
Expand All @@ -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`
<ha-card>
<h1 class="card-header">
Expand Down Expand Up @@ -222,7 +274,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
`
)}
</div>
${!stateObj.attributes.code_format
${!stateObj.attributes.code_format || defaultCode
? nothing
: html`
<ha-textfield
Expand All @@ -234,7 +286,7 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard {
: "text"}
></ha-textfield>
`}
${stateObj.attributes.code_format !== FORMAT_NUMBER
${stateObj.attributes.code_format !== FORMAT_NUMBER || defaultCode
? nothing
: html`
<div id="keypad">
Expand Down
Loading
Loading