Skip to content

Commit

Permalink
initial commit - switch
Browse files Browse the repository at this point in the history
  • Loading branch information
farmio committed Nov 20, 2023
1 parent 5954f2b commit 40aa4a7
Show file tree
Hide file tree
Showing 10 changed files with 700 additions and 17 deletions.
224 changes: 224 additions & 0 deletions src/components/knx-configure-switch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";

import { fireEvent } from "@ha/common/dom/fire_event";
import "@ha/components/ha-button";
import "@ha/components/ha-card";
import "@ha/components/ha-fab";
import "@ha/components/ha-svg-icon";
import "@ha/components/ha-expansion-panel";
import "@ha/components/ha-navigation-list";
import "@ha/components/ha-icon-button";
import "@ha/components/ha-icon-overflow-menu";
import "@ha/components/ha-selector/ha-selector";
import "@ha/components/ha-selector/ha-selector-select";
import "@ha/components/ha-settings-row";
import "@ha/panels/config/ha-config-section";

import { HomeAssistant } from "@ha/types";
import "./knx-sync-state-selector-row";
import { SwitchEntityData, CreateEntityData } from "../types/entity_data";
import { KNX } from "../types/knx";
import { platformConstants } from "../utils/common";
import { KNXLogger } from "../tools/knx-logger";

const logger = new KNXLogger("knx-configure-switch");

declare global {
// for fire event
interface HASSDomEvents {
"knx-entity-configuration-changed": CreateEntityData;
}
}
@customElement("knx-configure-switch")
export class KNXConfigureSwitch extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;

@property({ attribute: false }) public knx!: KNX;

@state() private config: Partial<SwitchEntityData> = {};

protected render(): TemplateResult | void {
const dpt1gas = Object.values(this.knx.project!.knxproject.group_addresses).filter(
(groupAddress) => groupAddress.dpt?.main === 1,
);
const addressOptions = dpt1gas.map((groupAddress) => ({
value: groupAddress.address,
label: `${groupAddress.address} - ${groupAddress.name}`,
}));
return html`
<ha-card outlined>
<h1 class="card-header">
<ha-svg-icon .path=${platformConstants.switch.iconPath}></ha-svg-icon>Switch - KNX
configuration
</h1>
<p class="card-content">
The KNX switch platform is used as an interface to switching actuators.
</p>
<ha-settings-row narrow>
<div slot="heading">Switching</div>
<div slot="description">DPT 1 group addresses controlling the switch function.</div>
<ha-selector
.hass=${this.hass}
.label=${"Address"}
.selector=${{
select: { multiple: false, custom_value: true, options: addressOptions },
}}
.key=${"switch_address"}
.value=${this.config.switch_address}
@value-changed=${this._updateConfig}
></ha-selector>
<div class="spacer"></div>
<ha-selector
.hass=${this.hass}
.label=${"State address"}
.selector=${{
select: { multiple: false, custom_value: true, options: addressOptions },
}}
.key=${"switch_state_address"}
.value=${this.config.switch_state_address}
@value-changed=${this._updateConfig}
></ha-selector>
<ha-selector
.hass=${this.hass}
.label=${"Invert"}
.helper=${"Invert payloads before processing or sending."}
.selector=${{ boolean: {} }}
.key=${"invert"}
.value=${this.config.invert}
@value-changed=${this._updateConfig}
></ha-selector>
<ha-selector
.hass=${this.hass}
.label=${"Respond to read"}
.helper=${"Respond to GroupValueRead telegrams received to the configured address."}
.selector=${{ boolean: {} }}
.key=${"respond_to_read"}
.value=${this.config.respond_to_read}
@value-changed=${this._updateConfig}
></ha-selector>
</ha-settings-row>
<ha-expansion-panel .header=${"Advanced"} outlined>
<knx-sync-state-selector-row
.hass=${this.hass}
.key=${"sync_state"}
.value=${this.config.sync_state ?? true}
@value-changed=${this._updateConfig}
></knx-sync-state-selector-row>
<!-- <ha-settings-row narrow>
<div slot="heading">Entity settings</div>
<div slot="description">Description</div>
<ha-selector
.hass=${this.hass}

Check failure on line 112 in src/components/knx-configure-switch.ts

View workflow job for this annotation

GitHub Actions / Lint

Bindings cannot be used inside HTML comments
.label=${"Entity category"}
.selector=${{
select: {
multiple: false,
custom_value: false,
mode: "dropdown",
options: [
{ value: null, label: "None" }, // null not valid for selector - doesn't fire event
{ value: "config", label: "Config" },
{ value: "diagnostic", label: "Diagnostic" },
],
},
}}
.key=${"entity_category"}
.value=${this.config.entity_category ?? null}
@value-changed=${this._updateConfig}
></ha-selector>
</ha-settings-row> -->
</ha-expansion-panel>
</ha-card>
<ha-card outlined>
<h1 class="card-header">
<ha-svg-icon .path=${platformConstants.switch.iconPath}></ha-svg-icon>Switch - Entity
configuration
</h1>
<p class="card-content">Home Assistant entity specific settings.</p>
<ha-settings-row narrow>
<div slot="heading">Name</div>
<div slot="description">Name of the entity.</div>
<ha-selector
.hass=${this.hass}
.label=${"Name"}
.selector=${{
text: { type: "text" },
}}
.key=${"name"}
.value=${this.config.name}
@value-changed=${this._updateConfig}
></ha-selector>
</ha-settings-row>
</ha-card>
`;
}

