Big restructuring - repo is now a full home assistant config directory
This commit is contained in:
207
custom_frontend_sources/state-card-custom-cover/dist/state-card-custom-cover.js
vendored
Normal file
207
custom_frontend_sources/state-card-custom-cover/dist/state-card-custom-cover.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4607
custom_frontend_sources/state-card-custom-cover/package-lock.json
generated
Normal file
4607
custom_frontend_sources/state-card-custom-cover/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
custom_frontend_sources/state-card-custom-cover/package.json
Normal file
21
custom_frontend_sources/state-card-custom-cover/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "state-card-custom-cover",
|
||||
"version": "0.0.1",
|
||||
"description": "Cover card from home assistant",
|
||||
"main": "src/state-card-custom-cover.ts",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"private": true,
|
||||
"author": "Martin Bauer",
|
||||
"license": "GPLv3",
|
||||
"devDependencies": {
|
||||
"home-assistant-js-websocket": "^4.2.2",
|
||||
"lit-element": "^2.1.0",
|
||||
"ts-loader": "^6.0.2",
|
||||
"typescript": "^3.5.1",
|
||||
"webpack": "^4.33.0",
|
||||
"webpack-cli": "^3.3.4"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import {
|
||||
HassEntity,
|
||||
} from "home-assistant-js-websocket";
|
||||
import {HomeAssistant} from "./home-assistant-interface";
|
||||
|
||||
|
||||
const supportsFeature = (
|
||||
stateObj: HassEntity,
|
||||
feature: number
|
||||
): boolean => {
|
||||
// tslint:disable-next-line:no-bitwise
|
||||
return (stateObj.attributes.supported_features! & feature) !== 0;
|
||||
};
|
||||
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
export class CoverEntity {
|
||||
|
||||
public hass: HomeAssistant;
|
||||
public stateObj: HassEntity;
|
||||
private _attr: { [key: string]: any; };
|
||||
private _feat: any;
|
||||
|
||||
constructor(hass : HomeAssistant, stateObj) {
|
||||
this.hass = hass;
|
||||
this.stateObj = stateObj;
|
||||
this._attr = stateObj.attributes;
|
||||
this._feat = this._attr.supported_features;
|
||||
}
|
||||
|
||||
get isFullyOpen() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 100;
|
||||
}
|
||||
return this.stateObj.state === "open";
|
||||
}
|
||||
|
||||
get isFullyClosed() {
|
||||
if (this._attr.current_position !== undefined) {
|
||||
return this._attr.current_position === 0;
|
||||
}
|
||||
return this.stateObj.state === "closed";
|
||||
}
|
||||
|
||||
get isFullyOpenTilt() {
|
||||
return this._attr.current_tilt_position === 100;
|
||||
}
|
||||
|
||||
get isFullyClosedTilt() {
|
||||
return this._attr.current_tilt_position === 0;
|
||||
}
|
||||
|
||||
get isOpening() {
|
||||
return this.stateObj.state === "opening";
|
||||
}
|
||||
|
||||
get isClosing() {
|
||||
return this.stateObj.state === "closing";
|
||||
}
|
||||
|
||||
get supportsOpen() {
|
||||
return supportsFeature(this.stateObj, 1);
|
||||
}
|
||||
|
||||
get supportsClose() {
|
||||
return supportsFeature(this.stateObj, 2);
|
||||
}
|
||||
|
||||
get supportsSetPosition() {
|
||||
return supportsFeature(this.stateObj, 4);
|
||||
}
|
||||
|
||||
get supportsStop() {
|
||||
return supportsFeature(this.stateObj, 8);
|
||||
}
|
||||
|
||||
get supportsOpenTilt() {
|
||||
return supportsFeature(this.stateObj, 16);
|
||||
}
|
||||
|
||||
get supportsCloseTilt() {
|
||||
return supportsFeature(this.stateObj, 32);
|
||||
}
|
||||
|
||||
get supportsStopTilt() {
|
||||
return supportsFeature(this.stateObj, 64);
|
||||
}
|
||||
|
||||
get supportsSetTiltPosition() {
|
||||
return supportsFeature(this.stateObj, 128);
|
||||
}
|
||||
|
||||
get isTiltOnly() {
|
||||
const supportsCover =
|
||||
this.supportsOpen || this.supportsClose || this.supportsStop;
|
||||
const supportsTilt =
|
||||
this.supportsOpenTilt || this.supportsCloseTilt || this.supportsStopTilt;
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
|
||||
openCover() {
|
||||
this.callService("open_cover");
|
||||
}
|
||||
|
||||
closeCover() {
|
||||
this.callService("close_cover");
|
||||
}
|
||||
|
||||
stopCover() {
|
||||
this.callService("stop_cover");
|
||||
}
|
||||
|
||||
openCoverTilt() {
|
||||
this.callService("open_cover_tilt");
|
||||
}
|
||||
|
||||
closeCoverTilt() {
|
||||
this.callService("close_cover_tilt");
|
||||
}
|
||||
|
||||
stopCoverTilt() {
|
||||
this.callService("stop_cover_tilt");
|
||||
}
|
||||
|
||||
setCoverPosition(position) {
|
||||
this.callService("set_cover_position", { position });
|
||||
}
|
||||
|
||||
setCoverTiltPosition(tiltPosition) {
|
||||
this.callService("set_cover_tilt_position", {
|
||||
tilt_position: tiltPosition,
|
||||
});
|
||||
}
|
||||
|
||||
// helper method
|
||||
|
||||
callService(service, data = {}) {
|
||||
data['entity_id'] = this.stateObj.entity_id;
|
||||
this.hass.callService("cover", service, data);
|
||||
}
|
||||
}
|
||||
|
||||
export const supportsOpen = (stateObj) => supportsFeature(stateObj, 1);
|
||||
|
||||
export const supportsClose = (stateObj) => supportsFeature(stateObj, 2);
|
||||
|
||||
export const supportsSetPosition = (stateObj) => supportsFeature(stateObj, 4);
|
||||
|
||||
export const supportsStop = (stateObj) => supportsFeature(stateObj, 8);
|
||||
|
||||
export const supportsOpenTilt = (stateObj) => supportsFeature(stateObj, 16);
|
||||
|
||||
export const supportsCloseTilt = (stateObj) => supportsFeature(stateObj, 32);
|
||||
|
||||
export const supportsStopTilt = (stateObj) => supportsFeature(stateObj, 64);
|
||||
|
||||
export const supportsSetTiltPosition = (stateObj) =>
|
||||
supportsFeature(stateObj, 128);
|
||||
|
||||
export function isTiltOnly(stateObj) {
|
||||
const supportsCover =
|
||||
supportsOpen(stateObj) || supportsClose(stateObj) || supportsStop(stateObj);
|
||||
const supportsTilt =
|
||||
supportsOpenTilt(stateObj) ||
|
||||
supportsCloseTilt(stateObj) ||
|
||||
supportsStopTilt(stateObj);
|
||||
return supportsTilt && !supportsCover;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import {Connection, HassConfig, HassEntities, HassServices, MessageBase} from "home-assistant-js-websocket";
|
||||
|
||||
export interface HomeAssistant {
|
||||
connection: Connection;
|
||||
connected: boolean;
|
||||
states: HassEntities;
|
||||
services: HassServices;
|
||||
config: HassConfig;
|
||||
|
||||
callService: (
|
||||
domain: string,
|
||||
service: string,
|
||||
serviceData?: { [key: string]: any }
|
||||
) => Promise<void>;
|
||||
callApi: <T>(
|
||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
path: string,
|
||||
parameters?: { [key: string]: any }
|
||||
) => Promise<T>;
|
||||
fetchWithAuth: (
|
||||
path: string,
|
||||
init?: { [key: string]: any }
|
||||
) => Promise<Response>;
|
||||
sendWS: (msg: MessageBase) => void;
|
||||
callWS: <T>(msg: MessageBase) => Promise<T>;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import {LitElement, html, customElement, property, TemplateResult} from "lit-element";
|
||||
import {CoverEntity} from "./cover-model"
|
||||
import {HomeAssistant} from "./home-assistant-interface";
|
||||
|
||||
|
||||
export interface CustomCoverStateCardConfig {
|
||||
type: string;
|
||||
entity: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@customElement("state-card-custom-cover")
|
||||
export class StateCardCustomCover extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
|
||||
@property() private _config?: CustomCoverStateCardConfig;
|
||||
|
||||
@property()
|
||||
public get stateObj() {
|
||||
if (this.hass && this._config)
|
||||
return this.hass.states[this._config.entity];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@property() public inDialog: boolean = false;
|
||||
|
||||
|
||||
public setConfig(config: CustomCoverStateCardConfig | undefined) {
|
||||
if (!config || !config.entity) {
|
||||
throw new Error("Invalid configuration");
|
||||
}
|
||||
this._config = config;
|
||||
}
|
||||
|
||||
|
||||
get entityObj(): CoverEntity {
|
||||
if (this.hass && this.stateObj)
|
||||
return new CoverEntity(this.hass, this.stateObj);
|
||||
else
|
||||
throw new Error("Trying to get entityObj before setting hass & config");
|
||||
}
|
||||
|
||||
public static getCardSize(): number {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
protected stateInfoTemplate() {
|
||||
return html`
|
||||
State info template
|
||||
`;
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
const entityObj = this.entityObj;
|
||||
const stateObj = this.hass.states[this._config.entity];
|
||||
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<hui-warning
|
||||
>Does not work :(</hui-warning
|
||||
>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<style include="iron-flex iron-flex-alignment"></style>
|
||||
<style>
|
||||
:host {
|
||||
line-height: 1.5;
|
||||
}
|
||||
.state {
|
||||
white-space: nowrap;
|
||||
}
|
||||
[invisible] {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<hui-generic-entity-row .config="${this._config}" .hass="${this.hass}">
|
||||
<div class="state">
|
||||
<paper-icon-button
|
||||
icon="hass:menu"
|
||||
@click=${this.onHalfOpenTap}
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon="hass:arrow-up"
|
||||
@click=${this.onOpenTap}
|
||||
.disabled="${this.computeOpenDisabled(stateObj, this.entityObj)}"
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon="hass:stop"
|
||||
@click=${this.onStopTap}
|
||||
></paper-icon-button>
|
||||
<paper-icon-button
|
||||
icon="hass:arrow-down"
|
||||
@click=${this.onCloseTap}
|
||||
.disabled="${this.computeClosedDisabled(stateObj, entityObj)}"
|
||||
></paper-icon-button>
|
||||
</div>
|
||||
</hui-generic-entity-row>
|
||||
`;
|
||||
}
|
||||
|
||||
computeOpenDisabled(stateObj, entityObj) {
|
||||
const assumedState = stateObj.attributes.assumed_state === true;
|
||||
return (entityObj.isFullyOpen || entityObj.isOpening) && !assumedState;
|
||||
}
|
||||
|
||||
computeClosedDisabled(stateObj, entityObj) {
|
||||
const assumedState = stateObj.attributes.assumed_state === true;
|
||||
return (entityObj.isFullyClosed || entityObj.isClosing) && !assumedState;
|
||||
}
|
||||
|
||||
private onHalfOpenTap(ev) {
|
||||
const stateObj = this.hass!.states[this._config!.entity];
|
||||
ev.stopPropagation();
|
||||
this.entityObj.setCoverPosition(stateObj.attributes['half_position']);
|
||||
}
|
||||
|
||||
private onOpenTap(ev) {
|
||||
ev.stopPropagation();
|
||||
this.entityObj.openCover();
|
||||
}
|
||||
|
||||
private onCloseTap(ev) {
|
||||
ev.stopPropagation();
|
||||
this.entityObj.closeCover();
|
||||
}
|
||||
|
||||
private onStopTap(ev) {
|
||||
ev.stopPropagation();
|
||||
this.entityObj.stopCover();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom",
|
||||
"dom.iterable"
|
||||
],
|
||||
"noUnusedParameters": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"skipLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: "./src/state-card-custom-cover.ts",
|
||||
output: {
|
||||
filename: 'state-card-custom-cover.js',
|
||||
path: path.resolve(__dirname, 'dist')
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".js", ".json"]
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
// all files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'
|
||||
{test: /\.tsx?$/, use: ["ts-loader"], exclude: /node_modules/}
|
||||
]
|
||||
},
|
||||
mode: "production"
|
||||
}
|
||||
Reference in New Issue
Block a user