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
|
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.
|
> 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).
|
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
|
## 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
|
## State matching
|
||||||
| ---- | ---- | ------- | -----------
|
|
||||||
| 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
|
|
||||||
|
|
||||||
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.
|
If the `entity` parameter is set to an entity id, which card is displayed will depend on the state of that entity.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@ -143,16 +164,14 @@ If the `entity` parameter is set to `user`, which card is displayed will depend
|
|||||||
## Unknown user
|
## Unknown user
|
||||||
```
|
```
|
||||||
|
|
||||||
### browser
|
### deviceID
|
||||||
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.
|
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.
|
See [browser_mod](https://github.com/thomasloven/hass-browser_mod#devices) for a description on how deviceIDs work.
|
||||||
|
|
||||||
If the `default` parameter is **not** set, the default behavior will be to display a small card containing the browser ID.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
- type: custom:state-switch
|
- type: custom:state-switch
|
||||||
entity: browser
|
entity: deviceID
|
||||||
states:
|
states:
|
||||||
'9c2aaf6f-ed26e3c1':
|
'9c2aaf6f-ed26e3c1':
|
||||||
type: markdown
|
type: markdown
|
||||||
@ -163,3 +182,10 @@ If the `default` parameter is **not** set, the default behavior will be to displ
|
|||||||
content: >
|
content: >
|
||||||
Mobile
|
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(() => {
|
!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`
|
||||||
const cardTools = customElements.get('card-tools');
|
<div id="root">
|
||||||
class StateSwitch extends cardTools.LitElement {
|
${this.cards[this.state]}
|
||||||
|
</div>
|
||||||
setConfig(config) {
|
`}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}})}]);
|
||||||
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);
|
|
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