private _updateConfig(ev) {
ev.stopPropagation();
this.config[ev.target.key] = ev.detail.value;
logger.warn(ev.target);
logger.warn("update key", ev.target.key);
logger.warn("update value", ev.detail.value);
logger.warn("new_config", this.config);
if (true) {

Check warning on line 164 in src/components/knx-configure-switch.ts

View workflow job for this annotation

GitHub Actions / Lint

Unexpected constant condition
// validate
fireEvent(this, "knx-entity-configuration-changed", {
platform: "switch",
data: this.config,
});
}
this.requestUpdate();
}

static get styles() {
return css`
.spacer {
height: 16px;
}
.divider {
height: 1px;
background-color: var(--divider-color);
margin-top: 10px;
margin-right: 0px;
}
.card-header {
display: inline-flex;
align-items: center;
}
ha-card {
margin-bottom: 24px;
padding: 16px;
}
ha-svg-icon {
color: var(--text-primary-color);
padding: 8px;
background-color: var(--blue-color);
border-radius: 50%;
}
h1 > * {
margin-right: 8px;
}
p {
color: var(--secondary-text-color);
}
ha-settings-row {
padding: 0;
margin-bottom: 16px;
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"knx-configure-switch": KNXConfigureSwitch;
}
}
125 changes: 125 additions & 0 deletions src/components/knx-sync-state-selector-row.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";

import { fireEvent } from "@ha/common/dom/fire_event";
import { HomeAssistant } from "@ha/types";
import "@ha/components/ha-selector/ha-selector";
import "@ha/components/ha-settings-row";

@customElement("knx-sync-state-selector-row")
export class KnxSyncStateSelectorRow extends LitElement {
@property({ type: Object }) public hass!: HomeAssistant;

@property() public value: string | boolean = true;

@property() public key = "sync_state";

@property({ type: Boolean }) noneValid = true;

private _strategy: boolean | "init" | "expire" | "every" = true;

private _minutes: number = 60;

protected _hasMinutes(strategy: boolean | string): boolean {
return strategy === "expire" || strategy === "every";
}

protected willUpdate() {
if (typeof this.value === "boolean") {
this._strategy = this.value;
return;
}
const [strategy, minutes] = this.value.split(" ");
this._strategy = strategy;
if (+minutes) {
this._minutes = +minutes;
}
}

protected render(): TemplateResult {
return html`<ha-settings-row narrow>
<div slot="heading">State updater</div>
<div slot="description">Actively request state updates from KNX bus for state addresses.</div>
<div class="inline">
<ha-selector
.hass=${this.hass}
.label=${"Strategy"}
.selector=${{
select: {
multiple: false,
custom_value: false,
mode: "dropdown",
options: [
{ value: true, label: "Default" },
...(this.noneValid ? [{ value: false, label: "Never" }] : []),
{ value: "init", label: "Once after connection" },
{ value: "expire", label: "Expire after last value update" },
{ value: "every", label: "Scheduled every" },
],
},
}}
.key=${"strategy"}
.value=${this._strategy}
@value-changed=${this._handleChange}
>
</ha-selector>
<ha-selector
.hass=${this.hass}
.disabled=${!this._hasMinutes(this._strategy)}
.selector=${{
number: {
min: 2,
max: 1440,
step: 1,
unit_of_measurement: "minutes",
},
}}
.key=${"minutes"}
.value=${this._minutes}
@value-changed=${this._handleChange}
>
</ha-selector></div
></ha-settings-row>`;
}

private _handleChange(ev) {
ev.stopPropagation();
let strategy: boolean | string;
let minutes: number;
if (ev.target.key === "strategy") {
strategy = ev.detail.value;
minutes = this._minutes;
} else {
strategy = this._strategy;
minutes = ev.detail.value;
}
const value = this._hasMinutes(strategy) ? `${strategy} ${minutes}` : strategy;
fireEvent(this, "value-changed", { value });
}

static get styles() {
return css`
ha-settings-row {
padding: 0;
margin-bottom: 16px;
}
.inline {
width: 100%;
display: inline-flex;
flex-flow: row wrap;
gap: 16px;
justify-content: space-between;
}
.inline > ha-selector {
flex: 1;
}
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"knx-sync-state-selector-row": KnxSyncStateSelectorRow;
}
}
7 changes: 7 additions & 0 deletions src/knx-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ class KnxRouter extends HassRouterPage {
return import("./views/project_view");
},
},
"create-entity": {
tag: "knx-create-entity",
load: () => {
logger.debug("Importing knx-create-entity");
return import("./views/create_entity");
},
},
},
};

Expand Down
1 change: 1 addition & 0 deletions src/localize/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"project_view_table_name": "Name",
"project_view_table_description": "Description",
"project_view_table_dpt": "DPT",
"project_view_add_switch": "Add switch",
"Incoming": "Incoming",
"Outgoing": "Outgoing"
}
13 changes: 12 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { html, nothing } from "lit";
import { css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";

import { applyThemesOnElement } from "@ha/common/dom/apply_themes_on_element";
Expand Down Expand Up @@ -61,6 +61,17 @@ class KnxFrontend extends knxElement {
`;
}

static get styles() {
// apply "Settings" style toolbar color for `hass-subpage`
return css`
:host {
--app-header-background-color: var(--sidebar-background-color);
--app-header-text-color: var(--sidebar-text-color);
--app-header-border-bottom: 1px solid var(--divider-color);
}
`;
}

private _setRoute(ev: LocationChangedEvent): void {
if (!ev.detail?.route) {
return;
Expand Down
Loading

0 comments on commit 40aa4a7

Please sign in to comment.