Complete overhaul
This commit is contained in:
parent
a64a9b4cbe
commit
5495c5ba8c
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
state-switch.js binary
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
node_modules/
|
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Thomas Lovén
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
64
README.md
64
README.md
@ -1,29 +1,50 @@
|
||||
state-switch
|
||||
============
|
||||
[](https://github.com/custom-components/hacs)
|
||||
|
||||
Allows you to display different cards depending on the state of an entity, the currently logged in user or the current device-browser combination
|
||||
Dynamically replace lovelace cards depending on occasion.
|
||||
|
||||

|
||||
|
||||
> Note in the animation above that the two browser windows have two different users logged in, which changes the rightmost card.
|
||||
|
||||
## Installation
|
||||
This card requires [card-tools](https://github.com/thomasloven/lovelace-card-tools) to be installed.
|
||||
|
||||
For installation instructions [see this guide](https://github.com/thomasloven/hass-config/wiki/Lovelace-Plugins).
|
||||
|
||||
Install `state-switch.js` as a `module`.
|
||||
|
||||
```yaml
|
||||
resources:
|
||||
- url: /local/state-switch.js
|
||||
type: module
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
type: custom:state-switch
|
||||
entity: <entity>
|
||||
default: <default>
|
||||
states:
|
||||
<state 1>:
|
||||
<card 1>
|
||||
<state 2>:
|
||||
<card 2>
|
||||
...
|
||||
```
|
||||
|
||||
When the state of `<entity>` is `<state 1>`, `<card 1>` will be displayed, when it's `<state 2>`, `<card 2>` will be displayed.
|
||||
|
||||
If the state of `<entity>` doesn't match any `<state>`, the `<card>` for the `<default>` state will be displayed.
|
||||
|
||||
## Options
|
||||
- `<entity>` **Required** An entity id or `hash`, `user`, `deviceID`
|
||||
- `<default>` State to use as default fallback
|
||||
- `<state N>` The state to match
|
||||
- `<card N>` Lovelace card configuration
|
||||
|
||||
| Name | Type | Default | Description
|
||||
| ---- | ---- | ------- | -----------
|
||||
| type | string | **Required** | `custom:state-switch`
|
||||
| entity | string | **Required** | Controlling entity id, `hash`, `user` or `browser`
|
||||
| states | object | **Required** | Map of states to cards to display
|
||||
| default | string | none | State to use as default
|
||||
## State matching
|
||||
|
||||
The `entity` parameter can take four different types of value
|
||||
|
||||
### Entity\_id
|
||||
### entity\_id
|
||||
If the `entity` parameter is set to an entity id, which card is displayed will depend on the state of that entity.
|
||||
|
||||
```yaml
|
||||
@ -143,16 +164,14 @@ If the `entity` parameter is set to `user`, which card is displayed will depend
|
||||
## Unknown user
|
||||
```
|
||||
|
||||
### browser
|
||||
If the `entity` parameter is set to `browser`, which card is displayed will depend on the device-browser combination which is currently displaying the page.
|
||||
### deviceID
|
||||
If the `entity` parameter is set to `deviceID`, which card is displayed will depend on the device-browser combination which is currently displaying the page.
|
||||
|
||||
This "browser ID" is in the form of a 16 character string with a dash in the middle and is unique, random and persistent for the browser.
|
||||
|
||||
If the `default` parameter is **not** set, the default behavior will be to display a small card containing the browser ID.
|
||||
See [browser_mod](https://github.com/thomasloven/hass-browser_mod#devices) for a description on how deviceIDs work.
|
||||
|
||||
```yaml
|
||||
- type: custom:state-switch
|
||||
entity: browser
|
||||
entity: deviceID
|
||||
states:
|
||||
'9c2aaf6f-ed26e3c1':
|
||||
type: markdown
|
||||
@ -163,3 +182,10 @@ If the `default` parameter is **not** set, the default behavior will be to displ
|
||||
content: >
|
||||
Mobile
|
||||
```
|
||||
|
||||
## A few tips
|
||||
|
||||
- To replace more than one card at a time, use e.g. [`vertical-stack`](https://www.home-assistant.io/lovelace/vertical-stack/), [`horizontal-stack`](https://www.home-assistant.io/lovelace/horizontal-stack/) or [`layout-card`](https://github.com/thomasloven/lovelace-layout-card).
|
||||
|
||||
---
|
||||
<a href="https://www.buymeacoffee.com/uqD6KHCdJ" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/white_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>
|
||||
|
4051
package-lock.json
generated
Normal file
4051
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
package.json
Normal file
25
package.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "state-switch",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "state-switch =================",
|
||||
"scripts": {
|
||||
"build": "webpack",
|
||||
"watch": "webpack --watch --mode=development",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "github.com:thomasloven/lovelace-state-switch"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Thomas Lovén",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"card-tools": "github:thomasloven/lovelace-card-tools"
|
||||
}
|
||||
}
|
82
src/main.js
Normal file
82
src/main.js
Normal file
@ -0,0 +1,82 @@
|
||||
import { LitElement, html } from "card-tools/src/lit-element";
|
||||
import { hass } from "card-tools/src/hass";
|
||||
import { createCard } from "card-tools/src/lovelace-element";
|
||||
import { deviceID } from "card-tools/src/deviceID";
|
||||
|
||||
class StateSwitch extends LitElement {
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {},
|
||||
state: {},
|
||||
};
|
||||
}
|
||||
|
||||
setConfig(config) {
|
||||
this._config = config;
|
||||
|
||||
this.state = undefined;
|
||||
this.cards = {};
|
||||
for(let k in config.states) {
|
||||
this.cards[k] = createCard(config.states[k]);
|
||||
this.cards[k].hass = hass();
|
||||
}
|
||||
|
||||
if(config.entity === 'hash') {
|
||||
window.addEventListener("location-changed", () => this.updated(new Map()));
|
||||
}
|
||||
}
|
||||
|
||||
update_state() {
|
||||
let newstate = undefined;
|
||||
switch(this._config.entity) {
|
||||
case "user":
|
||||
newstate = this.hass && this.hass.user && this.hass.user.name || undefined;
|
||||
break;
|
||||
case "deviceID":
|
||||
case "browser":
|
||||
newstate = deviceID;
|
||||
break;
|
||||
case "hash":
|
||||
newstate = location.hash.substr(1);
|
||||
break;
|
||||
default:
|
||||
newstate = this.hass.states[this._config.entity];
|
||||
newstate = newstate ? newstate.state : undefined;
|
||||
}
|
||||
|
||||
if (newstate === undefined || !this.cards.hasOwnProperty(newstate))
|
||||
newstate = this._config.default;
|
||||
this.state = newstate;
|
||||
}
|
||||
|
||||
updated(changedProperties) {
|
||||
if(changedProperties.has("hass"))
|
||||
for(let k in this.cards)
|
||||
this.cards[k].hass = this.hass;
|
||||
|
||||
if(!changedProperties.has("state")) {
|
||||
this.update_state();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div id="root">
|
||||
${this.cards[this.state]}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
getCardSize() {
|
||||
let sz = 1;
|
||||
for(let k in this.cards) {
|
||||
if(this.cards[k] && this.cards[k].getCardSize)
|
||||
sz = Math.max(sz, this.cards[k].getCardSize());
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("state-switch", StateSwitch);
|
@ -1,82 +1,5 @@
|
||||
customElements.whenDefined('card-tools').then(() => {
|
||||
const cardTools = customElements.get('card-tools');
|
||||
class StateSwitch extends cardTools.LitElement {
|
||||
|
||||
setConfig(config) {
|
||||
cardTools.checkVersion(0.4);
|
||||
this.config = config;
|
||||
|
||||
this.cardSize = 1;
|
||||
this.cards = {}
|
||||
|
||||
for(var k in this.config.states) {
|
||||
this.cards[k] = cardTools.createCard(this.config.states[k]);
|
||||
this.cardSize = Math.max(this.cardSize, this.cards[k].getCardSize());
|
||||
}
|
||||
|
||||
this.idCard = cardTools.createCard({
|
||||
type: "markdown",
|
||||
title: "Device ID",
|
||||
content: `Your device id is: \`${cardTools.deviceID}\``,
|
||||
});
|
||||
|
||||
if(config.entity === 'hash') {
|
||||
window.addEventListener("location-changed", () => this.updateCard());
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return cardTools.LitHtml`
|
||||
<div id="root">${this.currentCard}</div>
|
||||
`;
|
||||
}
|
||||
|
||||
updateCard() {
|
||||
const hass = this._hass;
|
||||
if(!hass) return;
|
||||
const lastCard = this.currentCard;
|
||||
if (this.config.entity === 'user') {
|
||||
this.currentCard = this.cards[hass.user.name]
|
||||
|| this.cards[this.config.default];
|
||||
} else if(this.config.entity == 'browser') {
|
||||
this.currentCard = this.cards[cardTools.deviceID]
|
||||
|| ((this.config.default)
|
||||
? this.cards[this.config.default]
|
||||
: this.idCard);
|
||||
} else if(this.config.entity == 'hash') {
|
||||
this.currentCard = this.cards[location.hash.substr(1)]
|
||||
|| this.cards[this.config.default];
|
||||
} else {
|
||||
let state = hass.states[this.config.entity];
|
||||
this.currentCard = ((state)?this.cards[state.state]:null)
|
||||
|| this.cards[this.config.default];
|
||||
}
|
||||
|
||||
if(this.currentCard != lastCard) this.requestUpdate();
|
||||
}
|
||||
|
||||
set hass(hass) {
|
||||
if(!hass) return;
|
||||
this._hass = hass;
|
||||
|
||||
this.updateCard();
|
||||
|
||||
for(var k in this.cards)
|
||||
this.cards[k].hass = hass;
|
||||
}
|
||||
|
||||
getCardSize() {
|
||||
return this.cardSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define('state-switch', StateSwitch);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
if(customElements.get('card-tools')) return;
|
||||
customElements.define('state-switch', class extends HTMLElement{
|
||||
setConfig() { throw new Error("Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools");}
|
||||
});
|
||||
}, 2000);
|
||||
!function(e){var t={};function s(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,s),o.l=!0,o.exports}s.m=e,s.c=t,s.d=function(e,t,r){s.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},s.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},s.t=function(e,t){if(1&t&&(e=s(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(s.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)s.d(r,o,function(t){return e[t]}.bind(null,o));return r},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,"a",t),t},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.p="",s(s.s=0)}([function(e,t,s){"use strict";s.r(t);const r=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view")),o=r.prototype.html;r.prototype.css;function n(){return document.querySelector("home-assistant").hass}const a="custom:";function i(e,t){const s=document.createElement("hui-error-card");return s.setConfig({type:"error",error:e,origConfig:t}),s}function c(e,t){if(!t||"object"!=typeof t||!t.type)return i(`No ${e} type configured`,t);let s=t.type;if(s=s.startsWith(a)?s.substr(a.length):`hui-${s}-${e}`,customElements.get(s))return function(e,t){const s=document.createElement(e);try{s.setConfig(t)}catch(e){return i(e,t)}return s}(s,t);const r=i(`Custom element doesn't exist: ${s}.`,t);r.style.display="None";const o=setTimeout(()=>{r.style.display=""},2e3);return customElements.whenDefined(s).then(()=>{clearTimeout(o),function(e,t,s=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},s)s.dispatchEvent(e);else{var r=document.querySelector("home-assistant");(r=(r=(r=(r=(r=(r=(r=(r=(r=(r=(r=r&&r.shadowRoot)&&r.querySelector("home-assistant-main"))&&r.shadowRoot)&&r.querySelector("app-drawer-layout partial-panel-resolver"))&&r.shadowRoot||r)&&r.querySelector("ha-panel-lovelace"))&&r.shadowRoot)&&r.querySelector("hui-root"))&&r.shadowRoot)&&r.querySelector("ha-app-layout #view"))&&r.firstElementChild)&&r.dispatchEvent(e)}}("ll-rebuild",{},r)}),r}function u(e){return c("card",e)}let l=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();customElements.define("state-switch",class extends r{static get properties(){return{hass:{},state:{}}}setConfig(e){this._config=e,this.state=void 0,this.cards={};for(let t in e.states)this.cards[t]=u(e.states[t]),this.cards[t].hass=n();"hash"===e.entity&&window.addEventListener("location-changed",()=>this.updated(new Map))}update_state(){let e=void 0;switch(this._config.entity){case"user":e=this.hass&&this.hass.user&&this.hass.user.name||void 0;break;case"deviceID":case"browser":e=l;break;case"hash":e=location.hash.substr(1);break;default:e=this.hass.states[this._config.entity],e=e?e.state:void 0}void 0!==e&&this.cards.hasOwnProperty(e)||(e=this._config.default),this.state=e}updated(e){if(e.has("hass"))for(let e in this.cards)this.cards[e].hass=this.hass;e.has("state")||this.update_state()}render(){return o`
|
||||
<div id="root">
|
||||
${this.cards[this.state]}
|
||||
</div>
|
||||
`}getCardSize(){let e=1;for(let t in this.cards)this.cards[t]&&this.cards[t].getCardSize&&(e=Math.max(e,this.cards[t].getCardSize()));return e}})}]);
|
10
webpack.config.js
Normal file
10
webpack.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
entry: './src/main.js',
|
||||
mode: 'production',
|
||||
output: {
|
||||
filename: 'state-switch.js',
|
||||
path: path.resolve(__dirname)
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user