Total overhaul!
This commit is contained in:
35
src/climate-controller.js
Normal file
35
src/climate-controller.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class ClimateController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return this.stateObj.attributes.temperature;
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
this._hass.callService("climate", "set_temperature", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
temperature: value,
|
||||
});
|
||||
}
|
||||
|
||||
get string() {
|
||||
if (this.stateObj.attributes.operation_mode === "off")
|
||||
return this._hass.localize("state.climate.off");
|
||||
return `${this.value} ${this._hass.config.unit_system.temperature}`;
|
||||
}
|
||||
|
||||
get isOff() {
|
||||
return this.stateObj.attributes.operation_mode === "off";
|
||||
}
|
||||
|
||||
get _min() {
|
||||
return this.stateObj.attributes.min_temp;
|
||||
}
|
||||
get _max() {
|
||||
return this.stateObj.attributes.max_temp;
|
||||
}
|
||||
get _step() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
59
src/controller.js
Normal file
59
src/controller.js
Normal file
@@ -0,0 +1,59 @@
|
||||
export class Controller {
|
||||
constructor(config) {
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
set hass(hass) {
|
||||
this._hass = hass;
|
||||
this.stateObj = this._config.entity in hass.states ? hass.states[this._config.entity] : null;
|
||||
}
|
||||
|
||||
get value() {
|
||||
if(this._value)
|
||||
return Math.round(this._value/this.step)*this.step;
|
||||
return 0;
|
||||
}
|
||||
set value(value) {
|
||||
if (value !== this.value)
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
get string() {
|
||||
return `${this.value}`;
|
||||
}
|
||||
get hidden() {
|
||||
return false;
|
||||
}
|
||||
get hasSlider() {
|
||||
return true;
|
||||
}
|
||||
get hasToggle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get isOff() {
|
||||
return this.value === 0;
|
||||
}
|
||||
|
||||
get min() {
|
||||
if (this._config.min !== undefined)
|
||||
return this._config.min;
|
||||
if (this._min !== undefined)
|
||||
return this._min;
|
||||
return 0;
|
||||
}
|
||||
get max() {
|
||||
if (this._config.max !== undefined)
|
||||
return this._config.max;
|
||||
if (this._max !== undefined)
|
||||
return this._max;
|
||||
return 100;
|
||||
}
|
||||
get step() {
|
||||
if (this._config.step !== undefined)
|
||||
return this._config.step;
|
||||
if (this._step !== undefined)
|
||||
return this._step;
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
40
src/cover-controller.js
Normal file
40
src/cover-controller.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class CoverController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return this.stateObj.state === "open"
|
||||
? this.stateObj.attributes.current_position
|
||||
: 0;
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
this._hass.callService("cover", "set_cover_position", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
position: value,
|
||||
});
|
||||
}
|
||||
|
||||
get string() {
|
||||
if (!this.hasSlider)
|
||||
return "";
|
||||
if (this.stateObj.state === "closed")
|
||||
return this._hass.localize("state.cover.closed");
|
||||
return `${this.value} %`
|
||||
}
|
||||
|
||||
get hasToggle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get hasSlider() {
|
||||
if ("current_position" in this.stateObj.attributes) return true;
|
||||
if (("supported_features" in this.stateObj.attributes) &&
|
||||
(this.stateObj.attributes.supported_features & 4)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
get _step() {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
43
src/fan-controller.js
Normal file
43
src/fan-controller.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class FanController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return (this.stateObj.state !== "off")
|
||||
? this.stateObj.attributes.speed_list.indexOf(this.stateObj.attributes.speed)
|
||||
: 0;
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
if (value in this.stateObj.attributes.speed_list) {
|
||||
this._hass.callService("fan", "turn_on", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
speed: this.stateObj.attributes.speed_list[value],
|
||||
});
|
||||
} else {
|
||||
this._hass.callService("fan", "turn_off", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get string() {
|
||||
if (this.stateObj.state === "off")
|
||||
return this._hass.localize("state.default.off");
|
||||
return this.stateObj.attributes.speed;
|
||||
}
|
||||
|
||||
get hasSlider() {
|
||||
if ("speed" in this.stateObj.attributes) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
get _max() {
|
||||
return this.stateObj.attributes.speed_list.length -1;
|
||||
}
|
||||
|
||||
get _step() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
44
src/input-number-controller.js
Normal file
44
src/input-number-controller.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class InputNumberController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return this.stateObj.state;
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
this._hass.callService("input_number", "set_value", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
value: value,
|
||||
});
|
||||
}
|
||||
|
||||
get string() {
|
||||
return `${Math.round(this.stateObj.state)}`
|
||||
}
|
||||
|
||||
get isOff() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get hasToggle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get hasSlider() {
|
||||
return this.stateObj.attributes.mode === "slider";
|
||||
}
|
||||
|
||||
get _min() {
|
||||
return this.stateObj.attributes.min;
|
||||
}
|
||||
|
||||
get _max() {
|
||||
return this.stateObj.attributes.max;
|
||||
}
|
||||
|
||||
get _step() {
|
||||
return this.stateObj.attributes.step;
|
||||
}
|
||||
|
||||
}
|
||||
41
src/input-select-controller.js
Normal file
41
src/input-select-controller.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class InputSelectController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return this.stateObj.attributes.options.indexOf(this.stateObj.state);
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
if (value in this.stateObj.attributes.options)
|
||||
this._hass.callService("input_select", "select_option", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
option: this.stateObj.attributes.options[value],
|
||||
});
|
||||
}
|
||||
|
||||
get string() {
|
||||
return this.stateObj.state;
|
||||
}
|
||||
|
||||
get isOff() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get hasToggle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
get hasSlider() {
|
||||
return this.stateObj.attributes.options && this.stateObj.attributes.options.length > 0
|
||||
}
|
||||
|
||||
get _max() {
|
||||
return this.stateObj.attributes.options.length - 1;
|
||||
}
|
||||
|
||||
get _step() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
37
src/light-controller.js
Normal file
37
src/light-controller.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class LightController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return (this.stateObj.state === "on")
|
||||
? Math.ceil(this.stateObj.attributes.brightness*100.0/255)
|
||||
: 0;
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
value = Math.ceil(value/100.0*255);
|
||||
if (value) {
|
||||
this._hass.callService("light", "turn_on", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
brightness: value,
|
||||
});
|
||||
} else {
|
||||
this._hass.callService("light", "turn_off", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get string() {
|
||||
if (this.stateObj.state === "off")
|
||||
return this._hass.localize("state.default.off");
|
||||
return `${this.value} %`;
|
||||
}
|
||||
|
||||
get hasSlider() {
|
||||
if ("brightness" in this.stateObj.attributes) return true;
|
||||
if (("supported_features" in this.stateObj.attributes) &&
|
||||
(this.stateObj.attributes.supported_features & 1)) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
119
src/main.js
Normal file
119
src/main.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import {LitElement, html, css} from "/card-tools/lit-element.js";
|
||||
|
||||
import { Controller } from "./controller.js";
|
||||
import { LightController } from "./light-controller.js";
|
||||
import { MediaPlayerController } from "./media-player-controller.js";
|
||||
import { ClimateController } from "./climate-controller.js";
|
||||
import { CoverController } from "./cover-controller.js";
|
||||
import { FanController } from "./fan-controller.js";
|
||||
import { InputNumberController } from "./input-number-controller.js";
|
||||
import { InputSelectController } from "./input-select-controller.js";
|
||||
|
||||
const controllers = {
|
||||
light: LightController,
|
||||
media_player: MediaPlayerController,
|
||||
climate: ClimateController,
|
||||
cover: CoverController,
|
||||
fan: FanController,
|
||||
input_number: InputNumberController,
|
||||
input_select: InputSelectController,
|
||||
};
|
||||
|
||||
class SliderEntityRow extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {},
|
||||
};
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
this._config = config;
|
||||
const domain = config.entity.split('.')[0];
|
||||
const ctrlClass = controllers[domain];
|
||||
if(!ctrlClass)
|
||||
throw new Error(`Unsupported entity type: ${domain}`);
|
||||
this.ctrl = new ctrlClass(config);
|
||||
}
|
||||
|
||||
render() {
|
||||
const c = this.ctrl;
|
||||
c.hass = this.hass;
|
||||
const slider = html`
|
||||
<ha-slider
|
||||
.min=${c.min}
|
||||
.max=${c.max}
|
||||
.step=${c.step}
|
||||
.value=${c.value}
|
||||
pin
|
||||
@change=${(ev) => c.value = this.shadowRoot.querySelector("ha-slider").value}
|
||||
class=${this._config.full_row ? "full" : ""}
|
||||
></ha-slider>
|
||||
`;
|
||||
const toggle = html`
|
||||
<ha-entity-toggle
|
||||
.stateObj=${this.hass.states[this._config.entity]}
|
||||
.hass=${this.hass}
|
||||
></ha-entity-toggle>
|
||||
`;
|
||||
|
||||
const content = html`
|
||||
<div class="wrapper" @click=${(ev) => ev.stopPropagation()}>
|
||||
${(c.stateObj.state === "unavailable")
|
||||
? html`
|
||||
<span class="state">
|
||||
unavailable
|
||||
</span>
|
||||
`
|
||||
: html`
|
||||
${((this._config.hide_when_off && c.isOff)
|
||||
|| !c.hasSlider)
|
||||
? ""
|
||||
: slider }
|
||||
${(this._config.hide_state || this._config.toggle)
|
||||
? ""
|
||||
: html`
|
||||
<span class="state">
|
||||
${c.string}
|
||||
</span>
|
||||
`}
|
||||
${this._config.toggle
|
||||
&& c.hasToggle
|
||||
? toggle
|
||||
: ""}
|
||||
`}
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (this._config.full_row)
|
||||
return content;
|
||||
|
||||
return html`
|
||||
<hui-generic-entity-row
|
||||
.hass=${this.hass}
|
||||
.config=${this._config}
|
||||
> ${content} </hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return css`
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
}
|
||||
.state {
|
||||
min-width: 45px;
|
||||
text-align: end;
|
||||
}
|
||||
ha-entity-toggle {
|
||||
margin-left: 8px;
|
||||
}
|
||||
ha-slider.full {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('slider-entity-row', SliderEntityRow);
|
||||
34
src/media-player-controller.js
Normal file
34
src/media-player-controller.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import {Controller} from "./controller.js";
|
||||
|
||||
export class MediaPlayerController extends Controller {
|
||||
|
||||
get _value() {
|
||||
return (this.stateObj.is_volume_muted === "on")
|
||||
? 0
|
||||
: Math.ceil(this.stateObj.attributes.volume_level*100.0);
|
||||
}
|
||||
|
||||
set _value(value) {
|
||||
value = value/100.0;
|
||||
this._hass.callService("media_player", "volume_set", {
|
||||
entity_id: this.stateObj.entity_id,
|
||||
volume_level: value,
|
||||
});
|
||||
}
|
||||
|
||||
get isOff() {
|
||||
return this.stateObj.state === "off";
|
||||
}
|
||||
|
||||
get string() {
|
||||
if (this.stateObj.attributes.is_volume_muted)
|
||||
return "-";
|
||||
return !!this.stateObj.attributes.volume_level
|
||||
? `${this.value} %`
|
||||
: this._hass.localize("state.media_player.off");
|
||||
}
|
||||
|
||||
get hasToggle() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user