Big restructuring - repo is now a full home assistant config directory

This commit is contained in:
Martin Bauer
2019-06-30 19:37:32 +02:00
parent d35b9e132e
commit 808727ad92
79 changed files with 14378 additions and 27 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View 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"
}
}

View File

@@ -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;
}

View File

@@ -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>;
}

View File

@@ -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();
}
}

View File

@@ -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
}
}

View File

@@ -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"
}