mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 01:06:35 +00:00
commit
00ad91af9a
@ -1,12 +1,11 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
|
||||
import "../../../src/components/ha-card";
|
||||
import { longPress } from "../../../src/panels/lovelace/common/directives/long-press-directive";
|
||||
|
||||
export class DemoUtilLongPress extends LitElement {
|
||||
public render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
${
|
||||
|
@ -17,7 +17,6 @@
|
||||
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@material/mwc-ripple": "^0.3.1",
|
||||
"@mdi/svg": "^3.0.39",
|
||||
"@polymer/app-layout": "^3.0.1",
|
||||
"@polymer/app-localize-behavior": "^3.0.1",
|
||||
@ -35,7 +34,6 @@
|
||||
"@polymer/iron-media-query": "^3.0.1",
|
||||
"@polymer/iron-pages": "^3.0.1",
|
||||
"@polymer/iron-resizable-behavior": "^3.0.1",
|
||||
"@polymer/lit-element": "0.6.2",
|
||||
"@polymer/neon-animation": "^3.0.1",
|
||||
"@polymer/paper-button": "^3.0.1",
|
||||
"@polymer/paper-card": "^3.0.1",
|
||||
@ -78,7 +76,8 @@
|
||||
"jquery": "^3.3.1",
|
||||
"js-yaml": "^3.12.0",
|
||||
"leaflet": "^1.3.4",
|
||||
"lit-html": "0.12.0",
|
||||
"lit-element": "2.0.0-rc.2",
|
||||
"lit-html": "1.0.0-rc.2",
|
||||
"marked": "^0.5.0",
|
||||
"mdn-polyfills": "^5.12.0",
|
||||
"moment": "^2.22.2",
|
||||
@ -158,9 +157,7 @@
|
||||
"@webcomponents/shadycss": "^1.6.0",
|
||||
"@vaadin/vaadin-overlay": "3.2.2",
|
||||
"@vaadin/vaadin-lumo-styles": "1.3.0",
|
||||
"fecha": "https://github.com/taylorhakes/fecha/archive/5e8fe08d982647fdb19fb403459838b02647813c.tar.gz",
|
||||
"lit-html": "0.12.0",
|
||||
"@polymer/lit-element": "0.6.2"
|
||||
"fecha": "https://github.com/taylorhakes/fecha/archive/5e8fe08d982647fdb19fb403459838b02647813c.tar.gz"
|
||||
},
|
||||
"main": "src/home-assistant.js",
|
||||
"husky": {
|
||||
|
@ -10,9 +10,10 @@ function patch(version) {
|
||||
|
||||
function today() {
|
||||
const now = new Date();
|
||||
return `${now.getFullYear()}${now.getMonth() + 1}${String(
|
||||
now.getDate()
|
||||
).padStart(2, "0")}.0`;
|
||||
return `${now.getFullYear()}${String(now.getMonth() + 1).padStart(
|
||||
2,
|
||||
"0"
|
||||
)}${String(now.getDate()).padStart(2, "0")}.0`;
|
||||
}
|
||||
|
||||
const methods = {
|
||||
@ -51,4 +52,4 @@ async function main(args) {
|
||||
console.log(stdout);
|
||||
}
|
||||
|
||||
main(process.argv.slice(2));
|
||||
main(process.argv.slice(2)).catch(console.error);
|
||||
|
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="home-assistant-frontend",
|
||||
version="20190109.1",
|
||||
version="20190116.0",
|
||||
description="The Home Assistant frontend",
|
||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||
author="The Home Assistant Authors",
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
|
||||
import { LitElement, html, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { LitElement, html, PropertyDeclarations } from "lit-element";
|
||||
import "./ha-auth-flow";
|
||||
import { AuthProvider } from "../data/auth";
|
||||
|
||||
@ -50,7 +50,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
protected render() {
|
||||
if (!this._authProviders) {
|
||||
return html`
|
||||
<p>[[localize('ui.panel.page-authorize.initializing')]]</p>
|
||||
|
@ -8,7 +8,7 @@
|
||||
export const DEFAULT_DOMAIN_ICON = "hass:bookmark";
|
||||
|
||||
/** Panel to show when no panel is picked. */
|
||||
export const DEFAULT_PANEL = "states";
|
||||
export const DEFAULT_PANEL = "lovelace";
|
||||
|
||||
/** Domains that have a state card. */
|
||||
export const DOMAINS_WITH_CARD = [
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { LitElement, html } from "@polymer/lit-element";
|
||||
import { LitElement, html } from "lit-element";
|
||||
|
||||
import "./ha-progress-button";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
|
@ -3,10 +3,10 @@ import {
|
||||
html,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import computeStateDomain from "../../common/entity/compute_state_domain";
|
||||
import computeStateName from "../../common/entity/compute_state_name";
|
||||
@ -41,7 +41,7 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
||||
this.clearInterval();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
const state = this.state;
|
||||
|
||||
if (!state) {
|
||||
|
@ -1,10 +1,13 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult, html } from "lit-html";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
TemplateResult,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import "./ha-icon";
|
||||
|
||||
class HaLabelBadge extends LitElement {
|
||||
@ -24,9 +27,8 @@ class HaLabelBadge extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<div class="badge-container">
|
||||
<div class="label-badge" id="badge">
|
||||
<div
|
||||
@ -77,9 +79,9 @@ class HaLabelBadge extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
protected renderStyle(): TemplateResult {
|
||||
return html`
|
||||
<style>
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
css`
|
||||
.badge-container {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
@ -148,8 +150,8 @@ class HaLabelBadge extends LitElement {
|
||||
text-overflow: ellipsis;
|
||||
line-height: normal;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
|
@ -20,6 +20,7 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
|
||||
<paper-toggle-button
|
||||
disabled="[[_compDisabled(disabled, loading)]]"
|
||||
checked="{{pushChecked}}"
|
||||
on-change="handlePushChange"
|
||||
></paper-toggle-button>
|
||||
`;
|
||||
}
|
||||
@ -35,7 +36,6 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
|
||||
type: Boolean,
|
||||
value:
|
||||
"Notification" in window && Notification.permission === "granted",
|
||||
observer: "handlePushChange",
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
@ -63,12 +63,12 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
|
||||
}
|
||||
}
|
||||
|
||||
handlePushChange(pushChecked) {
|
||||
handlePushChange(event) {
|
||||
// Somehow this is triggered on Safari on page load causing
|
||||
// it to get into a loop and crash the page.
|
||||
if (!pushSupported) return;
|
||||
|
||||
if (pushChecked) {
|
||||
if (event.target.checked) {
|
||||
this.subscribePushNotifications();
|
||||
} else {
|
||||
this.unsubscribePushNotifications();
|
||||
@ -77,10 +77,9 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
|
||||
|
||||
async subscribePushNotifications() {
|
||||
const reg = await navigator.serviceWorker.ready;
|
||||
let sub;
|
||||
|
||||
try {
|
||||
const sub = await reg.pushManager.subscribe({ userVisibleOnly: true });
|
||||
|
||||
let browserName;
|
||||
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
|
||||
browserName = "firefox";
|
||||
@ -88,12 +87,24 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) {
|
||||
browserName = "chrome";
|
||||
}
|
||||
|
||||
const name = prompt("What should this device be called ?");
|
||||
if (name == null) {
|
||||
this.pushChecked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
sub = await reg.pushManager.subscribe({ userVisibleOnly: true });
|
||||
|
||||
await this.hass.callApi("POST", "notify.html5", {
|
||||
subscription: sub,
|
||||
browser: browserName,
|
||||
name,
|
||||
});
|
||||
} catch (err) {
|
||||
const message = err.message || "Notification registration failed.";
|
||||
if (sub) {
|
||||
await sub.unsubscribe();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
console.error(err);
|
||||
|
@ -1,8 +1,28 @@
|
||||
import "@polymer/paper-slider";
|
||||
|
||||
const PaperSliderClass = customElements.get("paper-slider");
|
||||
let subTemplate;
|
||||
|
||||
class HaSlider extends PaperSliderClass {
|
||||
static get template() {
|
||||
if (!subTemplate) {
|
||||
subTemplate = PaperSliderClass.template.cloneNode(true);
|
||||
|
||||
const superStyle = subTemplate.content.querySelector("style");
|
||||
|
||||
// append style to add mirroring of pin in RTL
|
||||
superStyle.appendChild(
|
||||
document.createTextNode(`
|
||||
:host([dir="rtl"]) #sliderContainer.pin.expand > .slider-knob > .slider-knob-inner::after {
|
||||
-webkit-transform: scale(1) translate(0, -17px) scaleX(-1) !important;
|
||||
transform: scale(1) translate(0, -17px) scaleX(-1) !important;
|
||||
}
|
||||
`)
|
||||
);
|
||||
}
|
||||
return subTemplate;
|
||||
}
|
||||
|
||||
_calcStep(value) {
|
||||
if (!this.step) {
|
||||
return parseFloat(value);
|
||||
|
@ -20,6 +20,10 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) {
|
||||
:host([rendered]) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
ha-chart-base {
|
||||
direction: ltr;
|
||||
}
|
||||
</style>
|
||||
<ha-chart-base
|
||||
data="[[chartData]]"
|
||||
@ -185,6 +189,11 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) {
|
||||
afterSetDimensions: (yaxe) => {
|
||||
yaxe.maxWidth = yaxe.chart.width * 0.18;
|
||||
},
|
||||
position: this.hass.translationMetadata.translations[
|
||||
this.hass.selectedLanguage || this.hass.language
|
||||
].isRTL
|
||||
? "right"
|
||||
: "left",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export const FORMAT_TEXT = "text";
|
||||
export const FORMAT_NUMBER = "number";
|
||||
|
||||
export const callAlarmAction = (
|
||||
hass: HomeAssistant,
|
||||
entity: string,
|
||||
|
104
src/data/zha.ts
Normal file
104
src/data/zha.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { HomeAssistant } from "../types";
|
||||
|
||||
export interface ZHADeviceEntity extends HassEntity {
|
||||
device_info?: {
|
||||
identifiers: any[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface ZHAEntities {
|
||||
[key: string]: HassEntity[];
|
||||
}
|
||||
|
||||
export interface Attribute {
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface Cluster {
|
||||
name: string;
|
||||
id: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Command {
|
||||
name: string;
|
||||
id: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ReadAttributeServiceData {
|
||||
entity_id: string;
|
||||
cluster_id: number;
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
manufacturer: number;
|
||||
}
|
||||
|
||||
export const reconfigureNode = (
|
||||
hass: HomeAssistant,
|
||||
ieeeAddress: string
|
||||
): Promise<void> =>
|
||||
hass.callWS({
|
||||
type: "zha/nodes/reconfigure",
|
||||
ieee: ieeeAddress,
|
||||
});
|
||||
|
||||
export const fetchAttributesForCluster = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string,
|
||||
ieeeAddress: string,
|
||||
clusterId: number,
|
||||
clusterType: string
|
||||
): Promise<Attribute[]> =>
|
||||
hass.callWS({
|
||||
type: "zha/entities/clusters/attributes",
|
||||
entity_id: entityId,
|
||||
ieee: ieeeAddress,
|
||||
cluster_id: clusterId,
|
||||
cluster_type: clusterType,
|
||||
});
|
||||
|
||||
export const readAttributeValue = (
|
||||
hass: HomeAssistant,
|
||||
data: ReadAttributeServiceData
|
||||
): Promise<string> => {
|
||||
return hass.callWS({
|
||||
...data,
|
||||
type: "zha/entities/clusters/attributes/value",
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchCommandsForCluster = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string,
|
||||
ieeeAddress: string,
|
||||
clusterId: number,
|
||||
clusterType: string
|
||||
): Promise<Command[]> =>
|
||||
hass.callWS({
|
||||
type: "zha/entities/clusters/commands",
|
||||
entity_id: entityId,
|
||||
ieee: ieeeAddress,
|
||||
cluster_id: clusterId,
|
||||
cluster_type: clusterType,
|
||||
});
|
||||
|
||||
export const fetchClustersForZhaNode = (
|
||||
hass: HomeAssistant,
|
||||
entityId: string,
|
||||
ieeeAddress: string
|
||||
): Promise<Cluster[]> =>
|
||||
hass.callWS({
|
||||
type: "zha/entities/clusters",
|
||||
entity_id: entityId,
|
||||
ieee: ieeeAddress,
|
||||
});
|
||||
|
||||
export const fetchEntitiesForZhaNode = (
|
||||
hass: HomeAssistant
|
||||
): Promise<ZHAEntities> =>
|
||||
hass.callWS({
|
||||
type: "zha/entities",
|
||||
});
|
@ -72,6 +72,18 @@ function initPushNotifications() {
|
||||
var data;
|
||||
if (event.data) {
|
||||
data = event.data.json();
|
||||
if (data.dismiss) {
|
||||
event.waitUntil(
|
||||
self.registration
|
||||
.getNotifications({ tag: data.tag })
|
||||
.then(function(notifications) {
|
||||
for (const n of notifications) {
|
||||
n.close();
|
||||
}
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
event.waitUntil(
|
||||
self.registration
|
||||
.showNotification(data.title, data)
|
||||
@ -96,7 +108,11 @@ function initPushNotifications() {
|
||||
|
||||
event.notification.close();
|
||||
|
||||
if (!event.notification.data || !event.notification.data.url) {
|
||||
if (
|
||||
event.action ||
|
||||
!event.notification.data ||
|
||||
!event.notification.data.url
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PolymerElement } from "@polymer/polymer";
|
||||
import { Constructor } from "@polymer/lit-element";
|
||||
import { Constructor } from "lit-element";
|
||||
import { HASSDomEvent, ValidHassDomEvent } from "../../common/dom/fire_event";
|
||||
|
||||
interface RegisterDialogParams {
|
||||
|
@ -4,7 +4,7 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import { afterNextRender } from "@polymer/polymer/lib/utils/render-status";
|
||||
import { html as litHtml, LitElement } from "@polymer/lit-element";
|
||||
import { html as litHtml, LitElement } from "lit-element";
|
||||
|
||||
import "../home-assistant-main";
|
||||
import "../ha-init-page";
|
||||
@ -95,7 +95,11 @@ class HomeAssistant extends ext(PolymerElement, [
|
||||
}
|
||||
|
||||
computePanelUrl(routeData) {
|
||||
return (routeData && routeData.panel) || DEFAULT_PANEL;
|
||||
return (
|
||||
(routeData && routeData.panel) ||
|
||||
localStorage.defaultPage ||
|
||||
DEFAULT_PANEL
|
||||
);
|
||||
}
|
||||
|
||||
panelUrlChanged(newPanelUrl) {
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
} from "lit-element";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { getActiveTranslation } from "../util/hass-translation";
|
||||
import { LocalizeFunc, LocalizeMixin } from "./localize-base-mixin";
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
} from "lit-element";
|
||||
import { HomeAssistant } from "../types";
|
||||
import {
|
||||
localizeBaseMixin,
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
@ -23,7 +27,7 @@ export class CloudAlexaPref extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.cloudStatus) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -3,8 +3,8 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { repeat } from "lit-html/directives/repeat";
|
||||
import "@polymer/paper-tooltip/paper-tooltip";
|
||||
import { HassEntityBase } from "home-assistant-js-websocket";
|
||||
@ -34,7 +34,7 @@ export class CloudExposedEntities extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._filterFunc) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
@ -24,7 +28,7 @@ export class CloudGooglePref extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.cloudStatus) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
css,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
@ -10,10 +16,9 @@ import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog";
|
||||
// tslint:disable-next-line
|
||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
|
||||
import { buttonLink } from "../../../resources/ha-style";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { WebhookDialogParams } from "./types";
|
||||
import { haStyle } from "../../../resources/ha-style";
|
||||
|
||||
const inputLabel = "Public URL – Click to copy to clipboard";
|
||||
|
||||
@ -44,7 +49,6 @@ export class CloudWebhookManageDialog extends LitElement {
|
||||
? "https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger"
|
||||
: `https://www.home-assistant.io/components/${webhook.domain}/`;
|
||||
return html`
|
||||
${this._renderStyle()}
|
||||
<paper-dialog with-backdrop>
|
||||
<h2>Webhook for ${webhook.name}</h2>
|
||||
<div>
|
||||
@ -112,24 +116,25 @@ export class CloudWebhookManageDialog extends LitElement {
|
||||
this._paperInput.label = inputLabel;
|
||||
}
|
||||
|
||||
private _renderStyle() {
|
||||
return html`
|
||||
<style>
|
||||
static get styles(): CSSResult[] {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
paper-dialog {
|
||||
width: 650px;
|
||||
}
|
||||
paper-input {
|
||||
margin-top: -8px;
|
||||
}
|
||||
${buttonLink} button.link {
|
||||
button.link {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
paper-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-item/paper-item-body";
|
||||
|
52
src/panels/config/js/trigger/time_pattern.js
Normal file
52
src/panels/config/js/trigger/time_pattern.js
Normal file
@ -0,0 +1,52 @@
|
||||
import { h, Component } from "preact";
|
||||
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { onChangeEvent } from "../../../../common/preact/event";
|
||||
|
||||
export default class TimePatternTrigger extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.onChange = onChangeEvent.bind(this, "trigger");
|
||||
}
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
render({ trigger, localize }) {
|
||||
const { hours, minutes, seconds } = trigger;
|
||||
return (
|
||||
<div>
|
||||
<paper-input
|
||||
label={localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time_pattern.hours"
|
||||
)}
|
||||
name="hours"
|
||||
value={hours}
|
||||
onvalue-changed={this.onChange}
|
||||
/>
|
||||
<paper-input
|
||||
label={localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time_pattern.minutes"
|
||||
)}
|
||||
name="minutes"
|
||||
value={minutes}
|
||||
onvalue-changed={this.onChange}
|
||||
/>
|
||||
<paper-input
|
||||
label={localize(
|
||||
"ui.panel.config.automation.editor.triggers.type.time_pattern.seconds"
|
||||
)}
|
||||
name="seconds"
|
||||
value={seconds}
|
||||
onvalue-changed={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TimePatternTrigger.defaultConfig = {
|
||||
hours: "",
|
||||
minutes: "",
|
||||
seconds: "",
|
||||
};
|
@ -8,6 +8,7 @@ import EventTrigger from "./event";
|
||||
import HassTrigger from "./homeassistant";
|
||||
import MQTTTrigger from "./mqtt";
|
||||
import NumericStateTrigger from "./numeric_state";
|
||||
import TimePatternTrigger from "./time_pattern";
|
||||
import StateTrigger from "./state";
|
||||
import SunTrigger from "./sun";
|
||||
import TemplateTrigger from "./template";
|
||||
@ -24,6 +25,7 @@ const TYPES = {
|
||||
sun: SunTrigger,
|
||||
template: TemplateTrigger,
|
||||
time: TimeTrigger,
|
||||
time_pattern: TimePatternTrigger,
|
||||
webhook: WebhookTrigger,
|
||||
zone: ZoneTrigger,
|
||||
};
|
||||
|
@ -1,51 +1,119 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import "@polymer/app-layout/app-header/app-header";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import { Cluster } from "../../../data/zha";
|
||||
import "../../../layouts/ha-app-layout";
|
||||
import "../../../resources/ha-style";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import {
|
||||
ZHAClusterSelectedParams,
|
||||
ZHAEntitySelectedParams,
|
||||
ZHANodeSelectedParams,
|
||||
} from "./types";
|
||||
import "./zha-cluster-attributes";
|
||||
import "./zha-cluster-commands";
|
||||
import "./zha-network";
|
||||
import "./zha-node";
|
||||
|
||||
export class HaConfigZha extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
private _selectedNode?: HassEntity;
|
||||
private _selectedCluster?: Cluster;
|
||||
private _selectedEntity?: HassEntity;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_selectedCluster: {},
|
||||
_selectedEntity: {},
|
||||
_selectedNode: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-app-layout has-scrolling-region="">
|
||||
<app-header slot="header" fixed="">
|
||||
<ha-app-layout>
|
||||
<app-header slot="header">
|
||||
<app-toolbar>
|
||||
<paper-icon-button
|
||||
icon="hass:arrow-left"
|
||||
@click="${this._onBackTapped}"
|
||||
></paper-icon-button>
|
||||
<div main-title>Zigbee Home Automation</div>
|
||||
</app-toolbar>
|
||||
</app-header>
|
||||
|
||||
<zha-network
|
||||
id="zha-network"
|
||||
.is-wide="${this.isWide}"
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
></zha-network>
|
||||
|
||||
<zha-node
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
@zha-cluster-selected="${this._onClusterSelected}"
|
||||
@zha-node-selected="${this._onNodeSelected}"
|
||||
@zha-entity-selected="${this._onEntitySelected}"
|
||||
></zha-node>
|
||||
${
|
||||
this._selectedCluster
|
||||
? html`
|
||||
<zha-cluster-attributes
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
.selectedNode="${this._selectedNode}"
|
||||
.selectedEntity="${this._selectedEntity}"
|
||||
.selectedCluster="${this._selectedCluster}"
|
||||
></zha-cluster-attributes>
|
||||
|
||||
<zha-cluster-commands
|
||||
.isWide="${this.isWide}"
|
||||
.hass="${this.hass}"
|
||||
.selectedNode="${this._selectedNode}"
|
||||
.selectedEntity="${this._selectedEntity}"
|
||||
.selectedCluster="${this._selectedCluster}"
|
||||
></zha-cluster-commands>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</ha-app-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
private _onClusterSelected(
|
||||
selectedClusterEvent: HASSDomEvent<ZHAClusterSelectedParams>
|
||||
): void {
|
||||
this._selectedCluster = selectedClusterEvent.detail.cluster;
|
||||
}
|
||||
|
||||
private _onNodeSelected(
|
||||
selectedNodeEvent: HASSDomEvent<ZHANodeSelectedParams>
|
||||
): void {
|
||||
this._selectedNode = selectedNodeEvent.detail.node;
|
||||
this._selectedCluster = undefined;
|
||||
this._selectedEntity = undefined;
|
||||
}
|
||||
|
||||
private _onEntitySelected(
|
||||
selectedEntityEvent: HASSDomEvent<ZHAEntitySelectedParams>
|
||||
): void {
|
||||
this._selectedEntity = selectedEntityEvent.detail.entity;
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
|
50
src/panels/config/zha/types.ts
Normal file
50
src/panels/config/zha/types.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { ZHADeviceEntity, Cluster } from "../../../data/zha";
|
||||
|
||||
export interface PickerTarget extends EventTarget {
|
||||
selected: number;
|
||||
}
|
||||
|
||||
export interface ItemSelectedEvent {
|
||||
target?: PickerTarget;
|
||||
}
|
||||
|
||||
export interface ChangeEvent {
|
||||
detail?: {
|
||||
value?: any;
|
||||
};
|
||||
target?: EventTarget;
|
||||
}
|
||||
|
||||
export interface SetAttributeServiceData {
|
||||
entity_id: string;
|
||||
cluster_id: number;
|
||||
cluster_type: string;
|
||||
attribute: number;
|
||||
value: any;
|
||||
manufacturer: number;
|
||||
}
|
||||
|
||||
export interface IssueCommandServiceData {
|
||||
entity_id: string;
|
||||
cluster_id: number;
|
||||
cluster_type: string;
|
||||
command: number;
|
||||
command_type: string;
|
||||
}
|
||||
|
||||
export interface ZHAEntitySelectedParams {
|
||||
entity: HassEntity;
|
||||
}
|
||||
|
||||
export interface ZHANodeSelectedParams {
|
||||
node: ZHADeviceEntity;
|
||||
}
|
||||
|
||||
export interface ZHAClusterSelectedParams {
|
||||
cluster: Cluster;
|
||||
}
|
||||
|
||||
export interface NodeServiceData {
|
||||
ieee_address: string;
|
||||
}
|
329
src/panels/config/zha/zha-cluster-attributes.ts
Normal file
329
src/panels/config/zha/zha-cluster-attributes.ts
Normal file
@ -0,0 +1,329 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import {
|
||||
Attribute,
|
||||
Cluster,
|
||||
fetchAttributesForCluster,
|
||||
ReadAttributeServiceData,
|
||||
readAttributeValue,
|
||||
ZHADeviceEntity,
|
||||
} from "../../../data/zha";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import {
|
||||
ChangeEvent,
|
||||
ItemSelectedEvent,
|
||||
SetAttributeServiceData,
|
||||
} from "./types";
|
||||
|
||||
export class ZHAClusterAttributes extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
public showHelp: boolean;
|
||||
public selectedNode?: HassEntity;
|
||||
public selectedEntity?: ZHADeviceEntity;
|
||||
public selectedCluster?: Cluster;
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
private _attributes: Attribute[];
|
||||
private _selectedAttributeIndex: number;
|
||||
private _attributeValue?: any;
|
||||
private _manufacturerCodeOverride?: string | number;
|
||||
private _setAttributeServiceData?: SetAttributeServiceData;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showHelp = false;
|
||||
this._selectedAttributeIndex = -1;
|
||||
this._attributes = [];
|
||||
this._attributeValue = "";
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
showHelp: {},
|
||||
selectedNode: {},
|
||||
selectedEntity: {},
|
||||
selectedCluster: {},
|
||||
_attributes: {},
|
||||
_selectedAttributeIndex: {},
|
||||
_attributeValue: {},
|
||||
_manufacturerCodeOverride: {},
|
||||
_setAttributeServiceData: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("selectedCluster")) {
|
||||
this._attributes = [];
|
||||
this._selectedAttributeIndex = -1;
|
||||
this._attributeValue = "";
|
||||
this._fetchAttributesForCluster();
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div style="position: relative" slot="header">
|
||||
<span>Cluster Attributes</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
>
|
||||
</paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">View and edit cluster attributes.</span>
|
||||
|
||||
<paper-card class="content">
|
||||
<div class="attribute-picker">
|
||||
<paper-dropdown-menu
|
||||
label="Attributes of the selected cluster"
|
||||
class="flex"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedAttributeIndex}"
|
||||
@iron-select="${this._selectedAttributeChanged}"
|
||||
>
|
||||
${
|
||||
this._attributes.map(
|
||||
(entry) => html`
|
||||
<paper-item
|
||||
>${entry.name + " (id: " + entry.id + ")"}</paper-item
|
||||
>
|
||||
`
|
||||
)
|
||||
}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this.showHelp
|
||||
? html`
|
||||
<div style="color: grey; padding: 16px">
|
||||
Select an attribute to view or set its value
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
this._selectedAttributeIndex !== -1
|
||||
? this._renderAttributeInteractions()
|
||||
: ""
|
||||
}
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderAttributeInteractions(): TemplateResult {
|
||||
return html`
|
||||
<div class="input-text">
|
||||
<paper-input
|
||||
label="Value"
|
||||
type="string"
|
||||
.value="${this._attributeValue}"
|
||||
@value-changed="${this._onAttributeValueChanged}"
|
||||
placeholder="Value"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="input-text">
|
||||
<paper-input
|
||||
label="Manufacturer code override"
|
||||
type="number"
|
||||
.value="${this._manufacturerCodeOverride}"
|
||||
@value-changed="${this._onManufacturerCodeOverrideChanged}"
|
||||
placeholder="Value"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<paper-button @click="${this._onGetZigbeeAttributeClick}"
|
||||
>Get Zigbee Attribute</paper-button
|
||||
>
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="set_zigbee_cluster_attribute"
|
||||
.serviceData="${this._setAttributeServiceData}"
|
||||
>Set Zigbee Attribute</ha-call-service-button
|
||||
>
|
||||
${
|
||||
this.showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="set_zigbee_cluster_attribute"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchAttributesForCluster(): Promise<void> {
|
||||
if (this.selectedEntity && this.selectedCluster && this.hass) {
|
||||
this._attributes = await fetchAttributesForCluster(
|
||||
this.hass,
|
||||
this.selectedEntity!.entity_id,
|
||||
this.selectedEntity!.device_info!.identifiers[0][1],
|
||||
this.selectedCluster!.id,
|
||||
this.selectedCluster!.type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _computeReadAttributeServiceData():
|
||||
| ReadAttributeServiceData
|
||||
| undefined {
|
||||
if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
entity_id: this.selectedEntity!.entity_id,
|
||||
cluster_id: this.selectedCluster!.id,
|
||||
cluster_type: this.selectedCluster!.type,
|
||||
attribute: this._attributes[this._selectedAttributeIndex].id,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.attributes.manufacturer_code,
|
||||
};
|
||||
}
|
||||
|
||||
private _computeSetAttributeServiceData():
|
||||
| SetAttributeServiceData
|
||||
| undefined {
|
||||
if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
entity_id: this.selectedEntity!.entity_id,
|
||||
cluster_id: this.selectedCluster!.id,
|
||||
cluster_type: this.selectedCluster!.type,
|
||||
attribute: this._attributes[this._selectedAttributeIndex].id,
|
||||
value: this._attributeValue,
|
||||
manufacturer: this._manufacturerCodeOverride
|
||||
? parseInt(this._manufacturerCodeOverride as string, 10)
|
||||
: this.selectedNode!.attributes.manufacturer_code,
|
||||
};
|
||||
}
|
||||
|
||||
private _onAttributeValueChanged(value: ChangeEvent): void {
|
||||
this._attributeValue = value.detail!.value;
|
||||
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
||||
}
|
||||
|
||||
private _onManufacturerCodeOverrideChanged(value: ChangeEvent): void {
|
||||
this._manufacturerCodeOverride = value.detail!.value;
|
||||
this._setAttributeServiceData = this._computeSetAttributeServiceData();
|
||||
}
|
||||
|
||||
private async _onGetZigbeeAttributeClick(): Promise<void> {
|
||||
const data = this._computeReadAttributeServiceData();
|
||||
if (data && this.hass) {
|
||||
this._attributeValue = await readAttributeValue(this.hass, data);
|
||||
}
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this.showHelp = !this.showHelp;
|
||||
}
|
||||
|
||||
private _selectedAttributeChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedAttributeIndex = event.target!.selected;
|
||||
this._attributeValue = "";
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
(document.getElementById("ha-style")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!this._ironFlex) {
|
||||
this._ironFlex = document.importNode(
|
||||
(document.getElementById("iron-flex")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
return html`
|
||||
${this._ironFlex} ${this._haStyle}
|
||||
<style>
|
||||
.content {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
paper-card {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.card-actions.warning ha-call-service-button {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
|
||||
.attribute-picker {
|
||||
@apply --layout-horizontal;
|
||||
@apply --layout-center-center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.input-text {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
ha-service-description {
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-cluster-attributes": ZHAClusterAttributes;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-cluster-attributes", ZHAClusterAttributes);
|
282
src/panels/config/zha/zha-cluster-commands.ts
Normal file
282
src/panels/config/zha/zha-cluster-commands.ts
Normal file
@ -0,0 +1,282 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import {
|
||||
Cluster,
|
||||
Command,
|
||||
fetchCommandsForCluster,
|
||||
ZHADeviceEntity,
|
||||
} from "../../../data/zha";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import {
|
||||
ChangeEvent,
|
||||
IssueCommandServiceData,
|
||||
ItemSelectedEvent,
|
||||
} from "./types";
|
||||
|
||||
export class ZHAClusterCommands extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
public selectedNode?: HassEntity;
|
||||
public selectedEntity?: ZHADeviceEntity;
|
||||
public selectedCluster?: Cluster;
|
||||
private _showHelp: boolean;
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
private _commands: Command[];
|
||||
private _selectedCommandIndex: number;
|
||||
private _manufacturerCodeOverride?: number;
|
||||
private _issueClusterCommandServiceData?: IssueCommandServiceData;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._showHelp = false;
|
||||
this._selectedCommandIndex = -1;
|
||||
this._commands = [];
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
selectedNode: {},
|
||||
selectedEntity: {},
|
||||
selectedCluster: {},
|
||||
_showHelp: {},
|
||||
_commands: {},
|
||||
_selectedCommandIndex: {},
|
||||
_manufacturerCodeOverride: {},
|
||||
_issueClusterCommandServiceData: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("selectedCluster")) {
|
||||
this._commands = [];
|
||||
this._selectedCommandIndex = -1;
|
||||
this._fetchCommandsForCluster();
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div class="sectionHeader" slot="header">
|
||||
<span>Cluster Commands</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
>
|
||||
</paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">View and issue cluster commands.</span>
|
||||
|
||||
<paper-card class="content">
|
||||
<div class="command-picker">
|
||||
<paper-dropdown-menu
|
||||
label="Commands of the selected cluster"
|
||||
class="flex"
|
||||
>
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedCommandIndex}"
|
||||
@iron-select="${this._selectedCommandChanged}"
|
||||
>
|
||||
${
|
||||
this._commands.map(
|
||||
(entry) => html`
|
||||
<paper-item
|
||||
>${entry.name + " (id: " + entry.id + ")"}</paper-item
|
||||
>
|
||||
`
|
||||
)
|
||||
}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<div class="helpText">Select a command to interact with</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
this._selectedCommandIndex !== -1
|
||||
? html`
|
||||
<div class="input-text">
|
||||
<paper-input
|
||||
label="Manufacturer code override"
|
||||
type="number"
|
||||
.value="${this._manufacturerCodeOverride}"
|
||||
@value-changed="${
|
||||
this._onManufacturerCodeOverrideChanged
|
||||
}"
|
||||
placeholder="Value"
|
||||
></paper-input>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="issue_zigbee_cluster_command"
|
||||
.serviceData="${this._issueClusterCommandServiceData}"
|
||||
>Issue Zigbee Command</ha-call-service-button
|
||||
>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="issue_zigbee_cluster_command"
|
||||
></ha-service-description>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchCommandsForCluster(): Promise<void> {
|
||||
if (this.selectedEntity && this.selectedCluster && this.hass) {
|
||||
this._commands = await fetchCommandsForCluster(
|
||||
this.hass,
|
||||
this.selectedEntity!.entity_id,
|
||||
this.selectedEntity!.device_info!.identifiers[0][1],
|
||||
this.selectedCluster!.id,
|
||||
this.selectedCluster!.type
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _computeIssueClusterCommandServiceData():
|
||||
| IssueCommandServiceData
|
||||
| undefined {
|
||||
if (!this.selectedEntity || !this.selectedCluster) {
|
||||
return;
|
||||
}
|
||||
return {
|
||||
entity_id: this.selectedEntity!.entity_id,
|
||||
cluster_id: this.selectedCluster!.id,
|
||||
cluster_type: this.selectedCluster!.type,
|
||||
command: this._commands[this._selectedCommandIndex].id,
|
||||
command_type: this._commands[this._selectedCommandIndex].type,
|
||||
};
|
||||
}
|
||||
|
||||
private _onManufacturerCodeOverrideChanged(value: ChangeEvent): void {
|
||||
this._manufacturerCodeOverride = value.detail!.value;
|
||||
this._issueClusterCommandServiceData = this._computeIssueClusterCommandServiceData();
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _selectedCommandChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedCommandIndex = event.target!.selected;
|
||||
this._issueClusterCommandServiceData = this._computeIssueClusterCommandServiceData();
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
(document.getElementById("ha-style")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!this._ironFlex) {
|
||||
this._ironFlex = document.importNode(
|
||||
(document.getElementById("iron-flex")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
return html`
|
||||
${this._ironFlex} ${this._haStyle}
|
||||
<style>
|
||||
.content {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
paper-card {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.card-actions.warning ha-call-service-button {
|
||||
color: var(--google-red-500);
|
||||
}
|
||||
|
||||
.command-picker {
|
||||
@apply --layout-horizontal;
|
||||
@apply --layout-center-center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.input-text {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
ha-service-description {
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-cluster-commands": ZHAClusterCommands;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-cluster-commands", ZHAClusterCommands);
|
165
src/panels/config/zha/zha-clusters.ts
Normal file
165
src/panels/config/zha/zha-clusters.ts
Normal file
@ -0,0 +1,165 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import {
|
||||
Cluster,
|
||||
fetchClustersForZhaNode,
|
||||
ZHADeviceEntity,
|
||||
} from "../../../data/zha";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-cluster-selected": {
|
||||
cluster?: Cluster;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const computeClusterKey = (cluster: Cluster): string => {
|
||||
return `${cluster.name} (id: ${cluster.id}, type: ${cluster.type})`;
|
||||
};
|
||||
|
||||
export class ZHAClusters extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
public showHelp: boolean;
|
||||
public selectedEntity?: ZHADeviceEntity;
|
||||
private _selectedClusterIndex: number;
|
||||
private _clusters: Cluster[];
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showHelp = false;
|
||||
this._selectedClusterIndex = -1;
|
||||
this._clusters = [];
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
showHelp: {},
|
||||
selectedEntity: {},
|
||||
_selectedClusterIndex: {},
|
||||
_clusters: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("selectedEntity")) {
|
||||
this._clusters = [];
|
||||
this._selectedClusterIndex = -1;
|
||||
fireEvent(this, "zha-cluster-selected", {
|
||||
cluster: undefined,
|
||||
});
|
||||
this._fetchClustersForZhaNode();
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this._renderStyle()}
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu label="Clusters" class="flex">
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedClusterIndex}"
|
||||
@iron-select="${this._selectedClusterChanged}"
|
||||
>
|
||||
${
|
||||
this._clusters.map(
|
||||
(entry) => html`
|
||||
<paper-item>${computeClusterKey(entry)}</paper-item>
|
||||
`
|
||||
)
|
||||
}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this.showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
Select cluster to view attributes and commands
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchClustersForZhaNode(): Promise<void> {
|
||||
if (this.hass) {
|
||||
this._clusters = await fetchClustersForZhaNode(
|
||||
this.hass,
|
||||
this.selectedEntity!.entity_id,
|
||||
this.selectedEntity!.device_info!.identifiers[0][1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _selectedClusterChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedClusterIndex = event.target!.selected;
|
||||
fireEvent(this, "zha-cluster-selected", {
|
||||
cluster: this._clusters[this._selectedClusterIndex],
|
||||
});
|
||||
}
|
||||
|
||||
private _renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
(document.getElementById("ha-style")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!this._ironFlex) {
|
||||
this._ironFlex = document.importNode(
|
||||
(document.getElementById("iron-flex")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
return html`
|
||||
${this._ironFlex} ${this._haStyle}
|
||||
<style>
|
||||
.node-picker {
|
||||
@apply --layout-horizontal;
|
||||
@apply --layout-center-center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-cluster": ZHAClusters;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-clusters", ZHAClusters);
|
177
src/panels/config/zha/zha-entities.ts
Normal file
177
src/panels/config/zha/zha-entities.ts
Normal file
@ -0,0 +1,177 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { fetchEntitiesForZhaNode } from "../../../data/zha";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { ItemSelectedEvent } from "./types";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-entity-selected": {
|
||||
entity?: HassEntity;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ZHAEntities extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public showHelp?: boolean;
|
||||
public selectedNode?: HassEntity;
|
||||
private _selectedEntityIndex: number;
|
||||
private _entities: HassEntity[];
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._entities = [];
|
||||
this._selectedEntityIndex = -1;
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
showHelp: {},
|
||||
selectedNode: {},
|
||||
_selectedEntityIndex: {},
|
||||
_entities: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("selectedNode")) {
|
||||
this._entities = [];
|
||||
this._selectedEntityIndex = -1;
|
||||
fireEvent(this, "zha-entity-selected", {
|
||||
entity: undefined,
|
||||
});
|
||||
this._fetchEntitiesForZhaNode();
|
||||
}
|
||||
super.update(changedProperties);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this._renderStyle()}
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu label="Entities" class="flex">
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
.selected="${this._selectedEntityIndex}"
|
||||
@iron-select="${this._selectedEntityChanged}"
|
||||
>
|
||||
${
|
||||
this._entities.map(
|
||||
(entry) => html`
|
||||
<paper-item>${entry.entity_id}</paper-item>
|
||||
`
|
||||
)
|
||||
}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this.showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
Select entity to view per-entity options
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
this._selectedEntityIndex !== -1
|
||||
? html`
|
||||
<div class="actions">
|
||||
<paper-button @click="${this._showEntityInformation}"
|
||||
>Entity Information</paper-button
|
||||
>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private async _fetchEntitiesForZhaNode(): Promise<void> {
|
||||
if (this.hass) {
|
||||
const fetchedEntities = await fetchEntitiesForZhaNode(this.hass);
|
||||
this._entities = fetchedEntities[this.selectedNode!.attributes.ieee];
|
||||
}
|
||||
}
|
||||
|
||||
private _selectedEntityChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedEntityIndex = event.target!.selected;
|
||||
fireEvent(this, "zha-entity-selected", {
|
||||
entity: this._entities[this._selectedEntityIndex],
|
||||
});
|
||||
}
|
||||
|
||||
private _showEntityInformation(): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: this._entities[this._selectedEntityIndex].entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
(document.getElementById("ha-style")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!this._ironFlex) {
|
||||
this._ironFlex = document.importNode(
|
||||
(document.getElementById("iron-flex")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
return html`
|
||||
${this._ironFlex} ${this._haStyle}
|
||||
<style>
|
||||
.node-picker {
|
||||
@apply --layout-horizontal;
|
||||
@apply --layout-center-center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.actions {
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 5px 16px;
|
||||
position: relative;
|
||||
}
|
||||
.actions paper-button:not([disabled]) {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
}
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-entities": ZHAEntities;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-entities", ZHAEntities);
|
@ -1,42 +1,45 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../ha-config-section";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
|
||||
export class ZHANetwork extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
public showDescription: boolean;
|
||||
private _showHelp: boolean;
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.showDescription = false;
|
||||
this._showHelp = false;
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
showDescription: {},
|
||||
_showHelp: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-config-section .is-wide="${this.isWide}">
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div style="position: relative" slot="header">
|
||||
<span>Zigbee Home Automation network management</span>
|
||||
<span>Network Management</span>
|
||||
<paper-icon-button class="toggle-help-icon" @click="${
|
||||
this._onHelpTap
|
||||
}" icon="hass:help-circle"></paper-icon-button>
|
||||
@ -49,7 +52,7 @@ export class ZHANetwork extends LitElement {
|
||||
this.hass
|
||||
}" domain="zha" service="permit">Permit</ha-call-service-button>
|
||||
${
|
||||
this.showDescription
|
||||
this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
@ -65,7 +68,7 @@ export class ZHANetwork extends LitElement {
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this.showDescription = !this.showDescription;
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
|
325
src/panels/config/zha/zha-node.ts
Normal file
325
src/panels/config/zha/zha-node.ts
Normal file
@ -0,0 +1,325 @@
|
||||
import "@polymer/iron-flex-layout/iron-flex-layout-classes";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-card/paper-card";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import sortByName from "../../../common/entity/states_sort_by_name";
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
import "../../../components/ha-service-description";
|
||||
import "../../../resources/ha-style";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import "../ha-config-section";
|
||||
import {
|
||||
ItemSelectedEvent,
|
||||
NodeServiceData,
|
||||
ZHAEntitySelectedParams,
|
||||
} from "./types";
|
||||
import "./zha-clusters";
|
||||
import "./zha-entities";
|
||||
import { reconfigureNode } from "../../../data/zha";
|
||||
|
||||
declare global {
|
||||
// for fire event
|
||||
interface HASSDomEvents {
|
||||
"zha-node-selected": {
|
||||
node?: HassEntity;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ZHANode extends LitElement {
|
||||
public hass?: HomeAssistant;
|
||||
public isWide?: boolean;
|
||||
private _showHelp: boolean;
|
||||
private _selectedNodeIndex: number;
|
||||
private _selectedNode?: HassEntity;
|
||||
private _selectedEntity?: HassEntity;
|
||||
private _serviceData?: {};
|
||||
private _haStyle?: DocumentFragment;
|
||||
private _ironFlex?: DocumentFragment;
|
||||
private _nodes: HassEntity[];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._showHelp = false;
|
||||
this._selectedNodeIndex = -1;
|
||||
this._nodes = [];
|
||||
}
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
hass: {},
|
||||
isWide: {},
|
||||
_showHelp: {},
|
||||
_selectedNodeIndex: {},
|
||||
_selectedNode: {},
|
||||
_serviceData: {},
|
||||
_selectedEntity: {},
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
this._nodes = this._computeNodes(this.hass);
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<ha-config-section .isWide="${this.isWide}">
|
||||
<div class="sectionHeader" slot="header">
|
||||
<span>Node Management</span>
|
||||
<paper-icon-button
|
||||
class="toggle-help-icon"
|
||||
@click="${this._onHelpTap}"
|
||||
icon="hass:help-circle"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
<span slot="introduction">
|
||||
Run ZHA commands that affect a single node. Pick a node to see a list
|
||||
of available commands. <br /><br />Note: Sleepy (battery powered)
|
||||
devices need to be awake when executing commands against them. You can
|
||||
generally wake a sleepy device by triggering it. <br /><br />Some
|
||||
devices such as Xiaomi sensors have a wake up button that you can
|
||||
press at ~5 second intervals that keep devices awake while you
|
||||
interact with them.
|
||||
</span>
|
||||
<paper-card class="content">
|
||||
<div class="node-picker">
|
||||
<paper-dropdown-menu label="Nodes" class="flex">
|
||||
<paper-listbox
|
||||
slot="dropdown-content"
|
||||
@iron-select="${this._selectedNodeChanged}"
|
||||
>
|
||||
${
|
||||
this._nodes.map(
|
||||
(entry) => html`
|
||||
<paper-item
|
||||
>${this._computeSelectCaption(entry)}</paper-item
|
||||
>
|
||||
`
|
||||
)
|
||||
}
|
||||
</paper-listbox>
|
||||
</paper-dropdown-menu>
|
||||
</div>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<div class="helpText">
|
||||
Select node to view per-node options
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
${this._selectedNodeIndex !== -1 ? this._renderNodeActions() : ""}
|
||||
${this._selectedNodeIndex !== -1 ? this._renderEntities() : ""}
|
||||
${this._selectedEntity ? this._renderClusters() : ""}
|
||||
</paper-card>
|
||||
</ha-config-section>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderNodeActions(): TemplateResult {
|
||||
return html`
|
||||
<div class="card-actions">
|
||||
<paper-button @click="${this._showNodeInformation}"
|
||||
>Node Information</paper-button
|
||||
>
|
||||
<paper-button @click="${this._onReconfigureNodeClick}"
|
||||
>Reconfigure Node</paper-button
|
||||
>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="reconfigure_device"
|
||||
/>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
<ha-call-service-button
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
.serviceData="${this._serviceData}"
|
||||
>Remove Node</ha-call-service-button
|
||||
>
|
||||
${
|
||||
this._showHelp
|
||||
? html`
|
||||
<ha-service-description
|
||||
.hass="${this.hass}"
|
||||
domain="zha"
|
||||
service="remove"
|
||||
/>
|
||||
`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderEntities(): TemplateResult {
|
||||
return html`
|
||||
<zha-entities
|
||||
.hass="${this.hass}"
|
||||
.selectedNode="${this._selectedNode}"
|
||||
.showHelp="${this._showHelp}"
|
||||
@zha-entity-selected="${this._onEntitySelected}"
|
||||
></zha-entities>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderClusters(): TemplateResult {
|
||||
return html`
|
||||
<zha-clusters
|
||||
.hass="${this.hass}"
|
||||
.selectedEntity="${this._selectedEntity}"
|
||||
.showHelp="${this._showHelp}"
|
||||
></zha-clusters>
|
||||
`;
|
||||
}
|
||||
|
||||
private _onHelpTap(): void {
|
||||
this._showHelp = !this._showHelp;
|
||||
}
|
||||
|
||||
private _selectedNodeChanged(event: ItemSelectedEvent): void {
|
||||
this._selectedNodeIndex = event!.target!.selected;
|
||||
this._selectedNode = this._nodes[this._selectedNodeIndex];
|
||||
this._selectedEntity = undefined;
|
||||
fireEvent(this, "zha-node-selected", { node: this._selectedNode });
|
||||
this._serviceData = this._computeNodeServiceData();
|
||||
}
|
||||
|
||||
private async _onReconfigureNodeClick(): Promise<void> {
|
||||
if (this.hass) {
|
||||
await reconfigureNode(this.hass, this._selectedNode!.attributes.ieee);
|
||||
}
|
||||
}
|
||||
|
||||
private _showNodeInformation(): void {
|
||||
fireEvent(this, "hass-more-info", {
|
||||
entityId: this._selectedNode!.entity_id,
|
||||
});
|
||||
}
|
||||
|
||||
private _computeNodeServiceData(): NodeServiceData {
|
||||
return {
|
||||
ieee_address: this._selectedNode!.attributes.ieee,
|
||||
};
|
||||
}
|
||||
|
||||
private _computeSelectCaption(stateObj: HassEntity): string {
|
||||
return (
|
||||
computeStateName(stateObj) + " (Node:" + stateObj.attributes.ieee + ")"
|
||||
);
|
||||
}
|
||||
|
||||
private _computeNodes(hass?: HomeAssistant): HassEntity[] {
|
||||
if (hass) {
|
||||
return Object.keys(hass.states)
|
||||
.map((key) => hass.states[key])
|
||||
.filter((ent) => ent.entity_id.match("zha[.]"))
|
||||
.sort(sortByName);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private _onEntitySelected(
|
||||
entitySelectedEvent: HASSDomEvent<ZHAEntitySelectedParams>
|
||||
): void {
|
||||
this._selectedEntity = entitySelectedEvent.detail.entity;
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
if (!this._haStyle) {
|
||||
this._haStyle = document.importNode(
|
||||
(document.getElementById("ha-style")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
if (!this._ironFlex) {
|
||||
this._ironFlex = document.importNode(
|
||||
(document.getElementById("iron-flex")!
|
||||
.children[0] as HTMLTemplateElement).content,
|
||||
true
|
||||
);
|
||||
}
|
||||
return html`
|
||||
${this._ironFlex} ${this._haStyle}
|
||||
<style>
|
||||
.content {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.node-info {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
}
|
||||
|
||||
.helpText {
|
||||
color: grey;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
paper-card {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.node-picker {
|
||||
@apply --layout-horizontal;
|
||||
@apply --layout-center-center;
|
||||
padding-left: 28px;
|
||||
padding-right: 28px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
ha-service-description {
|
||||
display: block;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-help-icon {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 0;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"zha-node": ZHANode;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("zha-node", ZHANode);
|
@ -20,7 +20,7 @@ import formatTime from "../../common/datetime/format_time";
|
||||
import EventsMixin from "../../mixins/events-mixin";
|
||||
import LocalizeMixin from "../../mixins/localize-mixin";
|
||||
|
||||
const OPT_IN_PANEL = "lovelace";
|
||||
const OPT_IN_PANEL = "states";
|
||||
let registeredDialog = false;
|
||||
|
||||
class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
@ -167,7 +167,7 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
</template>
|
||||
</p>
|
||||
<p>
|
||||
<a href='/lovelace'>Try out the new Lovelace UI</a>
|
||||
<a href="[[_nonDefaultLink()]]">[[_nonDefaultLinkText()]]</a>
|
||||
<div id="love" style="cursor:pointer;" on-click="_toggleDefaultPage">[[_defaultPageText()]]</div
|
||||
</p>
|
||||
</div>
|
||||
@ -366,6 +366,26 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
});
|
||||
}
|
||||
|
||||
_nonDefaultLink() {
|
||||
if (
|
||||
localStorage.defaultPage === OPT_IN_PANEL &&
|
||||
OPT_IN_PANEL === "states"
|
||||
) {
|
||||
return "/lovelace";
|
||||
}
|
||||
return "/states";
|
||||
}
|
||||
|
||||
_nonDefaultLinkText() {
|
||||
if (
|
||||
localStorage.defaultPage === OPT_IN_PANEL &&
|
||||
OPT_IN_PANEL === "states"
|
||||
) {
|
||||
return "Go to the Lovelace UI";
|
||||
}
|
||||
return "Go to the states UI";
|
||||
}
|
||||
|
||||
_defaultPageText() {
|
||||
return `>> ${
|
||||
localStorage.defaultPage === OPT_IN_PANEL ? "Remove" : "Set"
|
||||
|
@ -3,14 +3,17 @@ import {
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { callAlarmAction } from "../../../data/alarm_control_panel";
|
||||
import {
|
||||
callAlarmAction,
|
||||
FORMAT_NUMBER,
|
||||
} from "../../../data/alarm_control_panel";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
@ -97,7 +100,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement)
|
||||
return true;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
@ -150,7 +153,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement)
|
||||
`
|
||||
}
|
||||
${
|
||||
stateObj.attributes.code_format !== "Number"
|
||||
stateObj.attributes.code_format !== FORMAT_NUMBER
|
||||
? html``
|
||||
: html`
|
||||
<div id="keypad">
|
||||
@ -206,7 +209,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement)
|
||||
private _handleActionClick(e: MouseEvent): void {
|
||||
callAlarmAction(
|
||||
this.hass!,
|
||||
this._config!.entity_id,
|
||||
this._config!.entity,
|
||||
(e.currentTarget! as any).action,
|
||||
this._code!
|
||||
);
|
||||
|
@ -3,8 +3,8 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../components/hui-entities-toggle";
|
||||
@ -21,7 +21,7 @@ import { createRowElement } from "../common/create-row-element";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
import applyThemesOnElement from "../../../common/dom/apply_themes_on_element";
|
||||
|
||||
export interface ConfigEntity extends EntityConfig {
|
||||
export interface EntitiesCardEntityConfig extends EntityConfig {
|
||||
type?: string;
|
||||
secondary_info?: "entity-id" | "last-changed";
|
||||
action_name?: string;
|
||||
@ -30,10 +30,10 @@ export interface ConfigEntity extends EntityConfig {
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
export interface EntitiesCardConfig extends LovelaceCardConfig {
|
||||
show_header_toggle?: boolean;
|
||||
title?: string;
|
||||
entities: ConfigEntity[];
|
||||
entities: EntitiesCardEntityConfig[];
|
||||
theme?: string;
|
||||
}
|
||||
|
||||
@ -49,8 +49,8 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
|
||||
protected _hass?: HomeAssistant;
|
||||
protected _config?: Config;
|
||||
protected _configEntities?: ConfigEntity[];
|
||||
protected _config?: EntitiesCardConfig;
|
||||
protected _configEntities?: EntitiesCardEntityConfig[];
|
||||
|
||||
set hass(hass: HomeAssistant) {
|
||||
this._hass = hass;
|
||||
@ -81,7 +81,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
|
||||
return (this._config.title ? 1 : 0) + this._config.entities.length;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: EntitiesCardConfig): void {
|
||||
const entities = processConfigEntities(config.entities);
|
||||
|
||||
this._config = { theme: "default", ...config };
|
||||
@ -95,7 +95,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this._hass) {
|
||||
return html``;
|
||||
}
|
||||
@ -171,7 +171,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
|
||||
`;
|
||||
}
|
||||
|
||||
private renderEntity(entityConf: ConfigEntity): TemplateResult {
|
||||
private renderEntity(entityConf: EntitiesCardEntityConfig): TemplateResult {
|
||||
const element = createRowElement(entityConf);
|
||||
if (this._hass) {
|
||||
element.hass = this._hass;
|
||||
@ -189,7 +189,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement)
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleClick(entityConf: ConfigEntity): void {
|
||||
private _handleClick(entityConf: EntitiesCardEntityConfig): void {
|
||||
const entityId = entityConf.entity;
|
||||
fireEvent(this, "hass-more-info", { entityId });
|
||||
}
|
||||
|
@ -3,10 +3,10 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { HassEntity } from "home-assistant-js-websocket";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { styleMap } from "lit-html/directives/styleMap";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
|
||||
@ -82,7 +82,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement)
|
||||
return true;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
|
||||
interface Config extends LovelaceCardConfig {
|
||||
@ -40,7 +39,7 @@ export class HuiErrorCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { styleMap } from "lit-html/directives/styleMap";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
@ -56,6 +56,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _updated?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
@ -78,7 +79,12 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
this._config = { min: 0, max: 100, theme: "default", ...config };
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._setBaseUnit();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
@ -148,12 +154,8 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
(this.shadowRoot!.querySelector(
|
||||
"ha-card"
|
||||
)! as HTMLElement).style.setProperty(
|
||||
"--base-unit",
|
||||
this._computeBaseUnit()
|
||||
);
|
||||
this._updated = true;
|
||||
this._setBaseUnit();
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
@ -169,6 +171,19 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
}
|
||||
|
||||
private _setBaseUnit(): void {
|
||||
if (!this.isConnected || !this._updated) {
|
||||
return;
|
||||
}
|
||||
const baseUnit = this._computeBaseUnit();
|
||||
if (baseUnit === "0px") {
|
||||
return;
|
||||
}
|
||||
(this.shadowRoot!.querySelector(
|
||||
"ha-card"
|
||||
)! as HTMLElement).style.setProperty("--base-unit", baseUnit);
|
||||
}
|
||||
|
||||
private _computeSeverity(numberValue: number): string {
|
||||
const sections = this._config!.severity;
|
||||
|
||||
|
@ -3,9 +3,9 @@ import {
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
@ -114,7 +114,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement)
|
||||
return true;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, TemplateResult } from "lit-element";
|
||||
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import { HuiStackCard } from "./hui-stack-card";
|
||||
|
@ -1,11 +1,15 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { styleMap } from "lit-html/directives/styleMap";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
aspect_ratio?: string;
|
||||
@ -31,7 +35,13 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
public getCardSize(): number {
|
||||
return 1 + this.offsetHeight / 50;
|
||||
if (!this._config) {
|
||||
return 3;
|
||||
}
|
||||
const aspectRatio = this._config.aspect_ratio
|
||||
? Number(this._config.aspect_ratio.replace("%", ""))
|
||||
: 50;
|
||||
return 1 + aspectRatio / 25;
|
||||
}
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
@ -42,7 +52,7 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
@ -75,7 +85,6 @@ export class HuiIframeCard extends LitElement implements LovelaceCard {
|
||||
#root {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
padding-top: ${this._config!.aspect_ratio || "50%"};
|
||||
}
|
||||
iframe {
|
||||
position: absolute;
|
||||
|
@ -3,11 +3,11 @@ import {
|
||||
LitElement,
|
||||
PropertyValues,
|
||||
PropertyDeclarations,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { styleMap } from "lit-html/directives/styleMap";
|
||||
import { styleMap } from "lit-html/directives/style-map";
|
||||
import { HomeAssistant, LightEntity } from "../../../types";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
@ -82,7 +82,7 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = { theme: "default", ...config };
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -247,7 +247,10 @@ class HuiMapCard extends PolymerElement {
|
||||
const stateObj = this.hass.states[entityId];
|
||||
if (
|
||||
computeStateDomain(stateObj) === "geo_location" &&
|
||||
this._configGeoLocationSources.includes(stateObj.attributes.source)
|
||||
(this._configGeoLocationSources.includes(
|
||||
stateObj.attributes.source
|
||||
) ||
|
||||
this._configGeoLocationSources.includes("all"))
|
||||
) {
|
||||
allEntities.push(entityId);
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-markdown";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
export interface Config extends LovelaceCardConfig {
|
||||
content: string;
|
||||
@ -42,7 +46,7 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import { handleClick } from "../common/handle-click";
|
||||
import { longPress } from "../common/directives/long-press-directive";
|
||||
|
||||
@ -49,7 +53,7 @@ export class HuiPictureCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import { createHuiElement } from "../common/create-hui-element";
|
||||
|
||||
@ -55,7 +54,7 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html/lib/shady-render";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../components/hui-image";
|
||||
@ -65,7 +69,7 @@ class HuiPictureEntityCard extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = { show_name: true, show_state: true, ...config };
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
@ -83,7 +87,7 @@ class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
@ -192,7 +192,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
||||
return 3;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
import { repeat } from "lit-html/directives/repeat";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { PaperInputElement } from "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-checkbox/paper-checkbox";
|
||||
|
||||
@ -79,7 +78,7 @@ class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import { createCardElement } from "../common/create-card-element";
|
||||
|
||||
@ -12,10 +11,6 @@ interface Config extends LovelaceCardConfig {
|
||||
}
|
||||
|
||||
export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
protected _cards?: LovelaceCard[];
|
||||
private _config?: Config;
|
||||
private _hass?: HomeAssistant;
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_config: {},
|
||||
@ -33,6 +28,9 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
element.hass = this._hass;
|
||||
}
|
||||
}
|
||||
protected _cards?: LovelaceCard[];
|
||||
private _config?: Config;
|
||||
private _hass?: HomeAssistant;
|
||||
|
||||
public abstract getCardSize(): number;
|
||||
|
||||
@ -42,15 +40,12 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
this._config = config;
|
||||
this._cards = config.cards.map((card) => {
|
||||
const element = createCardElement(card) as LovelaceCard;
|
||||
if (this._hass) {
|
||||
element.hass = this._hass;
|
||||
}
|
||||
const element = this._createCardElement(card) as LovelaceCard;
|
||||
return element;
|
||||
});
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
@ -62,4 +57,31 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
|
||||
protected abstract renderStyle(): TemplateResult;
|
||||
|
||||
private _createCardElement(cardConfig: LovelaceCardConfig) {
|
||||
const element = createCardElement(cardConfig) as LovelaceCard;
|
||||
if (this._hass) {
|
||||
element.hass = this._hass;
|
||||
}
|
||||
element.addEventListener(
|
||||
"ll-rebuild",
|
||||
(ev) => {
|
||||
ev.stopPropagation();
|
||||
this._rebuildCard(element, cardConfig);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
return element;
|
||||
}
|
||||
|
||||
private _rebuildCard(
|
||||
cardElToReplace: LovelaceCard,
|
||||
config: LovelaceCardConfig
|
||||
): void {
|
||||
const newCardEl = this._createCardElement(config);
|
||||
cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace);
|
||||
this._cards = this._cards!.map((curCardEl) =>
|
||||
curCardEl === cardElToReplace ? newCardEl : curCardEl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,9 +3,9 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon";
|
||||
@ -51,18 +51,6 @@ export interface Config extends LovelaceCardConfig {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
function formatTemp(temps: string[]): string {
|
||||
return temps.filter(Boolean).join("-");
|
||||
}
|
||||
|
||||
function computeTemperatureStepSize(hass: HomeAssistant, config: Config) {
|
||||
const stateObj = hass.states[config.entity];
|
||||
if (stateObj.attributes.target_temp_step) {
|
||||
return stateObj.attributes.target_temp_step;
|
||||
}
|
||||
return hass.config.unit_system.temperature === UNIT_F ? 1 : 0.5;
|
||||
}
|
||||
|
||||
export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
implements LovelaceCard {
|
||||
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||
@ -79,6 +67,8 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
private _roundSliderStyle?: TemplateResult;
|
||||
private _jQuery?: any;
|
||||
private _broadCard?: boolean;
|
||||
private _loaded?: boolean;
|
||||
private _updated?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
@ -101,7 +91,14 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = { theme: "default", ...config };
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
if (this._updated && !this._loaded) {
|
||||
this._initialLoad();
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this._config) {
|
||||
return html``;
|
||||
}
|
||||
@ -157,7 +154,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
this._initialLoad();
|
||||
this._updated = true;
|
||||
if (this.isConnected && !this._loaded) {
|
||||
this._initialLoad();
|
||||
}
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues): void {
|
||||
@ -189,13 +189,23 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
}
|
||||
|
||||
private get _stepSize(): number {
|
||||
const stateObj = this.hass!.states[this._config!.entity];
|
||||
if (stateObj.attributes.target_temp_step) {
|
||||
return stateObj.attributes.target_temp_step;
|
||||
}
|
||||
return this.hass!.config.unit_system.temperature === UNIT_F ? 1 : 0.5;
|
||||
}
|
||||
|
||||
private async _initialLoad(): Promise<void> {
|
||||
const radius = this.clientWidth / 3;
|
||||
this._loaded = true;
|
||||
|
||||
const radius = this.clientWidth / 3.2;
|
||||
this._broadCard = this.clientWidth > 390;
|
||||
|
||||
(this.shadowRoot!.querySelector(
|
||||
"#thermostat"
|
||||
)! as HTMLElement).style.minHeight = radius * 2 + "px";
|
||||
)! as HTMLElement).style.height = radius * 2 + "px";
|
||||
|
||||
const loaded = await loadRoundslider();
|
||||
await new Promise((resolve) => afterNextRender(resolve));
|
||||
@ -212,7 +222,6 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
: "min-range";
|
||||
|
||||
const [sliderValue, uiValue] = this._genSliderValue(stateObj);
|
||||
const step = computeTemperatureStepSize(this.hass!, this._config!);
|
||||
|
||||
this._jQuery("#thermostat", this.shadowRoot).roundSlider({
|
||||
...thermostatConfig,
|
||||
@ -220,11 +229,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
min: stateObj.attributes.min_temp,
|
||||
max: stateObj.attributes.max_temp,
|
||||
sliderType: _sliderType,
|
||||
create: () => this._loaded(),
|
||||
change: (value) => this._setTemperature(value),
|
||||
drag: (value) => this._dragEvent(value),
|
||||
value: sliderValue,
|
||||
step,
|
||||
step: this._stepSize,
|
||||
});
|
||||
this._updateSetTemp(uiValue);
|
||||
}
|
||||
@ -240,10 +248,13 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
sliderValue = `${stateObj.attributes.target_temp_low}, ${
|
||||
stateObj.attributes.target_temp_high
|
||||
}`;
|
||||
uiValue = formatTemp([
|
||||
String(stateObj.attributes.target_temp_low),
|
||||
String(stateObj.attributes.target_temp_high),
|
||||
]);
|
||||
uiValue = this.formatTemp(
|
||||
[
|
||||
String(stateObj.attributes.target_temp_low),
|
||||
String(stateObj.attributes.target_temp_high),
|
||||
],
|
||||
false
|
||||
);
|
||||
} else {
|
||||
sliderValue = stateObj.attributes.temperature;
|
||||
uiValue = "" + stateObj.attributes.temperature;
|
||||
@ -252,18 +263,12 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
return [sliderValue, uiValue];
|
||||
}
|
||||
|
||||
private _loaded(): void {
|
||||
(this.shadowRoot!.querySelector(
|
||||
"#thermostat"
|
||||
)! as HTMLElement).style.minHeight = null;
|
||||
}
|
||||
|
||||
private _updateSetTemp(value: string): void {
|
||||
this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = value;
|
||||
}
|
||||
|
||||
private _dragEvent(e): void {
|
||||
this._updateSetTemp(formatTemp(String(e.value).split(",")));
|
||||
this._updateSetTemp(this.formatTemp(String(e.value).split(","), true));
|
||||
}
|
||||
|
||||
private _setTemperature(e): void {
|
||||
@ -314,6 +319,21 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
});
|
||||
}
|
||||
|
||||
private formatTemp(temps: string[], spaceStepSize: boolean): string {
|
||||
temps = temps.filter(Boolean);
|
||||
|
||||
// If we are sliding the slider, append 0 to the temperatures if we're
|
||||
// having a 0.5 step size, so that the text doesn't jump while sliding
|
||||
if (spaceStepSize) {
|
||||
const stepSize = this._stepSize;
|
||||
temps = temps.map((val) =>
|
||||
val.includes(".") || stepSize === 1 ? val : `${val}.0`
|
||||
);
|
||||
}
|
||||
|
||||
return temps.join("-");
|
||||
}
|
||||
|
||||
private renderStyle(): TemplateResult {
|
||||
return html`
|
||||
${this._roundSliderStyle}
|
||||
@ -370,39 +390,37 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
--mode-color: var(--unknown-color);
|
||||
}
|
||||
.no-title {
|
||||
--title-margin-top: 33% !important;
|
||||
--title-position-top: 33% !important;
|
||||
}
|
||||
.large {
|
||||
--thermostat-padding-top: 25px;
|
||||
--thermostat-margin-bottom: 25px;
|
||||
--title-font-size: 28px;
|
||||
--title-margin-top: 20%;
|
||||
--climate-info-margin-top: 17%;
|
||||
--modes-margin-top: 2%;
|
||||
--title-position-top: 27%;
|
||||
--climate-info-position-top: 81%;
|
||||
--set-temperature-font-size: 25px;
|
||||
--current-temperature-font-size: 71px;
|
||||
--current-temperature-margin-top: 10%;
|
||||
--current-temperature-position-top: 10%;
|
||||
--current-temperature-text-padding-left: 15px;
|
||||
--uom-font-size: 20px;
|
||||
--uom-margin-left: -18px;
|
||||
--current-mode-font-size: 18px;
|
||||
--set-temperature-padding-bottom: 5px;
|
||||
--set-temperature-margin-bottom: -5px;
|
||||
}
|
||||
.small {
|
||||
--thermostat-padding-top: 15px;
|
||||
--thermostat-margin-bottom: 15px;
|
||||
--title-font-size: 18px;
|
||||
--title-margin-top: 20%;
|
||||
--climate-info-margin-top: 7.5%;
|
||||
--modes-margin-top: 1%;
|
||||
--title-position-top: 28%;
|
||||
--climate-info-position-top: 79%;
|
||||
--set-temperature-font-size: 16px;
|
||||
--current-temperature-font-size: 25px;
|
||||
--current-temperature-margin-top: 5%;
|
||||
--current-temperature-position-top: 5%;
|
||||
--current-temperature-text-padding-left: 7px;
|
||||
--uom-font-size: 12px;
|
||||
--uom-margin-left: -5px;
|
||||
--current-mode-font-size: 14px;
|
||||
--set-temperature-padding-bottom: 0px;
|
||||
--set-temperature-margin-bottom: 0px;
|
||||
}
|
||||
#thermostat {
|
||||
margin: 0 auto var(--thermostat-margin-bottom);
|
||||
@ -449,21 +467,28 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
#set-temperature {
|
||||
font-size: var(--set-temperature-font-size);
|
||||
padding-bottom: var(--set-temperature-padding-bottom);
|
||||
margin-bottom: var(--set-temperature-margin-bottom);
|
||||
}
|
||||
.title {
|
||||
font-size: var(--title-font-size);
|
||||
margin-top: var(--title-margin-top);
|
||||
position: absolute;
|
||||
top: var(--title-position-top);
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.climate-info {
|
||||
margin-top: var(--climate-info-margin-top);
|
||||
position: absolute;
|
||||
top: var(--climate-info-position-top);
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 100%;
|
||||
}
|
||||
.current-mode {
|
||||
font-size: var(--current-mode-font-size);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.modes {
|
||||
margin-top: var(--modes-margin-top);
|
||||
margin-top: 16px;
|
||||
}
|
||||
.modes ha-icon {
|
||||
color: var(--disabled-text-color);
|
||||
@ -475,7 +500,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
color: var(--mode-color);
|
||||
}
|
||||
.current-temperature {
|
||||
margin-top: var(--current-temperature-margin-top);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: var(--current-temperature-font-size);
|
||||
}
|
||||
.current-temperature-text {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { html } from "@polymer/lit-element";
|
||||
import { html, TemplateResult } from "lit-element";
|
||||
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import { HuiStackCard } from "./hui-stack-card";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
class HuiVerticalStackCard extends HuiStackCard {
|
||||
public getCardSize() {
|
||||
|
@ -106,7 +106,7 @@ export const createCardElement = (
|
||||
|
||||
customElements.whenDefined(tag).then(() => {
|
||||
clearTimeout(timer);
|
||||
fireEvent(element, "rebuild-view");
|
||||
fireEvent(element, "ll-rebuild");
|
||||
});
|
||||
|
||||
return element;
|
||||
|
@ -72,7 +72,7 @@ export const createHuiElement = (
|
||||
|
||||
customElements.whenDefined(tag).then(() => {
|
||||
clearTimeout(timer);
|
||||
fireEvent(element, "rebuild-view");
|
||||
fireEvent(element, "ll-rebuild");
|
||||
});
|
||||
|
||||
return element;
|
||||
|
@ -52,6 +52,9 @@ const DOMAIN_TO_ELEMENT_TYPE = {
|
||||
timer: "timer",
|
||||
switch: "toggle",
|
||||
vacuum: "toggle",
|
||||
// Temporary. Once climate is rewritten,
|
||||
// water heater should get it's own row.
|
||||
water_heater: "climate",
|
||||
};
|
||||
const TIMEOUT = 2000;
|
||||
|
||||
@ -115,7 +118,7 @@ export const createRowElement = (
|
||||
|
||||
customElements.whenDefined(tag).then(() => {
|
||||
clearTimeout(timer);
|
||||
fireEvent(element, "rebuild-view");
|
||||
fireEvent(element, "ll-rebuild");
|
||||
});
|
||||
|
||||
return element;
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { directive, PropertyPart } from "lit-html";
|
||||
import "@material/mwc-ripple";
|
||||
// See https://github.com/home-assistant/home-assistant-polymer/pull/2457
|
||||
// on how to undo mwc -> paper migration
|
||||
// import "@material/mwc-ripple";
|
||||
import "@polymer/paper-ripple";
|
||||
|
||||
const isTouch =
|
||||
"ontouchstart" in window ||
|
||||
@ -25,7 +28,7 @@ class LongPress extends HTMLElement implements LongPress {
|
||||
constructor() {
|
||||
super();
|
||||
this.holdTime = 500;
|
||||
this.ripple = document.createElement("mwc-ripple");
|
||||
this.ripple = document.createElement("paper-ripple");
|
||||
this.timer = undefined;
|
||||
this.held = false;
|
||||
this.cooldownStart = false;
|
||||
@ -34,6 +37,7 @@ class LongPress extends HTMLElement implements LongPress {
|
||||
|
||||
public connectedCallback() {
|
||||
Object.assign(this.style, {
|
||||
borderRadius: "50%", // paper-ripple
|
||||
position: "absolute",
|
||||
width: isTouch ? "100px" : "50px",
|
||||
height: isTouch ? "100px" : "50px",
|
||||
@ -42,7 +46,9 @@ class LongPress extends HTMLElement implements LongPress {
|
||||
});
|
||||
|
||||
this.appendChild(this.ripple);
|
||||
this.ripple.primary = true;
|
||||
this.ripple.style.color = "#03a9f4"; // paper-ripple
|
||||
this.ripple.style.color = "var(--primary-color)"; // paper-ripple
|
||||
// this.ripple.primary = true;
|
||||
|
||||
[
|
||||
"touchcancel",
|
||||
@ -140,14 +146,17 @@ class LongPress extends HTMLElement implements LongPress {
|
||||
top: `${y}px`,
|
||||
display: null,
|
||||
});
|
||||
this.ripple.disabled = false;
|
||||
this.ripple.active = true;
|
||||
this.ripple.unbounded = true;
|
||||
this.ripple.holdDown = true; // paper-ripple
|
||||
this.ripple.simulatedRipple(); // paper-ripple
|
||||
// this.ripple.disabled = false;
|
||||
// this.ripple.active = true;
|
||||
// this.ripple.unbounded = true;
|
||||
}
|
||||
|
||||
private stopAnimation() {
|
||||
this.ripple.active = false;
|
||||
this.ripple.disabled = true;
|
||||
this.ripple.holdDown = false; // paper-ripple
|
||||
// this.ripple.active = false;
|
||||
// this.ripple.disabled = true;
|
||||
this.style.display = "none";
|
||||
}
|
||||
}
|
||||
@ -174,7 +183,6 @@ export const longPressBind = (element: LongPressElement) => {
|
||||
longpress.bind(element);
|
||||
};
|
||||
|
||||
export const longPress = () =>
|
||||
directive((part: PropertyPart) => {
|
||||
longPressBind(part.committer.element);
|
||||
});
|
||||
export const longPress = directive(() => (part: PropertyPart) => {
|
||||
longPressBind(part.committer.element);
|
||||
});
|
||||
|
@ -14,6 +14,7 @@ import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||
import { LocalizeFunc } from "../../../mixins/localize-base-mixin";
|
||||
import computeDomain from "../../../common/entity/compute_domain";
|
||||
import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types";
|
||||
import { EntitiesCardConfig } from "../cards/hui-entities-card";
|
||||
|
||||
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||
const DOMAINS_BADGES = [
|
||||
@ -24,11 +25,15 @@ const DOMAINS_BADGES = [
|
||||
"sun",
|
||||
"timer",
|
||||
];
|
||||
const HIDE_DOMAIN = new Set(["persistent_notification", "configurator"]);
|
||||
const HIDE_DOMAIN = new Set([
|
||||
"persistent_notification",
|
||||
"configurator",
|
||||
"geo_location",
|
||||
]);
|
||||
|
||||
const computeCards = (
|
||||
title: string,
|
||||
states: Array<[string, HassEntity]>
|
||||
states: Array<[string, HassEntity]>,
|
||||
entityCardOptions: Partial<EntitiesCardConfig>
|
||||
): LovelaceCardConfig[] => {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
|
||||
@ -68,7 +73,7 @@ const computeCards = (
|
||||
type: "weather-forecast",
|
||||
entity: entityId,
|
||||
});
|
||||
} else if (domain === "weblink") {
|
||||
} else if (domain === "weblink" && stateObj) {
|
||||
const conf: WeblinkConfig = {
|
||||
type: "weblink",
|
||||
url: stateObj.state,
|
||||
@ -85,9 +90,9 @@ const computeCards = (
|
||||
|
||||
if (entities.length > 0) {
|
||||
cards.unshift({
|
||||
title,
|
||||
type: "entities",
|
||||
entities,
|
||||
...entityCardOptions,
|
||||
});
|
||||
}
|
||||
|
||||
@ -152,10 +157,13 @@ const generateViewConfig = (
|
||||
splitted.groups.forEach((groupEntity) => {
|
||||
cards = cards.concat(
|
||||
computeCards(
|
||||
computeStateName(groupEntity),
|
||||
groupEntity.attributes.entity_id.map(
|
||||
(entityId): [string, HassEntity] => [entityId, entities[entityId]]
|
||||
)
|
||||
),
|
||||
{
|
||||
title: computeStateName(groupEntity),
|
||||
show_header_toggle: groupEntity.attributes.control !== "hidden",
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
@ -165,10 +173,12 @@ const generateViewConfig = (
|
||||
.forEach((domain) => {
|
||||
cards = cards.concat(
|
||||
computeCards(
|
||||
localize(`domain.${domain}`),
|
||||
ungroupedEntitites[domain].map(
|
||||
(entityId): [string, HassEntity] => [entityId, entities[entityId]]
|
||||
)
|
||||
),
|
||||
{
|
||||
title: localize(`domain.${domain}`),
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
@ -237,6 +247,16 @@ export const generateLovelaceConfig = (
|
||||
)
|
||||
);
|
||||
|
||||
// Add map of geo locations to default view if loaded
|
||||
if (hass.config.components.includes("geo_location")) {
|
||||
if (views[0] && views[0].cards) {
|
||||
views[0].cards.push({
|
||||
type: "map",
|
||||
geo_location_sources: ["all"],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't have Home as title and first tab.
|
||||
if (views.length > 1 && title === "Home") {
|
||||
title = "Home Assistant";
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { PropertyValues } from "@polymer/lit-element";
|
||||
import { PropertyValues } from "lit-element";
|
||||
|
||||
// Check if config or Entity changed
|
||||
export function hasConfigOrEntityChanged(
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
@ -51,7 +55,7 @@ export class HuiActionEditor extends LitElement {
|
||||
return config.service || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass || !this.actions) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { html, LitElement, PropertyDeclarations } from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import "@polymer/paper-menu-button/paper-menu-button";
|
||||
import "@polymer/paper-icon-button/paper-icon-button";
|
||||
@ -46,10 +46,6 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
|
||||
paper-button {
|
||||
color: var(--primary-color);
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.05em;
|
||||
font-size: 16px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
paper-icon-button {
|
||||
color: var(--primary-text-color);
|
||||
|
@ -3,8 +3,8 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { PaperToggleButtonElement } from "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import { DOMAINS_TOGGLE } from "../../../common/const";
|
||||
@ -35,7 +35,7 @@ class HuiEntitiesToggle extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._toggleEntities) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
@ -19,7 +23,7 @@ export class HuiEntityEditor extends LitElement {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.entities) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
|
||||
@ -28,7 +32,7 @@ export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
const themes = ["Backend-selected", "default"].concat(
|
||||
Object.keys(this.hass!.themes.themes).sort()
|
||||
);
|
||||
|
@ -3,8 +3,8 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import format_date from "../../../common/datetime/format_date";
|
||||
@ -49,7 +49,7 @@ class HuiTimestampDisplay extends hassLocalizeLitMixin(LitElement) {
|
||||
this._clearInterval();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.ts || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
import "@polymer/paper-button/paper-button";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
@ -39,7 +38,7 @@ export class HuiCardPicker extends hassLocalizeLitMixin(LitElement) {
|
||||
public hass?: HomeAssistant;
|
||||
public cardPicked?: (cardConf: LovelaceCardConfig) => void;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<h3>${this.localize("ui.panel.lovelace.editor.edit_card.pick_card")}</h3>
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
@ -48,7 +52,7 @@ export class HuiDialogEditCard extends LitElement {
|
||||
: undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
// tslint:disable-next-line:no-duplicate-imports
|
||||
@ -23,7 +27,7 @@ export class HuiDialogMoveCardView extends hassLocalizeLitMixin(LitElement) {
|
||||
await this.updateComplete;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
|
||||
|
||||
@ -17,7 +21,7 @@ export class HuiDialogPickCard extends hassLocalizeLitMixin(LitElement) {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<paper-dialog
|
||||
with-backdrop
|
||||
|
@ -3,9 +3,9 @@ import {
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
PropertyValues,
|
||||
} from "@polymer/lit-element";
|
||||
import { classMap } from "lit-html/directives/classMap";
|
||||
import { TemplateResult } from "lit-html";
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { classMap } from "lit-html/directives/class-map";
|
||||
import yaml from "js-yaml";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
@ -107,7 +107,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) {
|
||||
this._loadConfigElement(this.cardConfig!);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
let content;
|
||||
let preview;
|
||||
if (this._configElement !== undefined) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
@ -21,7 +25,7 @@ export class HuiYAMLEditor extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-textarea
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { html } from "@polymer/lit-element";
|
||||
import { html } from "lit-element";
|
||||
|
||||
export const configElementStyle = html`
|
||||
<style>
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
@ -49,7 +53,7 @@ export class HuiAlarmPanelCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.states || [];
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
@ -12,7 +16,10 @@ import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { LovelaceCardEditor } from "../../types";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { Config, ConfigEntity } from "../../cards/hui-entities-card";
|
||||
import {
|
||||
EntitiesCardConfig,
|
||||
EntitiesCardEntityConfig,
|
||||
} from "../../cards/hui-entities-card";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
import "../../../../components/entity/state-badge";
|
||||
@ -53,16 +60,16 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
}
|
||||
|
||||
public hass?: HomeAssistant;
|
||||
private _config?: Config;
|
||||
private _configEntities?: ConfigEntity[];
|
||||
private _config?: EntitiesCardConfig;
|
||||
private _configEntities?: EntitiesCardEntityConfig[];
|
||||
|
||||
public setConfig(config: Config): void {
|
||||
public setConfig(config: EntitiesCardConfig): void {
|
||||
config = cardConfigStruct(config);
|
||||
this._config = config;
|
||||
this._configEntities = processEditorEntities(config.entities);
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -68,7 +72,7 @@ export class HuiEntityButtonCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.theme || "default";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
@ -70,7 +74,7 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.severity || undefined;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
@ -68,7 +72,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.columns || NaN;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -44,7 +48,7 @@ export class HuiIframeCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.aspect_ratio || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -47,7 +51,7 @@ export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.entity || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -64,7 +68,7 @@ export class HuiMapCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.entities || [];
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-input/paper-textarea";
|
||||
|
||||
@ -40,7 +44,7 @@ export class HuiMarkdownCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.content || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
@ -34,7 +38,7 @@ export class HuiMediaControlCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.entity || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -51,7 +55,7 @@ export class HuiPictureCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.hold_action || { action: "none" };
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -42,7 +46,7 @@ export class HuiPlantStatusCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.name || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import "@polymer/paper-dropdown-menu/paper-dropdown-menu";
|
||||
import "@polymer/paper-item/paper-item";
|
||||
@ -75,7 +79,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.hours_to_show || "24";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -33,7 +37,7 @@ export class HuiShoppingListEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.title || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
@ -47,7 +51,7 @@ export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement)
|
||||
return this._config!.theme || "default";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { struct } from "../../common/structs/struct";
|
||||
import { EntitiesEditorEvent, EditorTarget } from "../types";
|
||||
@ -41,7 +45,7 @@ export class HuiWeatherForecastCardEditor
|
||||
return this._config!.name || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
@ -41,7 +45,7 @@ export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-dialog with-backdrop>
|
||||
@ -108,6 +112,7 @@ export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) {
|
||||
try {
|
||||
const lovelace = this._params!.lovelace;
|
||||
await lovelace.saveConfig(lovelace.config);
|
||||
lovelace.setEditMode(true);
|
||||
this._saving = false;
|
||||
this._closeDialog();
|
||||
} catch (err) {
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-dialog/paper-dialog";
|
||||
// This is not a duplicate import, one is for types, one is for element.
|
||||
@ -47,7 +51,7 @@ export class HuiDialogEditLovelace extends hassLocalizeLitMixin(LitElement) {
|
||||
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${this.renderStyle()}
|
||||
<paper-dialog with-backdrop>
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { EditorTarget } from "../types";
|
||||
@ -33,7 +37,7 @@ export class HuiLovelaceEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
return this.config.title || "";
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
${configElementStyle}
|
||||
<div class="card-config">
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import { HomeAssistant } from "../../../../types";
|
||||
import { HASSDomEvent } from "../../../../common/dom/fire_event";
|
||||
@ -34,7 +38,7 @@ export class HuiDialogEditView extends LitElement {
|
||||
(this.shadowRoot!.children[0] as any).showDialog();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._params) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "@polymer/paper-spinner/paper-spinner";
|
||||
import "@polymer/paper-tabs/paper-tab";
|
||||
@ -83,7 +87,7 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) {
|
||||
return this.shadowRoot!.querySelector("paper-dialog")!;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
let content;
|
||||
switch (this._curTab) {
|
||||
case "tab-settings":
|
||||
|
@ -1,5 +1,9 @@
|
||||
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
PropertyDeclarations,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
|
||||
import { EditorTarget } from "../types";
|
||||
@ -59,7 +63,7 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import "../../../components/ha-icon";
|
||||
|
||||
@ -8,7 +8,6 @@ import { longPress } from "../common/directives/long-press-directive";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
interface Config extends LovelaceElementConfig {
|
||||
icon: string;
|
||||
@ -31,7 +30,7 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import "../components/hui-image";
|
||||
|
||||
@ -8,7 +8,6 @@ import { longPress } from "../common/directives/long-press-directive";
|
||||
import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
interface Config extends LovelaceElementConfig {
|
||||
image?: string;
|
||||
@ -40,7 +39,7 @@ export class HuiImageElement extends hassLocalizeLitMixin(LitElement)
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { TemplateResult } from "lit-html";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import "../../../components/buttons/ha-call-service-button";
|
||||
|
||||
@ -37,7 +36,7 @@ export class HuiServiceButtonElement extends LitElement
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config) {
|
||||
return html``;
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { html, LitElement } from "@polymer/lit-element";
|
||||
import { html, LitElement, TemplateResult } from "lit-element";
|
||||
|
||||
import "../../../components/entity/ha-state-label-badge";
|
||||
|
||||
import computeStateName from "../../../common/entity/compute_state_name";
|
||||
import { LovelaceElement, LovelaceElementConfig } from "./types";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
import { TemplateResult } from "lit-html";
|
||||
|
||||
export class HuiStateBadgeElement extends LitElement
|
||||
implements LovelaceElement {
|
||||
@ -24,7 +23,7 @@ export class HuiStateBadgeElement extends LitElement
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
protected render(): TemplateResult | void {
|
||||
if (
|
||||
!this._config ||
|
||||
!this.hass ||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user