Add Arsaboo demo (#2534)
* Add Arsaboo demo * Resize images * Fixes * Mock more things * Simplify
BIN
demo/public/assets/arsaboo/floorplans/ecobee_blank.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
demo/public/assets/arsaboo/floorplans/main.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
demo/public/assets/arsaboo/floorplans/second.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
demo/public/assets/arsaboo/icons/Harmony.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
demo/public/assets/arsaboo/icons/abode_disabled.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
demo/public/assets/arsaboo/icons/abode_enabled.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
demo/public/assets/arsaboo/icons/automation_disabled.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
demo/public/assets/arsaboo/icons/automation_enabled.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_backyard_recording.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_backyard_streaming.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_driveway_recording.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_driveway_streaming.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_patio_recording.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_patio_streaming.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_porch_recording.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
demo/public/assets/arsaboo/icons/camera_porch_streaming.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
demo/public/assets/arsaboo/icons/ecobee_blank.png
Normal file
After Width: | Height: | Size: 69 KiB |
BIN
demo/public/assets/arsaboo/icons/garage_door_closed.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
demo/public/assets/arsaboo/icons/garage_door_open.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
demo/public/assets/arsaboo/icons/light_bulb_off.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
demo/public/assets/arsaboo/icons/light_bulb_on.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
demo/public/assets/arsaboo/icons/light_off.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
demo/public/assets/arsaboo/icons/light_on.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
demo/public/assets/arsaboo/icons/security_armed_red.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
demo/public/assets/arsaboo/icons/security_disarmed.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
demo/public/assets/arsaboo/icons/tv_disabled.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
demo/public/assets/arsaboo/icons/tv_enabled.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
demo/public/assets/arsaboo/icons/tv_off2.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
demo/public/assets/arsaboo/icons/tv_on2.png
Normal file
After Width: | Height: | Size: 805 B |
7529
demo/src/configs/arsaboo/entities.ts
Normal file
13
demo/src/configs/arsaboo/index.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { DemoConfig } from "../types";
|
||||
import { demoLovelaceArsaboo } from "./lovelace";
|
||||
import { demoEntitiesArsaboo } from "./entities";
|
||||
import { demoThemeArsaboo } from "./theme";
|
||||
|
||||
export const demoArsaboo: DemoConfig = {
|
||||
authorName: "Arsaboo",
|
||||
authorUrl: "https://github.com/arsaboo/homeassistant-config/",
|
||||
name: "ARS Home",
|
||||
lovelace: demoLovelaceArsaboo,
|
||||
entities: demoEntitiesArsaboo,
|
||||
theme: demoThemeArsaboo,
|
||||
};
|
2576
demo/src/configs/arsaboo/lovelace.ts
Normal file
1
demo/src/configs/arsaboo/theme.ts
Normal file
@ -0,0 +1 @@
|
||||
export const demoThemeArsaboo = () => ({});
|
@ -3,6 +3,7 @@ import { Lovelace } from "../../../src/panels/lovelace/types";
|
||||
import { DemoConfig } from "./types";
|
||||
|
||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
||||
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
||||
|
@ -10,6 +10,7 @@ import { mockShoppingList } from "./stubs/shopping_list";
|
||||
import { mockSystemLog } from "./stubs/system_log";
|
||||
import { mockTemplate } from "./stubs/template";
|
||||
import { mockEvents } from "./stubs/events";
|
||||
import { mockMediaPlayer } from "./stubs/media_player";
|
||||
|
||||
class HaDemo extends HomeAssistant {
|
||||
protected async _handleConnProm() {
|
||||
@ -30,6 +31,7 @@ class HaDemo extends HomeAssistant {
|
||||
mockSystemLog(hass);
|
||||
mockTemplate(hass);
|
||||
mockEvents(hass);
|
||||
mockMediaPlayer(hass);
|
||||
selectedDemoConfig.then((conf) => {
|
||||
hass.addEntities(conf.entities());
|
||||
if (conf.theme) {
|
||||
|
5
demo/src/stubs/media_player.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
|
||||
export const mockMediaPlayer = (hass: MockHomeAssistant) => {
|
||||
hass.mockWS("media_player_thumbnail", () => Promise.reject());
|
||||
};
|
@ -158,7 +158,7 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class$="[[computeBannerClasses(playerObj)]]">
|
||||
<div class$="[[computeBannerClasses(playerObj, _coverLoadError)]]">
|
||||
<div class="cover" id="cover"></div>
|
||||
|
||||
<div class="caption">
|
||||
@ -228,6 +228,10 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
computed: "computePlaybackControlIcon(playerObj)",
|
||||
},
|
||||
playbackPosition: Number,
|
||||
_coverLoadError: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -265,10 +269,11 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
type: "media_player_thumbnail",
|
||||
entity_id: playerObj.stateObj.entity_id,
|
||||
});
|
||||
this._coverLoadError = false;
|
||||
this.$.cover.style.backgroundImage = `url(data:${contentType};base64,${content})`;
|
||||
} catch (err) {
|
||||
this.$.cover.style.backgroundImage = "";
|
||||
this.$.cover.parentElement.classList.add("no-cover");
|
||||
this._coverLoadError = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,12 +281,15 @@ class HaMediaPlayerCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
|
||||
this.playbackPosition = this.playerObj.currentProgress;
|
||||
}
|
||||
|
||||
computeBannerClasses(playerObj) {
|
||||
computeBannerClasses(playerObj, coverLoadError) {
|
||||
var cls = "banner";
|
||||
|
||||
if (playerObj.isOff || playerObj.isIdle) {
|
||||
cls += " is-off no-cover";
|
||||
} else if (!playerObj.stateObj.attributes.entity_picture) {
|
||||
} else if (
|
||||
!playerObj.stateObj.attributes.entity_picture ||
|
||||
coverLoadError
|
||||
) {
|
||||
cls += " no-cover";
|
||||
} else if (playerObj.stateObj.attributes.media_content_type === "music") {
|
||||
cls += " content-type-music";
|
||||
|
@ -85,6 +85,8 @@ class LightEntity extends Entity {
|
||||
} else {
|
||||
this.handleService(domain, "turn_on", data);
|
||||
}
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -105,6 +107,8 @@ class ToggleEntity extends Entity {
|
||||
} else {
|
||||
this.handleService(domain, "turn_on", data);
|
||||
}
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,6 +128,8 @@ class LockEntity extends Entity {
|
||||
this.update("locked");
|
||||
} else if (service === "unlock") {
|
||||
this.update("unlocked");
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,6 +154,30 @@ class AlarmControlPanelEntity extends Entity {
|
||||
|
||||
if (serviceStateMap[service]) {
|
||||
this.update(serviceStateMap[service], this.baseAttributes);
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MediaPlayerEntity extends Entity {
|
||||
public async handleService(
|
||||
domain,
|
||||
service,
|
||||
// @ts-ignore
|
||||
data
|
||||
) {
|
||||
if (domain !== this.domain) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (service === "media_play_pause") {
|
||||
this.update(
|
||||
this.state === "playing" ? "paused" : "playing",
|
||||
this.attributes
|
||||
);
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,6 +197,8 @@ class CoverEntity extends Entity {
|
||||
this.update("open");
|
||||
} else if (service === "close_cover") {
|
||||
this.update("closing");
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,6 +214,8 @@ class ClimateEntity extends Entity {
|
||||
data.operation_mode === "heat" ? "heat" : data.operation_mode,
|
||||
{ ...this.attributes, operation_mode: data.operation_mode }
|
||||
);
|
||||
} else {
|
||||
super.handleService(domain, service, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,6 +245,7 @@ const TYPES = {
|
||||
input_boolean: ToggleEntity,
|
||||
light: LightEntity,
|
||||
lock: LockEntity,
|
||||
media_player: MediaPlayerEntity,
|
||||
switch: ToggleEntity,
|
||||
};
|
||||
|
||||
|
@ -103,6 +103,15 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
return html``;
|
||||
}
|
||||
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
|
||||
if (!stateObj) {
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="not-found">
|
||||
Entity not available: ${this._config.entity}
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
const mode = modeIcons[stateObj.attributes.operation_mode || ""]
|
||||
? stateObj.attributes.operation_mode!
|
||||
: "unknown-mode";
|
||||
@ -174,6 +183,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
|
||||
const stateObj = this.hass.states[this._config.entity] as ClimateEntity;
|
||||
|
||||
if (!stateObj) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this._jQuery &&
|
||||
// If jQuery changed, we just rendered in firstUpdated
|
||||
@ -355,6 +368,11 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
|
||||
--idle-color: #8a8a8a;
|
||||
--unknown-color: #bac;
|
||||
}
|
||||
.not-found {
|
||||
flex: 1;
|
||||
background-color: yellow;
|
||||
padding: 8px;
|
||||
}
|
||||
#root {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
@ -44,9 +44,10 @@ class HuiEntitiesToggle extends LitElement {
|
||||
${this.renderStyle()}
|
||||
<paper-toggle-button
|
||||
?checked="${
|
||||
this._toggleEntities!.some(
|
||||
(entityId) => this.hass!.states[entityId].state === "on"
|
||||
)
|
||||
this._toggleEntities!.some((entityId) => {
|
||||
const stateObj = this.hass!.states[entityId];
|
||||
return stateObj && stateObj.state === "on";
|
||||
})
|
||||
}"
|
||||
@change="${this._callService}"
|
||||
></paper-toggle-button>
|
||||
|
@ -420,11 +420,15 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
|
||||
this._loadResources(this.lovelace!.config.resources || []);
|
||||
// On config change, recreate the current view from scratch.
|
||||
force = true;
|
||||
// Recalculate to see if we need to adjust content area for tab bar
|
||||
fireEvent(this, "iron-resize");
|
||||
}
|
||||
|
||||
if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) {
|
||||
// On edit mode change, recreate the current view from scratch
|
||||
force = true;
|
||||
// Recalculate to see if we need to adjust content area for tab bar
|
||||
fireEvent(this, "iron-resize");
|
||||
}
|
||||
}
|
||||
|
||||
|