Add teachingbirds demo (#2516)
* Add teachingbirds demo * Remove some custom cards * Lint
BIN
demo/public/assets/teachingbirds/House_square.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
demo/public/assets/teachingbirds/Stefan_square.jpg
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
demo/public/assets/teachingbirds/background_square.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
demo/public/assets/teachingbirds/cleaning_square.jpg
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
demo/public/assets/teachingbirds/clothes_drying_square.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
demo/public/assets/teachingbirds/dryer_square.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
demo/public/assets/teachingbirds/folded_clothes_square.jpg
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
demo/public/assets/teachingbirds/guests_square.jpg
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
demo/public/assets/teachingbirds/isa_square.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
demo/public/assets/teachingbirds/laundry_clean_2_square.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
demo/public/assets/teachingbirds/laundry_running_square.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
demo/public/assets/teachingbirds/mailbox_bw_square.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
demo/public/assets/teachingbirds/mailbox_square.jpg
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
demo/public/assets/teachingbirds/meteogram.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
demo/public/assets/teachingbirds/radiator_off.jpg
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
demo/public/assets/teachingbirds/radiator_on.jpg
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
demo/public/assets/teachingbirds/roomba_bw_square.jpg
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
demo/public/assets/teachingbirds/roomba_square.jpg
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
demo/public/assets/teachingbirds/trash_bear_bw_square.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
demo/public/assets/teachingbirds/trash_square.jpg
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
demo/public/assets/teachingbirds/washer_square.jpg
Normal file
After Width: | Height: | Size: 20 KiB |
@ -3,6 +3,7 @@ import { Lovelace } from "../../../src/panels/lovelace/types";
|
|||||||
import { DemoConfig } from "./types";
|
import { DemoConfig } from "./types";
|
||||||
|
|
||||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||||
|
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||||
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
||||||
];
|
];
|
||||||
|
@ -4,7 +4,7 @@ import { demoEntitiesKernehed } from "./entities";
|
|||||||
|
|
||||||
export const demoKernehed: DemoConfig = {
|
export const demoKernehed: DemoConfig = {
|
||||||
authorName: "Kernehed",
|
authorName: "Kernehed",
|
||||||
authorUrl: "",
|
authorUrl: "https://github.com/kernehed",
|
||||||
name: "Hem",
|
name: "Hem",
|
||||||
lovelace: demoLovelaceKernehed,
|
lovelace: demoLovelaceKernehed,
|
||||||
entities: demoEntitiesKernehed,
|
entities: demoEntitiesKernehed,
|
||||||
|
12855
demo/src/configs/teachingbirds/entities.ts
Normal file
11
demo/src/configs/teachingbirds/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { DemoConfig } from "../types";
|
||||||
|
import { demoLovelaceTeachingbirds } from "./lovelace";
|
||||||
|
import { demoEntitiesTeachingbirds } from "./entities";
|
||||||
|
|
||||||
|
export const demoTeachingbirds: DemoConfig = {
|
||||||
|
authorName: "Isabella Gross Alström",
|
||||||
|
authorUrl: "https://github.com/isabellaalstrom/",
|
||||||
|
name: "Isa's mobile friendly LL",
|
||||||
|
lovelace: demoLovelaceTeachingbirds,
|
||||||
|
entities: demoEntitiesTeachingbirds,
|
||||||
|
};
|
1709
demo/src/configs/teachingbirds/lovelace.ts
Normal file
@ -5,6 +5,8 @@ import { mockLovelace } from "./stubs/lovelace";
|
|||||||
import { mockAuth } from "./stubs/auth";
|
import { mockAuth } from "./stubs/auth";
|
||||||
import { selectedDemoConfig } from "./configs/demo-configs";
|
import { selectedDemoConfig } from "./configs/demo-configs";
|
||||||
import { mockTranslations } from "./stubs/translations";
|
import { mockTranslations } from "./stubs/translations";
|
||||||
|
import { mockHistory } from "./stubs/history";
|
||||||
|
import { mockShoppingList } from "./stubs/shopping_list";
|
||||||
|
|
||||||
class HaDemo extends HomeAssistant {
|
class HaDemo extends HomeAssistant {
|
||||||
protected async _handleConnProm() {
|
protected async _handleConnProm() {
|
||||||
@ -16,6 +18,8 @@ class HaDemo extends HomeAssistant {
|
|||||||
mockLovelace(hass);
|
mockLovelace(hass);
|
||||||
mockAuth(hass);
|
mockAuth(hass);
|
||||||
mockTranslations(hass);
|
mockTranslations(hass);
|
||||||
|
mockHistory(hass);
|
||||||
|
mockShoppingList(hass);
|
||||||
selectedDemoConfig.then((conf) => hass.addEntities(conf.entities()));
|
selectedDemoConfig.then((conf) => hass.addEntities(conf.entities()));
|
||||||
|
|
||||||
// Taken from polymer/pwa-helpers. BSD-3 licensed
|
// Taken from polymer/pwa-helpers. BSD-3 licensed
|
||||||
|
5
demo/src/stubs/history.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockHistory = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockAPI(new RegExp("history/period/.+"), () => []);
|
||||||
|
};
|
44
demo/src/stubs/shopping_list.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
import { ShoppingListItem } from "../../../src/data/shopping-list";
|
||||||
|
|
||||||
|
let items: ShoppingListItem[] = [
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
name: "Milk",
|
||||||
|
complete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 13,
|
||||||
|
name: "Eggs",
|
||||||
|
complete: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
name: "Oranges",
|
||||||
|
complete: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const mockShoppingList = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("shopping_list/items", () => items);
|
||||||
|
hass.mockWS("shopping_list/items/add", (msg) => {
|
||||||
|
const item: ShoppingListItem = {
|
||||||
|
id: new Date().getTime(),
|
||||||
|
complete: false,
|
||||||
|
name: msg.name,
|
||||||
|
};
|
||||||
|
items.push(item);
|
||||||
|
hass.mockEvent("shopping_list_updated");
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
hass.mockWS("shopping_list/items/update", ({ type, item_id, ...updates }) => {
|
||||||
|
items = items.map((item) =>
|
||||||
|
item.id === item_id ? { ...item, ...updates } : item
|
||||||
|
);
|
||||||
|
hass.mockEvent("shopping_list_updated");
|
||||||
|
});
|
||||||
|
hass.mockWS("shopping_list/items/clear", () => {
|
||||||
|
items = items.filter((item) => !item.complete);
|
||||||
|
hass.mockEvent("shopping_list_updated");
|
||||||
|
});
|
||||||
|
};
|
@ -12,20 +12,20 @@ import { translationMetadata } from "../resources/translations-metadata";
|
|||||||
const ensureArray = <T>(val: T | T[]): T[] =>
|
const ensureArray = <T>(val: T | T[]): T[] =>
|
||||||
Array.isArray(val) ? val : [val];
|
Array.isArray(val) ? val : [val];
|
||||||
|
|
||||||
|
type RestCallback = (
|
||||||
|
method: string,
|
||||||
|
path: string,
|
||||||
|
parameters: { [key: string]: any } | undefined
|
||||||
|
) => any;
|
||||||
|
|
||||||
export interface MockHomeAssistant extends HomeAssistant {
|
export interface MockHomeAssistant extends HomeAssistant {
|
||||||
mockEntities: any;
|
mockEntities: any;
|
||||||
updateHass(obj: Partial<MockHomeAssistant>);
|
updateHass(obj: Partial<MockHomeAssistant>);
|
||||||
updateStates(newStates: HassEntities);
|
updateStates(newStates: HassEntities);
|
||||||
addEntities(entites: Entity | Entity[], replace?: boolean);
|
addEntities(entites: Entity | Entity[], replace?: boolean);
|
||||||
mockWS(type: string, callback: (msg: any) => any);
|
mockWS(type: string, callback: (msg: any) => any);
|
||||||
mockAPI(
|
mockAPI(path: string | RegExp, callback: RestCallback);
|
||||||
path: string,
|
mockEvent(event);
|
||||||
callback: (
|
|
||||||
method: string,
|
|
||||||
path: string,
|
|
||||||
parameters: { [key: string]: any }
|
|
||||||
) => any
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const provideHass = (
|
export const provideHass = (
|
||||||
@ -35,7 +35,10 @@ export const provideHass = (
|
|||||||
elements = ensureArray(elements);
|
elements = ensureArray(elements);
|
||||||
|
|
||||||
const wsCommands = {};
|
const wsCommands = {};
|
||||||
const restResponses = {};
|
const restResponses: Array<[string | RegExp, RestCallback]> = [];
|
||||||
|
const eventListeners: {
|
||||||
|
[event: string]: Array<(event) => void>;
|
||||||
|
} = {};
|
||||||
const entities = {};
|
const entities = {};
|
||||||
|
|
||||||
function updateHass(obj: Partial<MockHomeAssistant>) {
|
function updateHass(obj: Partial<MockHomeAssistant>) {
|
||||||
@ -67,12 +70,16 @@ export const provideHass = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockUpdateStateAPI(
|
function mockAPI(path, callback) {
|
||||||
|
restResponses.push([path, callback]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mockAPI(new RegExp("states/.+"), (
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
method,
|
method,
|
||||||
path,
|
path,
|
||||||
parameters
|
parameters
|
||||||
) {
|
) => {
|
||||||
const [domain, objectId] = path.substr(7).split(".", 2);
|
const [domain, objectId] = path.substr(7).split(".", 2);
|
||||||
if (!domain || !objectId) {
|
if (!domain || !objectId) {
|
||||||
return;
|
return;
|
||||||
@ -80,7 +87,7 @@ export const provideHass = (
|
|||||||
addEntities(
|
addEntities(
|
||||||
getEntity(domain, objectId, parameters.state, parameters.attributes)
|
getEntity(domain, objectId, parameters.state, parameters.attributes)
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
updateHass({
|
updateHass({
|
||||||
// Home Assistant properties
|
// Home Assistant properties
|
||||||
@ -97,10 +104,15 @@ export const provideHass = (
|
|||||||
callback,
|
callback,
|
||||||
event
|
event
|
||||||
) => {
|
) => {
|
||||||
// tslint:disable-next-line
|
if (!(event in eventListeners)) {
|
||||||
console.log("subscribeEvents", event);
|
eventListeners[event] = [];
|
||||||
// tslint:disable-next-line
|
}
|
||||||
return () => console.log("unsubscribeEvents", event);
|
eventListeners[event].push(callback);
|
||||||
|
return () => {
|
||||||
|
eventListeners[event] = eventListeners[event].filter(
|
||||||
|
(cb) => cb !== callback
|
||||||
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
socket: {
|
socket: {
|
||||||
readyState: WebSocket.OPEN,
|
readyState: WebSocket.OPEN,
|
||||||
@ -146,13 +158,12 @@ export const provideHass = (
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async callApi(method, path, parameters) {
|
async callApi(method, path, parameters) {
|
||||||
const callback =
|
const response = restResponses.find(([resPath]) =>
|
||||||
path.substr(0, 7) === "states/"
|
typeof resPath === "string" ? path === resPath : resPath.test(path)
|
||||||
? mockUpdateStateAPI
|
);
|
||||||
: restResponses[path];
|
|
||||||
|
|
||||||
return callback
|
return response
|
||||||
? callback(method, path, parameters)
|
? response[1](method, path, parameters)
|
||||||
: Promise.reject(`API Mock for ${path} is not implemented`);
|
: Promise.reject(`API Mock for ${path} is not implemented`);
|
||||||
},
|
},
|
||||||
fetchWithAuth: () => Promise.reject("Not implemented"),
|
fetchWithAuth: () => Promise.reject("Not implemented"),
|
||||||
@ -188,9 +199,11 @@ export const provideHass = (
|
|||||||
mockWS(type, callback) {
|
mockWS(type, callback) {
|
||||||
wsCommands[type] = callback;
|
wsCommands[type] = callback;
|
||||||
},
|
},
|
||||||
mockAPI(path, callback) {
|
mockAPI,
|
||||||
restResponses[path] = callback;
|
mockEvent(event) {
|
||||||
|
(eventListeners[event] || []).forEach((fn) => fn(event));
|
||||||
},
|
},
|
||||||
|
|
||||||
...overrideData,
|
...overrideData,
|
||||||
} as MockHomeAssistant);
|
} as MockHomeAssistant);
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
protected firstUpdated(): void {
|
protected firstUpdated(): void {
|
||||||
this._updated = true;
|
this._updated = true;
|
||||||
this._setBaseUnit();
|
this._setBaseUnit();
|
||||||
|
this.classList.add("init");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues): void {
|
protected updated(changedProps: PropertyValues): void {
|
||||||
@ -283,6 +284,8 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
border-radius: 0px 0px calc(var(--base-unit) * 2)
|
border-radius: 0px 0px calc(var(--base-unit) * 2)
|
||||||
calc(var(--base-unit) * 2);
|
calc(var(--base-unit) * 2);
|
||||||
transform-origin: center top;
|
transform-origin: center top;
|
||||||
|
}
|
||||||
|
.init .gauge-c {
|
||||||
transition: all 1.3s ease-in-out;
|
transition: all 1.3s ease-in-out;
|
||||||
}
|
}
|
||||||
.gauge-data {
|
.gauge-data {
|
||||||
@ -295,6 +298,8 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
top: calc(var(--base-unit) * 1.2);
|
top: calc(var(--base-unit) * 1.2);
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
.init .gauge-data {
|
||||||
transition: all 1s ease-out;
|
transition: all 1s ease-out;
|
||||||
}
|
}
|
||||||
.gauge-data #percent {
|
.gauge-data #percent {
|
||||||
|
@ -201,7 +201,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
let graph;
|
let graph;
|
||||||
|
|
||||||
if (this._config.graph === "line") {
|
if (stateObj && this._config.graph === "line") {
|
||||||
if (!stateObj.attributes.unit_of_measurement) {
|
if (!stateObj.attributes.unit_of_measurement) {
|
||||||
graph = html`
|
graph = html`
|
||||||
<div class="not-found">
|
<div class="not-found">
|
||||||
@ -308,7 +308,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard {
|
|||||||
endTime
|
endTime
|
||||||
);
|
);
|
||||||
|
|
||||||
if (stateHistory[0].length < 1) {
|
if (stateHistory.length < 1 || stateHistory[0].length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|