mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Add valve entity (#19024)
* Add valve entity * Update icon based on device class * Check assumed state first * Reset mode if entity id changes
This commit is contained in:
parent
ad543dbffb
commit
3e7fa66790
@ -28,10 +28,12 @@ import {
|
|||||||
mdiLockAlert,
|
mdiLockAlert,
|
||||||
mdiLockClock,
|
mdiLockClock,
|
||||||
mdiLockOpen,
|
mdiLockOpen,
|
||||||
|
mdiMeterGas,
|
||||||
mdiMotionSensor,
|
mdiMotionSensor,
|
||||||
mdiPackage,
|
mdiPackage,
|
||||||
mdiPackageDown,
|
mdiPackageDown,
|
||||||
mdiPackageUp,
|
mdiPackageUp,
|
||||||
|
mdiPipeValve,
|
||||||
mdiPowerPlug,
|
mdiPowerPlug,
|
||||||
mdiPowerPlugOff,
|
mdiPowerPlugOff,
|
||||||
mdiRestart,
|
mdiRestart,
|
||||||
@ -274,6 +276,16 @@ export const domainIconWithoutDefault = (
|
|||||||
: mdiPackageUp
|
: mdiPackageUp
|
||||||
: mdiPackage;
|
: mdiPackage;
|
||||||
|
|
||||||
|
case "valve":
|
||||||
|
switch (stateObj?.attributes.device_class) {
|
||||||
|
case "water":
|
||||||
|
return mdiPipeValve;
|
||||||
|
case "gas":
|
||||||
|
return mdiMeterGas;
|
||||||
|
default:
|
||||||
|
return mdiPipeValve;
|
||||||
|
}
|
||||||
|
|
||||||
case "water_heater":
|
case "water_heater":
|
||||||
return compareState === "off" ? mdiWaterBoilerOff : mdiWaterBoiler;
|
return compareState === "off" ? mdiWaterBoilerOff : mdiWaterBoiler;
|
||||||
|
|
||||||
|
@ -42,6 +42,8 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean {
|
|||||||
return compareState !== "standby";
|
return compareState !== "standby";
|
||||||
case "vacuum":
|
case "vacuum":
|
||||||
return !["idle", "docked", "paused"].includes(compareState);
|
return !["idle", "docked", "paused"].includes(compareState);
|
||||||
|
case "valve":
|
||||||
|
return compareState !== "closed";
|
||||||
case "plant":
|
case "plant":
|
||||||
return compareState === "problem";
|
return compareState === "problem";
|
||||||
case "group":
|
case "group":
|
||||||
|
@ -37,6 +37,7 @@ const STATE_COLORED_DOMAIN = new Set([
|
|||||||
"timer",
|
"timer",
|
||||||
"update",
|
"update",
|
||||||
"vacuum",
|
"vacuum",
|
||||||
|
"valve",
|
||||||
"water_heater",
|
"water_heater",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
102
src/components/ha-valve-controls.ts
Normal file
102
src/components/ha-valve-controls.ts
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import { mdiStop, mdiValveClosed, mdiValveOpen } from "@mdi/js";
|
||||||
|
import { CSSResultGroup, LitElement, html, css, nothing } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
|
import { supportsFeature } from "../common/entity/supports-feature";
|
||||||
|
import {
|
||||||
|
ValveEntity,
|
||||||
|
ValveEntityFeature,
|
||||||
|
canClose,
|
||||||
|
canOpen,
|
||||||
|
canStop,
|
||||||
|
} from "../data/valve";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import "./ha-icon-button";
|
||||||
|
|
||||||
|
@customElement("ha-valve-controls")
|
||||||
|
class HaValveControls extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj!: ValveEntity;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.stateObj) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="state">
|
||||||
|
<ha-icon-button
|
||||||
|
class=${classMap({
|
||||||
|
hidden: !supportsFeature(this.stateObj, ValveEntityFeature.OPEN),
|
||||||
|
})}
|
||||||
|
.label=${this.hass.localize("ui.card.valve.open_valve")}
|
||||||
|
@click=${this._onOpenTap}
|
||||||
|
.disabled=${!canOpen(this.stateObj)}
|
||||||
|
.path=${mdiValveOpen}
|
||||||
|
>
|
||||||
|
</ha-icon-button>
|
||||||
|
<ha-icon-button
|
||||||
|
class=${classMap({
|
||||||
|
hidden: !supportsFeature(this.stateObj, ValveEntityFeature.STOP),
|
||||||
|
})}
|
||||||
|
.label=${this.hass.localize("ui.card.valve.stop_valve")}
|
||||||
|
@click=${this._onStopTap}
|
||||||
|
.disabled=${!canStop(this.stateObj)}
|
||||||
|
.path=${mdiStop}
|
||||||
|
></ha-icon-button>
|
||||||
|
<ha-icon-button
|
||||||
|
class=${classMap({
|
||||||
|
hidden: !supportsFeature(this.stateObj, ValveEntityFeature.CLOSE),
|
||||||
|
})}
|
||||||
|
.label=${this.hass.localize("ui.card.valve.close_valve")}
|
||||||
|
@click=${this._onCloseTap}
|
||||||
|
.disabled=${!canClose(this.stateObj)}
|
||||||
|
.path=${mdiValveClosed}
|
||||||
|
>
|
||||||
|
</ha-icon-button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onOpenTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass.callService("valve", "open_valve", {
|
||||||
|
entity_id: this.stateObj.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onCloseTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass.callService("valve", "close_valve", {
|
||||||
|
entity_id: this.stateObj.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onStopTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass.callService("valve", "stop_valve", {
|
||||||
|
entity_id: this.stateObj.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.state {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
visibility: hidden !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-valve-controls": HaValveControls;
|
||||||
|
}
|
||||||
|
}
|
@ -65,7 +65,7 @@ export function canOpen(stateObj: CoverEntity) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const assumedState = stateObj.attributes.assumed_state === true;
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
return (!isFullyOpen(stateObj) && !isOpening(stateObj)) || assumedState;
|
return assumedState || (!isFullyOpen(stateObj) && !isOpening(stateObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canClose(stateObj: CoverEntity): boolean {
|
export function canClose(stateObj: CoverEntity): boolean {
|
||||||
@ -73,7 +73,7 @@ export function canClose(stateObj: CoverEntity): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const assumedState = stateObj.attributes.assumed_state === true;
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
return (!isFullyClosed(stateObj) && !isClosing(stateObj)) || assumedState;
|
return assumedState || (!isFullyClosed(stateObj) && !isClosing(stateObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canStop(stateObj: CoverEntity): boolean {
|
export function canStop(stateObj: CoverEntity): boolean {
|
||||||
@ -85,7 +85,7 @@ export function canOpenTilt(stateObj: CoverEntity): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const assumedState = stateObj.attributes.assumed_state === true;
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
return !isFullyOpenTilt(stateObj) || assumedState;
|
return assumedState || !isFullyOpenTilt(stateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canCloseTilt(stateObj: CoverEntity): boolean {
|
export function canCloseTilt(stateObj: CoverEntity): boolean {
|
||||||
@ -93,7 +93,7 @@ export function canCloseTilt(stateObj: CoverEntity): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const assumedState = stateObj.attributes.assumed_state === true;
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
return !isFullyClosedTilt(stateObj) || assumedState;
|
return assumedState || !isFullyClosedTilt(stateObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canStopTilt(stateObj: CoverEntity): boolean {
|
export function canStopTilt(stateObj: CoverEntity): boolean {
|
||||||
|
@ -75,6 +75,9 @@ export const DOMAIN_ATTRIBUTES_UNITS = {
|
|||||||
vacuum: {
|
vacuum: {
|
||||||
battery_level: "%",
|
battery_level: "%",
|
||||||
},
|
},
|
||||||
|
valve: {
|
||||||
|
current_position: "%",
|
||||||
|
},
|
||||||
sensor: {
|
sensor: {
|
||||||
battery_level: "%",
|
battery_level: "%",
|
||||||
},
|
},
|
||||||
|
85
src/data/valve.ts
Normal file
85
src/data/valve.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import {
|
||||||
|
HassEntityAttributeBase,
|
||||||
|
HassEntityBase,
|
||||||
|
} from "home-assistant-js-websocket";
|
||||||
|
import { UNAVAILABLE } from "./entity";
|
||||||
|
import { stateActive } from "../common/entity/state_active";
|
||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export const enum ValveEntityFeature {
|
||||||
|
OPEN = 1,
|
||||||
|
CLOSE = 2,
|
||||||
|
SET_POSITION = 4,
|
||||||
|
STOP = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFullyOpen(stateObj: ValveEntity) {
|
||||||
|
if (stateObj.attributes.current_position !== undefined) {
|
||||||
|
return stateObj.attributes.current_position === 100;
|
||||||
|
}
|
||||||
|
return stateObj.state === "open";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isFullyClosed(stateObj: ValveEntity) {
|
||||||
|
if (stateObj.attributes.current_position !== undefined) {
|
||||||
|
return stateObj.attributes.current_position === 0;
|
||||||
|
}
|
||||||
|
return stateObj.state === "closed";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isOpening(stateObj: ValveEntity) {
|
||||||
|
return stateObj.state === "opening";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isClosing(stateObj: ValveEntity) {
|
||||||
|
return stateObj.state === "closing";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canOpen(stateObj: ValveEntity) {
|
||||||
|
if (stateObj.state === UNAVAILABLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
|
return assumedState || (!isFullyOpen(stateObj) && !isOpening(stateObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canClose(stateObj: ValveEntity): boolean {
|
||||||
|
if (stateObj.state === UNAVAILABLE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const assumedState = stateObj.attributes.assumed_state === true;
|
||||||
|
return assumedState || (!isFullyClosed(stateObj) && !isClosing(stateObj));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function canStop(stateObj: ValveEntity): boolean {
|
||||||
|
return stateObj.state !== UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ValveEntityAttributes extends HassEntityAttributeBase {
|
||||||
|
current_position?: number;
|
||||||
|
position?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValveEntity extends HassEntityBase {
|
||||||
|
attributes: ValveEntityAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computeValvePositionStateDisplay(
|
||||||
|
stateObj: ValveEntity,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
position?: number
|
||||||
|
) {
|
||||||
|
const statePosition = stateActive(stateObj)
|
||||||
|
? stateObj.attributes.current_position
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const currentPosition = position ?? statePosition;
|
||||||
|
|
||||||
|
return currentPosition && currentPosition !== 100
|
||||||
|
? hass.formatEntityAttributeValue(
|
||||||
|
stateObj,
|
||||||
|
"current_position",
|
||||||
|
Math.round(currentPosition)
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
}
|
@ -27,6 +27,7 @@ export const DOMAINS_WITH_NEW_MORE_INFO = [
|
|||||||
"lock",
|
"lock",
|
||||||
"siren",
|
"siren",
|
||||||
"switch",
|
"switch",
|
||||||
|
"valve",
|
||||||
"water_heater",
|
"water_heater",
|
||||||
];
|
];
|
||||||
/** Domains with separate more info dialog. */
|
/** Domains with separate more info dialog. */
|
||||||
@ -61,6 +62,7 @@ export const DOMAINS_WITH_MORE_INFO = [
|
|||||||
"timer",
|
"timer",
|
||||||
"update",
|
"update",
|
||||||
"vacuum",
|
"vacuum",
|
||||||
|
"valve",
|
||||||
"water_heater",
|
"water_heater",
|
||||||
"weather",
|
"weather",
|
||||||
];
|
];
|
||||||
|
@ -42,7 +42,9 @@ class MoreInfoCover extends LitElement {
|
|||||||
protected willUpdate(changedProps: PropertyValues): void {
|
protected willUpdate(changedProps: PropertyValues): void {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
if (changedProps.has("stateObj") && this.stateObj) {
|
if (changedProps.has("stateObj") && this.stateObj) {
|
||||||
if (!this._mode) {
|
const entityId = this.stateObj.entity_id;
|
||||||
|
const oldEntityId = changedProps.get("stateObj")?.entity_id;
|
||||||
|
if (!this._mode || entityId !== oldEntityId) {
|
||||||
this._mode =
|
this._mode =
|
||||||
supportsFeature(this.stateObj, CoverEntityFeature.SET_POSITION) ||
|
supportsFeature(this.stateObj, CoverEntityFeature.SET_POSITION) ||
|
||||||
supportsFeature(this.stateObj, CoverEntityFeature.SET_TILT_POSITION)
|
supportsFeature(this.stateObj, CoverEntityFeature.SET_TILT_POSITION)
|
||||||
|
192
src/dialogs/more-info/controls/more-info-valve.ts
Normal file
192
src/dialogs/more-info/controls/more-info-valve.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { mdiMenu, mdiSwapVertical } from "@mdi/js";
|
||||||
|
import {
|
||||||
|
CSSResultGroup,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
|
nothing,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { supportsFeature } from "../../../common/entity/supports-feature";
|
||||||
|
import "../../../components/ha-attributes";
|
||||||
|
import "../../../components/ha-icon-button-group";
|
||||||
|
import "../../../components/ha-icon-button-toggle";
|
||||||
|
import {
|
||||||
|
ValveEntity,
|
||||||
|
ValveEntityFeature,
|
||||||
|
computeValvePositionStateDisplay,
|
||||||
|
} from "../../../data/valve";
|
||||||
|
import "../../../state-control/valve/ha-state-control-valve-buttons";
|
||||||
|
import "../../../state-control/valve/ha-state-control-valve-position";
|
||||||
|
import "../../../state-control/valve/ha-state-control-valve-toggle";
|
||||||
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import "../components/ha-more-info-state-header";
|
||||||
|
import { moreInfoControlStyle } from "../components/more-info-control-style";
|
||||||
|
|
||||||
|
type Mode = "position" | "button";
|
||||||
|
|
||||||
|
@customElement("more-info-valve")
|
||||||
|
class MoreInfoValve extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj?: ValveEntity;
|
||||||
|
|
||||||
|
@state() private _mode?: Mode;
|
||||||
|
|
||||||
|
private _setMode(ev) {
|
||||||
|
this._mode = ev.currentTarget.mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProps: PropertyValues): void {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (changedProps.has("stateObj") && this.stateObj) {
|
||||||
|
const entityId = this.stateObj.entity_id;
|
||||||
|
const oldEntityId = changedProps.get("stateObj")?.entity_id;
|
||||||
|
if (!this._mode || entityId !== oldEntityId) {
|
||||||
|
this._mode = supportsFeature(
|
||||||
|
this.stateObj,
|
||||||
|
ValveEntityFeature.SET_POSITION
|
||||||
|
)
|
||||||
|
? "position"
|
||||||
|
: "button";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private get _stateOverride() {
|
||||||
|
const stateDisplay = this.hass.formatEntityState(this.stateObj!);
|
||||||
|
|
||||||
|
const positionStateDisplay = computeValvePositionStateDisplay(
|
||||||
|
this.stateObj!,
|
||||||
|
this.hass
|
||||||
|
);
|
||||||
|
|
||||||
|
if (positionStateDisplay) {
|
||||||
|
return `${stateDisplay} ⸱ ${positionStateDisplay}`;
|
||||||
|
}
|
||||||
|
return stateDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this.hass || !this.stateObj) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const supportsPosition = supportsFeature(
|
||||||
|
this.stateObj,
|
||||||
|
ValveEntityFeature.SET_POSITION
|
||||||
|
);
|
||||||
|
|
||||||
|
const supportsOpenClose =
|
||||||
|
supportsFeature(this.stateObj, ValveEntityFeature.OPEN) ||
|
||||||
|
supportsFeature(this.stateObj, ValveEntityFeature.CLOSE) ||
|
||||||
|
supportsFeature(this.stateObj, ValveEntityFeature.STOP);
|
||||||
|
|
||||||
|
const supportsOpenCloseWithoutStop =
|
||||||
|
supportsFeature(this.stateObj, ValveEntityFeature.OPEN) &&
|
||||||
|
supportsFeature(this.stateObj, ValveEntityFeature.CLOSE) &&
|
||||||
|
!supportsFeature(this.stateObj, ValveEntityFeature.STOP);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-more-info-state-header
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
.stateOverride=${this._stateOverride}
|
||||||
|
></ha-more-info-state-header>
|
||||||
|
<div class="controls">
|
||||||
|
<div class="main-control">
|
||||||
|
${
|
||||||
|
this._mode === "position"
|
||||||
|
? html`
|
||||||
|
${supportsPosition
|
||||||
|
? html`
|
||||||
|
<ha-state-control-valve-position
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-state-control-valve-position>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
|
${
|
||||||
|
this._mode === "button"
|
||||||
|
? html`
|
||||||
|
${supportsOpenCloseWithoutStop
|
||||||
|
? html`
|
||||||
|
<ha-state-control-valve-toggle
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-state-control-valve-toggle>
|
||||||
|
`
|
||||||
|
: supportsOpenClose
|
||||||
|
? html`
|
||||||
|
<ha-state-control-valve-buttons
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></ha-state-control-valve-buttons>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
${
|
||||||
|
supportsPosition && supportsOpenClose
|
||||||
|
? html`
|
||||||
|
<ha-icon-button-group>
|
||||||
|
<ha-icon-button-toggle
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.dialogs.more_info_control.valve.switch_mode.position`
|
||||||
|
)}
|
||||||
|
.selected=${this._mode === "position"}
|
||||||
|
.path=${mdiMenu}
|
||||||
|
.mode=${"position"}
|
||||||
|
@click=${this._setMode}
|
||||||
|
></ha-icon-button-toggle>
|
||||||
|
<ha-icon-button-toggle
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.dialogs.more_info_control.valve.switch_mode.button`
|
||||||
|
)}
|
||||||
|
.selected=${this._mode === "button"}
|
||||||
|
.path=${mdiSwapVertical}
|
||||||
|
.mode=${"button"}
|
||||||
|
@click=${this._setMode}
|
||||||
|
></ha-icon-button-toggle>
|
||||||
|
</ha-icon-button-group>
|
||||||
|
`
|
||||||
|
: nothing
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ha-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
extra-filters="current_position,current_tilt_position"
|
||||||
|
></ha-attributes>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return [
|
||||||
|
moreInfoControlStyle,
|
||||||
|
css`
|
||||||
|
.main-control {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.main-control > * {
|
||||||
|
margin: 0 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"more-info-valve": MoreInfoValve;
|
||||||
|
}
|
||||||
|
}
|
@ -35,6 +35,7 @@ const LAZY_LOADED_MORE_INFO_CONTROL = {
|
|||||||
timer: () => import("./controls/more-info-timer"),
|
timer: () => import("./controls/more-info-timer"),
|
||||||
update: () => import("./controls/more-info-update"),
|
update: () => import("./controls/more-info-update"),
|
||||||
vacuum: () => import("./controls/more-info-vacuum"),
|
vacuum: () => import("./controls/more-info-vacuum"),
|
||||||
|
valve: () => import("./controls/more-info-valve"),
|
||||||
water_heater: () => import("./controls/more-info-water_heater"),
|
water_heater: () => import("./controls/more-info-water_heater"),
|
||||||
weather: () => import("./controls/more-info-weather"),
|
weather: () => import("./controls/more-info-weather"),
|
||||||
};
|
};
|
||||||
|
@ -251,6 +251,10 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
return this._renderStateContent(stateObj, ["state", "current_position"]);
|
return this._renderStateContent(stateObj, ["state", "current_position"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (domain === "valve" && active) {
|
||||||
|
return this._renderStateContent(stateObj, ["state", "current_position"]);
|
||||||
|
}
|
||||||
|
|
||||||
if (domain === "humidifier") {
|
if (domain === "humidifier") {
|
||||||
return this._renderStateContent(stateObj, ["state", "current_humidity"]);
|
return this._renderStateContent(stateObj, ["state", "current_humidity"]);
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,7 @@ const LAZY_LOAD_TYPES = {
|
|||||||
"time-entity": () => import("../entity-rows/hui-time-entity-row"),
|
"time-entity": () => import("../entity-rows/hui-time-entity-row"),
|
||||||
"timer-entity": () => import("../entity-rows/hui-timer-entity-row"),
|
"timer-entity": () => import("../entity-rows/hui-timer-entity-row"),
|
||||||
"update-entity": () => import("../entity-rows/hui-update-entity-row"),
|
"update-entity": () => import("../entity-rows/hui-update-entity-row"),
|
||||||
|
"valve-entity": () => import("../entity-rows/hui-valve-entity-row"),
|
||||||
conditional: () => import("../special-rows/hui-conditional-row"),
|
conditional: () => import("../special-rows/hui-conditional-row"),
|
||||||
"weather-entity": () => import("../entity-rows/hui-weather-entity-row"),
|
"weather-entity": () => import("../entity-rows/hui-weather-entity-row"),
|
||||||
divider: () => import("../special-rows/hui-divider-row"),
|
divider: () => import("../special-rows/hui-divider-row"),
|
||||||
@ -94,6 +95,7 @@ const DOMAIN_TO_ELEMENT_TYPE = {
|
|||||||
timer: "timer",
|
timer: "timer",
|
||||||
update: "update",
|
update: "update",
|
||||||
vacuum: "toggle",
|
vacuum: "toggle",
|
||||||
|
valve: "valve",
|
||||||
// Temporary. Once climate is rewritten,
|
// Temporary. Once climate is rewritten,
|
||||||
// water heater should get its own row.
|
// water heater should get its own row.
|
||||||
water_heater: "climate",
|
water_heater: "climate",
|
||||||
|
73
src/panels/lovelace/entity-rows/hui-valve-entity-row.ts
Normal file
73
src/panels/lovelace/entity-rows/hui-valve-entity-row.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
nothing,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../components/ha-valve-controls";
|
||||||
|
import { ValveEntity } from "../../../data/valve";
|
||||||
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { hasConfigOrEntityChanged } from "../common/has-changed";
|
||||||
|
import "../components/hui-generic-entity-row";
|
||||||
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
|
import { EntityConfig, LovelaceRow } from "./types";
|
||||||
|
|
||||||
|
@customElement("hui-valve-entity-row")
|
||||||
|
class HuiValveEntityRow extends LitElement implements LovelaceRow {
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _config?: EntityConfig;
|
||||||
|
|
||||||
|
public setConfig(config: EntityConfig): void {
|
||||||
|
if (!config) {
|
||||||
|
throw new Error("Invalid configuration");
|
||||||
|
}
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
|
return hasConfigOrEntityChanged(this, changedProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stateObj = this.hass.states[this._config.entity] as ValveEntity;
|
||||||
|
|
||||||
|
if (!stateObj) {
|
||||||
|
return html`
|
||||||
|
<hui-warning>
|
||||||
|
${createEntityNotFoundWarning(this.hass, this._config.entity)}
|
||||||
|
</hui-warning>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<hui-generic-entity-row .hass=${this.hass} .config=${this._config}>
|
||||||
|
<ha-valve-controls
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${stateObj}
|
||||||
|
></ha-valve-controls>
|
||||||
|
</hui-generic-entity-row>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-valve-controls {
|
||||||
|
margin-right: -0.57em;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-valve-entity-row": HuiValveEntityRow;
|
||||||
|
}
|
||||||
|
}
|
@ -174,6 +174,7 @@ const mainStyles = css`
|
|||||||
--state-switch-active-color: var(--amber-color);
|
--state-switch-active-color: var(--amber-color);
|
||||||
--state-update-active-color: var(--orange-color);
|
--state-update-active-color: var(--orange-color);
|
||||||
--state-vacuum-active-color: var(--teal-color);
|
--state-vacuum-active-color: var(--teal-color);
|
||||||
|
--state-valve-active-color: var(--blue-color);
|
||||||
--state-sensor-battery-high-color: var(--green-color);
|
--state-sensor-battery-high-color: var(--green-color);
|
||||||
--state-sensor-battery-low-color: var(--red-color);
|
--state-sensor-battery-low-color: var(--red-color);
|
||||||
--state-sensor-battery-medium-color: var(--orange-color);
|
--state-sensor-battery-medium-color: var(--orange-color);
|
||||||
|
145
src/state-control/valve/ha-state-control-valve-buttons.ts
Normal file
145
src/state-control/valve/ha-state-control-valve-buttons.ts
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
import { mdiStop, mdiValveClosed, mdiValveOpen } from "@mdi/js";
|
||||||
|
import {
|
||||||
|
CSSResultGroup,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
css,
|
||||||
|
html,
|
||||||
|
nothing,
|
||||||
|
} from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { supportsFeature } from "../../common/entity/supports-feature";
|
||||||
|
import "../../components/ha-control-button";
|
||||||
|
import "../../components/ha-control-button-group";
|
||||||
|
import "../../components/ha-control-slider";
|
||||||
|
import "../../components/ha-svg-icon";
|
||||||
|
import {
|
||||||
|
ValveEntity,
|
||||||
|
ValveEntityFeature,
|
||||||
|
canClose,
|
||||||
|
canOpen,
|
||||||
|
canStop,
|
||||||
|
} from "../../data/valve";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
|
type ValveButton = "open" | "close" | "stop" | "none";
|
||||||
|
|
||||||
|
export const getValveButtons = memoizeOne(
|
||||||
|
(stateObj: ValveEntity): ValveButton[] => {
|
||||||
|
const supportsOpen = supportsFeature(stateObj, ValveEntityFeature.OPEN);
|
||||||
|
const supportsClose = supportsFeature(stateObj, ValveEntityFeature.CLOSE);
|
||||||
|
const supportsStop = supportsFeature(stateObj, ValveEntityFeature.STOP);
|
||||||
|
|
||||||
|
const buttons: ValveButton[] = [];
|
||||||
|
if (supportsOpen) buttons.push("open");
|
||||||
|
if (supportsStop) buttons.push("stop");
|
||||||
|
if (supportsClose) buttons.push("close");
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
@customElement("ha-state-control-valve-buttons")
|
||||||
|
export class HaStateControlValveButtons extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj!: ValveEntity;
|
||||||
|
|
||||||
|
private _onOpenTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass!.callService("valve", "open_valve", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onCloseTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass!.callService("valve", "close_valve", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _onStopTap(ev): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this.hass!.callService("valve", "stop_valve", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected renderButton(button: ValveButton | undefined) {
|
||||||
|
if (button === "open") {
|
||||||
|
return html`
|
||||||
|
<ha-control-button
|
||||||
|
.label=${this.hass.localize("ui.card.valve.open_valve")}
|
||||||
|
@click=${this._onOpenTap}
|
||||||
|
.disabled=${!canOpen(this.stateObj)}
|
||||||
|
data-button="open"
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiValveOpen}></ha-svg-icon>
|
||||||
|
</ha-control-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
if (button === "close") {
|
||||||
|
return html`
|
||||||
|
<ha-control-button
|
||||||
|
.label=${this.hass.localize("ui.card.valve.close_valve")}
|
||||||
|
@click=${this._onCloseTap}
|
||||||
|
.disabled=${!canClose(this.stateObj)}
|
||||||
|
data-button="close"
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiValveClosed}></ha-svg-icon>
|
||||||
|
</ha-control-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
if (button === "stop") {
|
||||||
|
return html`
|
||||||
|
<ha-control-button
|
||||||
|
.label=${this.hass.localize("ui.card.valve.stop_valve")}
|
||||||
|
@click=${this._onStopTap}
|
||||||
|
.disabled=${!canStop(this.stateObj)}
|
||||||
|
data-button="stop"
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiStop}></ha-svg-icon>
|
||||||
|
</ha-control-button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
const buttons = getValveButtons(this.stateObj);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-control-button-group vertical>
|
||||||
|
${repeat(
|
||||||
|
buttons,
|
||||||
|
(button) => button,
|
||||||
|
(button) => this.renderButton(button)
|
||||||
|
)}
|
||||||
|
</ha-control-button-group>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-control-button-group {
|
||||||
|
height: 45vh;
|
||||||
|
max-height: 320px;
|
||||||
|
min-height: 200px;
|
||||||
|
--control-button-group-spacing: 6px;
|
||||||
|
--control-button-group-thickness: 100px;
|
||||||
|
}
|
||||||
|
ha-control-button {
|
||||||
|
--control-button-border-radius: 18px;
|
||||||
|
--mdc-icon-size: 24px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-state-control-valve-buttons": HaStateControlValveButtons;
|
||||||
|
}
|
||||||
|
}
|
88
src/state-control/valve/ha-state-control-valve-position.ts
Normal file
88
src/state-control/valve/ha-state-control-valve-position.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import { computeAttributeNameDisplay } from "../../common/entity/compute_attribute_display";
|
||||||
|
import { stateColorCss } from "../../common/entity/state_color";
|
||||||
|
import "../../components/ha-control-slider";
|
||||||
|
import { CoverEntity } from "../../data/cover";
|
||||||
|
import { UNAVAILABLE } from "../../data/entity";
|
||||||
|
import { DOMAIN_ATTRIBUTES_UNITS } from "../../data/entity_attributes";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
|
@customElement("ha-state-control-valve-position")
|
||||||
|
export class HaStateControlValvePosition extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj!: CoverEntity;
|
||||||
|
|
||||||
|
@state() value?: number;
|
||||||
|
|
||||||
|
protected updated(changedProp: Map<string | number | symbol, unknown>): void {
|
||||||
|
if (changedProp.has("stateObj")) {
|
||||||
|
const currentPosition = this.stateObj?.attributes.current_position;
|
||||||
|
this.value =
|
||||||
|
currentPosition != null ? Math.round(currentPosition) : undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent) {
|
||||||
|
const value = (ev.detail as any).value;
|
||||||
|
if (isNaN(value)) return;
|
||||||
|
|
||||||
|
this.hass.callService("valve", "set_valve_position", {
|
||||||
|
entity_id: this.stateObj!.entity_id,
|
||||||
|
position: value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
const color = stateColorCss(this.stateObj);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-control-slider
|
||||||
|
vertical
|
||||||
|
.value=${this.value}
|
||||||
|
min="0"
|
||||||
|
max="100"
|
||||||
|
show-handle
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
.ariaLabel=${computeAttributeNameDisplay(
|
||||||
|
this.hass.localize,
|
||||||
|
this.stateObj,
|
||||||
|
this.hass.entities,
|
||||||
|
"current_position"
|
||||||
|
)}
|
||||||
|
style=${styleMap({
|
||||||
|
"--control-slider-color": color,
|
||||||
|
"--control-slider-background": color,
|
||||||
|
})}
|
||||||
|
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||||
|
.unit=${DOMAIN_ATTRIBUTES_UNITS.valve.current_position}
|
||||||
|
.locale=${this.hass.locale}
|
||||||
|
>
|
||||||
|
</ha-control-slider>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-control-slider {
|
||||||
|
height: 45vh;
|
||||||
|
max-height: 320px;
|
||||||
|
min-height: 200px;
|
||||||
|
--control-slider-thickness: 100px;
|
||||||
|
--control-slider-border-radius: 24px;
|
||||||
|
--control-slider-color: var(--primary-color);
|
||||||
|
--control-slider-background: var(--disabled-color);
|
||||||
|
--control-slider-background-opacity: 0.2;
|
||||||
|
--control-slider-tooltip-font-size: 20px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-state-control-valve-position": HaStateControlValvePosition;
|
||||||
|
}
|
||||||
|
}
|
167
src/state-control/valve/ha-state-control-valve-toggle.ts
Normal file
167
src/state-control/valve/ha-state-control-valve-toggle.ts
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { classMap } from "lit/directives/class-map";
|
||||||
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import { domainIcon } from "../../common/entity/domain_icon";
|
||||||
|
import { stateColorCss } from "../../common/entity/state_color";
|
||||||
|
import "../../components/ha-control-button";
|
||||||
|
import "../../components/ha-control-switch";
|
||||||
|
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
|
import { forwardHaptic } from "../../data/haptics";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
|
@customElement("ha-state-control-valve-toggle")
|
||||||
|
export class HaStateControlValveToggle extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public stateObj!: HassEntity;
|
||||||
|
|
||||||
|
private _valueChanged(ev) {
|
||||||
|
const checked = ev.target.checked as boolean;
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
this._turnOn();
|
||||||
|
} else {
|
||||||
|
this._turnOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _turnOn() {
|
||||||
|
this._callService(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _turnOff() {
|
||||||
|
this._callService(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _callService(turnOn): Promise<void> {
|
||||||
|
if (!this.hass || !this.stateObj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
forwardHaptic("light");
|
||||||
|
|
||||||
|
await this.hass.callService(
|
||||||
|
"valve",
|
||||||
|
turnOn ? "open_valve" : "close_valve",
|
||||||
|
{
|
||||||
|
entity_id: this.stateObj.entity_id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
const onColor = stateColorCss(this.stateObj, "open");
|
||||||
|
const offColor = stateColorCss(this.stateObj, "closed");
|
||||||
|
|
||||||
|
const isOn =
|
||||||
|
this.stateObj.state === "open" ||
|
||||||
|
this.stateObj.state === "closing" ||
|
||||||
|
this.stateObj.state === "opening";
|
||||||
|
const isOff = this.stateObj.state === "closed";
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.stateObj.attributes.assumed_state ||
|
||||||
|
this.stateObj.state === UNKNOWN
|
||||||
|
) {
|
||||||
|
return html`
|
||||||
|
<div class="buttons">
|
||||||
|
<ha-control-button
|
||||||
|
.label=${this.hass.localize("ui.card.valve.open_valve")}
|
||||||
|
@click=${this._turnOn}
|
||||||
|
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||||
|
class=${classMap({
|
||||||
|
active: isOn,
|
||||||
|
})}
|
||||||
|
style=${styleMap({
|
||||||
|
"--color": onColor,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${domainIcon("valve", this.stateObj, "open")}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</ha-control-button>
|
||||||
|
<ha-control-button
|
||||||
|
.label=${this.hass.localize("ui.card.valve.close_valve")}
|
||||||
|
@click=${this._turnOff}
|
||||||
|
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||||
|
class=${classMap({
|
||||||
|
active: isOff,
|
||||||
|
})}
|
||||||
|
style=${styleMap({
|
||||||
|
"--color": offColor,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${domainIcon("valve", this.stateObj, "closed")}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</ha-control-button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-control-switch
|
||||||
|
.pathOn=${domainIcon("valve", this.stateObj, "open")}
|
||||||
|
.pathOff=${domainIcon("valve", this.stateObj, "closed")}
|
||||||
|
vertical
|
||||||
|
reversed
|
||||||
|
.checked=${isOn}
|
||||||
|
@change=${this._valueChanged}
|
||||||
|
.ariaLabel=${isOn
|
||||||
|
? this.hass.localize("ui.card.valve.close_valve")
|
||||||
|
: this.hass.localize("ui.card.valve.open_valve")}
|
||||||
|
style=${styleMap({
|
||||||
|
"--control-switch-on-color": onColor,
|
||||||
|
"--control-switch-off-color": offColor,
|
||||||
|
})}
|
||||||
|
.disabled=${this.stateObj.state === UNAVAILABLE}
|
||||||
|
>
|
||||||
|
</ha-control-switch>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-control-switch {
|
||||||
|
height: 45vh;
|
||||||
|
max-height: 320px;
|
||||||
|
min-height: 200px;
|
||||||
|
--control-switch-thickness: 100px;
|
||||||
|
--control-switch-border-radius: 24px;
|
||||||
|
--control-switch-padding: 6px;
|
||||||
|
--mdc-icon-size: 24px;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100px;
|
||||||
|
height: 45vh;
|
||||||
|
max-height: 320px;
|
||||||
|
min-height: 200px;
|
||||||
|
padding: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
ha-control-button {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
--control-button-border-radius: 18px;
|
||||||
|
--mdc-icon-size: 24px;
|
||||||
|
}
|
||||||
|
ha-control-button.active {
|
||||||
|
--control-button-icon-color: white;
|
||||||
|
--control-button-background-color: var(--color);
|
||||||
|
--control-button-background-opacity: 1;
|
||||||
|
}
|
||||||
|
ha-control-button:not(:last-child) {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-state-control-valve-toggle": HaStateControlValveToggle;
|
||||||
|
}
|
||||||
|
}
|
@ -255,6 +255,11 @@
|
|||||||
"turn_off": "Turn off"
|
"turn_off": "Turn off"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"valve": {
|
||||||
|
"open_valve": "Open valve",
|
||||||
|
"close_valve": "Close valve",
|
||||||
|
"stop_valve": "Stop valve"
|
||||||
|
},
|
||||||
"water_heater": {
|
"water_heater": {
|
||||||
"currently": "[%key:ui::card::climate::currently%]",
|
"currently": "[%key:ui::card::climate::currently%]",
|
||||||
"on_off": "On / off",
|
"on_off": "On / off",
|
||||||
@ -1094,6 +1099,12 @@
|
|||||||
"start_mowing": "Start mowing",
|
"start_mowing": "Start mowing",
|
||||||
"pause": "Pause",
|
"pause": "Pause",
|
||||||
"dock": "Return to dock"
|
"dock": "Return to dock"
|
||||||
|
},
|
||||||
|
"valve": {
|
||||||
|
"switch_mode": {
|
||||||
|
"button": "[%key:ui::dialogs::more_info_control::valve::switch_mode::button%]",
|
||||||
|
"position": "[%key:ui::dialogs::more_info_control::valve::switch_mode::position%]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entity_registry": {
|
"entity_registry": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user