@ -18,6 +18,7 @@
|
|||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"__DEV__": false,
|
"__DEV__": false,
|
||||||
|
"__DEMO__": false,
|
||||||
"__BUILD__": false,
|
"__BUILD__": false,
|
||||||
"__VERSION__": false,
|
"__VERSION__": false,
|
||||||
"__STATIC_PATH__": false,
|
"__STATIC_PATH__": false,
|
||||||
|
BIN
demo/public/assets/jimpower/background-15.jpg
Normal file
After Width: | Height: | Size: 232 KiB |
BIN
demo/public/assets/jimpower/cardbackK.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
demo/public/assets/jimpower/home/bus_10.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
demo/public/assets/jimpower/home/git.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
demo/public/assets/jimpower/home/house_4.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
demo/public/assets/jimpower/home/james_10.jpg
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
demo/public/assets/jimpower/home/tina_4.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
demo/public/assets/jimpower/security/air_8.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
demo/public/assets/jimpower/security/alarm_3.jpg
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
demo/public/assets/jimpower/security/door_3.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
demo/public/assets/jimpower/security/leak_2.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
demo/public/assets/jimpower/security/motion_3.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
demo/public/assets/jimpower/security/smoke_4.jpg
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
demo/public/assets/jimpower/security/window_2.jpg
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
demo/public/assets/kernehed/bella.jpg
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
demo/public/assets/kernehed/camera.entre.jpg
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
demo/public/assets/kernehed/oscar.jpg
Normal file
After Width: | Height: | Size: 25 KiB |
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 |
23
demo/public/index.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||||
|
/>
|
||||||
|
<meta name="theme-color" content="#2157BC" />
|
||||||
|
<title>Home Assistant Demo</title>
|
||||||
|
<script src="./custom-elements-es5-adapter.js"></script>
|
||||||
|
<script src="./compatibility.js"></script>
|
||||||
|
<script src="./main.js" async></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Roboto, Noto, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
17
demo/script/build_demo
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Build the demo
|
||||||
|
|
||||||
|
# Stop on errors
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
OUTPUT_DIR=dist
|
||||||
|
|
||||||
|
rm -rf $OUTPUT_DIR
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
DEMO=1 ./node_modules/.bin/gulp build-translations gen-icons
|
||||||
|
cd demo
|
||||||
|
|
||||||
|
NODE_ENV=production ../node_modules/.bin/webpack -p --config webpack.config.js
|
13
demo/script/develop_demo
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Develop the demo
|
||||||
|
|
||||||
|
# Stop on errors
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
DEMO=1 ./node_modules/.bin/gulp build-translations gen-icons
|
||||||
|
cd demo
|
||||||
|
|
||||||
|
../node_modules/.bin/webpack-dev-server
|
26
demo/src/configs/demo-configs.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
import { Lovelace } from "../../../src/panels/lovelace/types";
|
||||||
|
import { DemoConfig } from "./types";
|
||||||
|
|
||||||
|
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||||
|
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||||
|
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||||
|
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
||||||
|
];
|
||||||
|
|
||||||
|
export let selectedDemoConfigIndex: number = 0;
|
||||||
|
export let selectedDemoConfig: Promise<DemoConfig> = demoConfigs[
|
||||||
|
selectedDemoConfigIndex
|
||||||
|
]();
|
||||||
|
|
||||||
|
export const setDemoConfig = async (
|
||||||
|
hass: MockHomeAssistant,
|
||||||
|
lovelace: Lovelace,
|
||||||
|
index: number
|
||||||
|
) => {
|
||||||
|
selectedDemoConfigIndex = index;
|
||||||
|
selectedDemoConfig = demoConfigs[index]();
|
||||||
|
const config = await selectedDemoConfig;
|
||||||
|
hass.addEntities(config.entities(), true);
|
||||||
|
lovelace.saveConfig(config.lovelace());
|
||||||
|
};
|
13271
demo/src/configs/jimpower/entities.ts
Normal file
11
demo/src/configs/jimpower/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { DemoConfig } from "../types";
|
||||||
|
import { demoLovelaceJimpower } from "./lovelace";
|
||||||
|
import { demoEntitiesJimpower } from "./entities";
|
||||||
|
|
||||||
|
export const demoJimpower: DemoConfig = {
|
||||||
|
authorName: "Jimpower",
|
||||||
|
authorUrl: "https://github.com/JamesMcCarthy79/Home-Assistant-Config",
|
||||||
|
name: "Kingia Castle",
|
||||||
|
lovelace: demoLovelaceJimpower,
|
||||||
|
entities: demoEntitiesJimpower,
|
||||||
|
};
|
1420
demo/src/configs/jimpower/lovelace.ts
Normal file
8761
demo/src/configs/kernehed/entities.ts
Normal file
11
demo/src/configs/kernehed/index.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { DemoConfig } from "../types";
|
||||||
|
import { demoLovelaceKernehed } from "./lovelace";
|
||||||
|
import { demoEntitiesKernehed } from "./entities";
|
||||||
|
|
||||||
|
export const demoKernehed: DemoConfig = {
|
||||||
|
authorName: "Kernehed",
|
||||||
|
authorUrl: "https://github.com/kernehed",
|
||||||
|
name: "Hem",
|
||||||
|
lovelace: demoLovelaceKernehed,
|
||||||
|
entities: demoEntitiesKernehed,
|
||||||
|
};
|
476
demo/src/configs/kernehed/lovelace.ts
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||||
|
|
||||||
|
export const demoLovelaceKernehed: () => LovelaceConfig = () => ({
|
||||||
|
name: "Hem",
|
||||||
|
resources: [
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/monster-card.js",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/mini-media-player-bundle.js?v=0.9.8",
|
||||||
|
// type: "module",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/slideshow-card.js?=1.1.0",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/fold-entity-row.js?v=3ae2c4",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/swipe-card/swipe-card.js?v=2.0.0",
|
||||||
|
// type: "module",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/upcoming-media-card/upcoming-media-card.js",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/tracker-card.js?v=0.1.5",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/card-tools.js?v=6ce5d0",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// url: "/local/custom-lovelace/krisinfo.js?=0.0.1",
|
||||||
|
// type: "js",
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{ type: "custom:ha-demo-card" },
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
image: "/assets/kernehed/oscar.jpg",
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "93%",
|
||||||
|
left: "20%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.oskar_devices",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "93%",
|
||||||
|
left: "90%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.battery_oskar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "93%",
|
||||||
|
left: "55%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.oskar_tid_till_hem",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "picture-elements",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "/assets/kernehed/bella.jpg",
|
||||||
|
elements: [
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "92%",
|
||||||
|
left: "20%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.bella_devices",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "92%",
|
||||||
|
left: "90%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.battery_bella",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
color: "white",
|
||||||
|
top: "92%",
|
||||||
|
left: "55%",
|
||||||
|
},
|
||||||
|
type: "state-label",
|
||||||
|
entity: "sensor.bella_tid_till_hem",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "picture-elements",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "horizontal-stack",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "vertical-stack",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"lock.polycontrol_danalock_v3_btze_locked",
|
||||||
|
"sensor.zwave_battery_front_door",
|
||||||
|
"alarm_control_panel.kernehed_manison",
|
||||||
|
"binary_sensor.dorrklockan",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Lock",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// filter: {
|
||||||
|
// exclude: [
|
||||||
|
// {
|
||||||
|
// state: "not_home",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// include: [
|
||||||
|
// {
|
||||||
|
// entity_id: "device_tracker.annasiphone",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "device_tracker.iphone_2",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// type: "custom:monster-card",
|
||||||
|
// card: {
|
||||||
|
// show_header_toggle: false,
|
||||||
|
// type: "entities",
|
||||||
|
// title: "G\u00e4ster",
|
||||||
|
// },
|
||||||
|
// show_empty: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// filter: {
|
||||||
|
// exclude: [
|
||||||
|
// {
|
||||||
|
// state: "Inget",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// state: "i.u.",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// include: [
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_al",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_alm",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_salg_vide",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_bjork",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_bok",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_ek",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_grabo",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_gras",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id: "sensor.pollen_hassel",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// type: "custom:monster-card",
|
||||||
|
// card: {
|
||||||
|
// show_header_toggle: false,
|
||||||
|
// type: "entities",
|
||||||
|
// title: "Pollenniv\u00e5er",
|
||||||
|
// },
|
||||||
|
// show_empty: false,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"switch.rest_julbelysning",
|
||||||
|
"binary_sensor.front_door_sensor",
|
||||||
|
"binary_sensor.unifi_camera",
|
||||||
|
"binary_sensor.back_door_sensor",
|
||||||
|
],
|
||||||
|
image: "/assets/kernehed/camera.entre.jpg",
|
||||||
|
type: "picture-glance",
|
||||||
|
title: "Entrance camera",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"input_select.christmas_pattern",
|
||||||
|
"input_select.christmas_palette",
|
||||||
|
],
|
||||||
|
type: "entities",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "vertical-stack",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// url: "https://embed.windy.com/embed2.html",
|
||||||
|
// type: "iframe",
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
{
|
||||||
|
name: "Laundry sensor",
|
||||||
|
entity: "binary_sensor.tvattstugan_motion_sensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pantry sensor",
|
||||||
|
entity: "binary_sensor.skafferiet_motion_sensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Basement sensor",
|
||||||
|
entity: "binary_sensor.kallaren_motion_sensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Stair sensor",
|
||||||
|
entity: "binary_sensor.trapp_motion_sensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bench sensor",
|
||||||
|
entity: "binary_sensor.banksensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Porch sensor",
|
||||||
|
entity: "binary_sensor.altan_motion_sensor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bathroom sensor",
|
||||||
|
entity: "binary_sensor.badrumssensor",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "glance",
|
||||||
|
show_state: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: ["sensor.oskar_bluetooth"],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Occupancy",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// filter: {
|
||||||
|
// exclude: [
|
||||||
|
// {
|
||||||
|
// state: false,
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// include: [
|
||||||
|
// {
|
||||||
|
// entity_id:
|
||||||
|
// "binary_sensor.fibaro_system_unknown_type0c02_id1003_sensor_2",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// entity_id:
|
||||||
|
// "binary_sensor.fibaro_system_unknown_type0c02_id1003_sensor_3",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
// type: "custom:monster-card",
|
||||||
|
// card: {
|
||||||
|
// show_header_toggle: false,
|
||||||
|
// type: "entities",
|
||||||
|
// title: "Brandvarnare",
|
||||||
|
// },
|
||||||
|
// show_empty: false,
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
type: "weather-forecast",
|
||||||
|
entity: "weather.smhi_vader",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// cards: [
|
||||||
|
// {
|
||||||
|
// max: 50,
|
||||||
|
// min: -50,
|
||||||
|
// type: "gauge",
|
||||||
|
// title: "\u00d6verv\u00e5ning",
|
||||||
|
// entity:
|
||||||
|
// "sensor.fibaro_system_unknown_type0c02_id1003_temperature",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// max: 50,
|
||||||
|
// min: -50,
|
||||||
|
// type: "gauge",
|
||||||
|
// title: "Entr\u00e9n",
|
||||||
|
// entity:
|
||||||
|
// "sensor.fibaro_system_unknown_type0c02_id1003_temperature_2",
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// max: 50,
|
||||||
|
// min: -50,
|
||||||
|
// type: "gauge",
|
||||||
|
// title: "K\u00e4llaren",
|
||||||
|
// entity:
|
||||||
|
// "sensor.philio_technology_corporation_phpat02beu_multisensor_2in1_temperature",
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// type: "custom:slideshow-card",
|
||||||
|
// arrow_color: "var(--primary-text-color)",
|
||||||
|
// arrow_opacity: 0.7,
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
title: "Home",
|
||||||
|
path: "home",
|
||||||
|
icon: "mdi:home",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"sensor.processor_use",
|
||||||
|
"sensor.memory_free",
|
||||||
|
"sensor.disk_free_home",
|
||||||
|
"sensor.last_boot",
|
||||||
|
"sensor.db_size",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "System",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"sensor.pi_hole_dns_queries_today",
|
||||||
|
"sensor.pi_hole_ads_blocked_today",
|
||||||
|
"sensor.pi_hole_dns_unique_clients",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Pi-Hole",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"sensor.plex",
|
||||||
|
"binary_sensor.gaming_pc",
|
||||||
|
"binary_sensor.server_1",
|
||||||
|
"binary_sensor.server_2",
|
||||||
|
"binary_sensor.windows_server",
|
||||||
|
"binary_sensor.teamspeak",
|
||||||
|
"binary_sensor.harmony_hub",
|
||||||
|
{
|
||||||
|
style: {
|
||||||
|
height: "1px",
|
||||||
|
width: "85%",
|
||||||
|
"margin-left": "auto",
|
||||||
|
background: "#62717b",
|
||||||
|
"margin-right": "auto",
|
||||||
|
},
|
||||||
|
type: "divider",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// items: ["sensor.uptime_router", "sensor.installerad_routeros"],
|
||||||
|
// head: {
|
||||||
|
// entity: "binary_sensor.router",
|
||||||
|
// },
|
||||||
|
// type: "custom:fold-entity-row",
|
||||||
|
// group_config: {
|
||||||
|
// icon: "mdi:router",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// items: [
|
||||||
|
// "sensor.uptime_router_server",
|
||||||
|
// "sensor.installerad_routeros_server",
|
||||||
|
// ],
|
||||||
|
// head: {
|
||||||
|
// entity: "binary_sensor.router_server",
|
||||||
|
// },
|
||||||
|
// type: "custom:fold-entity-row",
|
||||||
|
// group_config: {
|
||||||
|
// icon: "mdi:router",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Network",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"binary_sensor.ubiquiti_controller",
|
||||||
|
"binary_sensor.ubiquiti_switch",
|
||||||
|
"binary_sensor.ubiquiti_nvr",
|
||||||
|
"binary_sensor.entre_kamera",
|
||||||
|
// {
|
||||||
|
// items: ["sensor.uptime_ap_1"],
|
||||||
|
// head: {
|
||||||
|
// entity: "binary_sensor.accesspunkt_1",
|
||||||
|
// },
|
||||||
|
// type: "custom:fold-entity-row",
|
||||||
|
// group_config: {
|
||||||
|
// icon: "router-wireless",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// items: ["sensor.uptime_ap_2"],
|
||||||
|
// head: {
|
||||||
|
// entity: "binary_sensor.accesspunkt_2",
|
||||||
|
// },
|
||||||
|
// type: "custom:fold-entity-row",
|
||||||
|
// group_config: {
|
||||||
|
// icon: "router-wireless",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
"sensor.total_clients_wireless",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Ubiquiti",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"sensor.qbittorrent_up_speed",
|
||||||
|
"sensor.qbittorrent_down_speed",
|
||||||
|
"sensor.qbittorrent_status",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Bittorrent",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
entities: [
|
||||||
|
"sensor.speedtest_download",
|
||||||
|
"sensor.speedtest_upload",
|
||||||
|
"sensor.speedtest_ping",
|
||||||
|
],
|
||||||
|
show_header_toggle: false,
|
||||||
|
type: "entities",
|
||||||
|
title: "Bandbredd",
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// title: "Updater",
|
||||||
|
// type: "custom:tracker-card",
|
||||||
|
// trackers: [
|
||||||
|
// "sensor.custom_card_tracker",
|
||||||
|
// "sensor.custom_component_tracker",
|
||||||
|
// ],
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
title: "System & Network",
|
||||||
|
path: "system_network",
|
||||||
|
icon: "mdi:server-network",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
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
11
demo/src/configs/types.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { LovelaceConfig } from "../../../src/data/lovelace";
|
||||||
|
import { Entity } from "../../../src/fake_data/entity";
|
||||||
|
|
||||||
|
export interface DemoConfig {
|
||||||
|
index?: number;
|
||||||
|
name: string;
|
||||||
|
authorName: string;
|
||||||
|
authorUrl: string;
|
||||||
|
lovelace: () => LovelaceConfig;
|
||||||
|
entities: () => Entity[];
|
||||||
|
}
|
86
demo/src/custom-cards/card-modder.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { LitElement } from "lit-element";
|
||||||
|
import "./card-tools";
|
||||||
|
|
||||||
|
class CardModder extends LitElement {
|
||||||
|
setConfig(config) {
|
||||||
|
if (!window.cardTools)
|
||||||
|
throw new Error(
|
||||||
|
`Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools`
|
||||||
|
);
|
||||||
|
window.cardTools.checkVersion(0.2);
|
||||||
|
|
||||||
|
if (!config || !config.card) {
|
||||||
|
throw new Error("Card config incorrect");
|
||||||
|
}
|
||||||
|
if (Array.isArray(config.card)) {
|
||||||
|
throw new Error("It says 'card', not 'cardS'. Remove the dash.");
|
||||||
|
}
|
||||||
|
this._config = config;
|
||||||
|
this.card = window.cardTools.createCard(config.card);
|
||||||
|
this.templated = [];
|
||||||
|
this.attempts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return window.cardTools.litHtml`
|
||||||
|
<div id="root">${this.card}</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this._cardMod();
|
||||||
|
}
|
||||||
|
|
||||||
|
_cardMod() {
|
||||||
|
if (!this._config.style) return;
|
||||||
|
|
||||||
|
let target = null;
|
||||||
|
target = target || this.card.querySelector("ha-card");
|
||||||
|
target =
|
||||||
|
target ||
|
||||||
|
(this.card.shadowRoot && this.card.shadowRoot.querySelector("ha-card"));
|
||||||
|
target =
|
||||||
|
target ||
|
||||||
|
(this.card.firstChild &&
|
||||||
|
this.card.firstChild.shadowRoot &&
|
||||||
|
this.card.firstChild.shadowRoot.querySelector("ha-card"));
|
||||||
|
if (!target && !this.attempts)
|
||||||
|
// Try twice
|
||||||
|
setTimeout(() => this._cardMod(), 100);
|
||||||
|
this.attempts++;
|
||||||
|
target = target || this.card;
|
||||||
|
|
||||||
|
for (var k in this._config.style) {
|
||||||
|
if (window.cardTools.hasTemplate(this._config.style[k]))
|
||||||
|
this.templated.push(k);
|
||||||
|
target.style.setProperty(
|
||||||
|
k,
|
||||||
|
window.cardTools.parseTemplate(this._config.style[k])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
set hass(hass) {
|
||||||
|
if (this.card) this.card.hass = hass;
|
||||||
|
if (this.templated)
|
||||||
|
this.templated.forEach((k) => {
|
||||||
|
this.target.style.setProperty(
|
||||||
|
k,
|
||||||
|
window.cardTools.parseTemplate(this._config.style[k], "")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCardSize() {
|
||||||
|
if (this._config && this._config.report_size)
|
||||||
|
return this._config.report_size;
|
||||||
|
if (this.card)
|
||||||
|
return typeof this.card.getCardSize === "function"
|
||||||
|
? this.card.getCardSize()
|
||||||
|
: 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("card-modder", CardModder);
|
197
demo/src/custom-cards/card-tools.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
import { LitElement, html } from "lit-element";
|
||||||
|
|
||||||
|
if (!window.cardTools) {
|
||||||
|
const version = 0.2;
|
||||||
|
const CUSTOM_TYPE_PREFIX = "custom:";
|
||||||
|
|
||||||
|
let cardTools = {};
|
||||||
|
|
||||||
|
cardTools.v = version;
|
||||||
|
|
||||||
|
cardTools.checkVersion = (v) => {
|
||||||
|
if (version < v) {
|
||||||
|
throw new Error(
|
||||||
|
`Old version of card-tools found. Get the latest version of card-tools.js from https://github.com/thomasloven/lovelace-card-tools`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.LitElement = LitElement;
|
||||||
|
|
||||||
|
cardTools.litHtml = html;
|
||||||
|
|
||||||
|
cardTools.hass = () => {
|
||||||
|
return document.querySelector("home-assistant").hass;
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.fireEvent = (ev, detail) => {
|
||||||
|
ev = new Event(ev, {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: false,
|
||||||
|
composed: true,
|
||||||
|
});
|
||||||
|
ev.detail = detail || {};
|
||||||
|
document.querySelector("ha-demo").dispatchEvent(ev);
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.createThing = (thing, config) => {
|
||||||
|
const _createThing = (tag, config) => {
|
||||||
|
const element = document.createElement(tag);
|
||||||
|
try {
|
||||||
|
element.setConfig(config);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(tag, err);
|
||||||
|
return _createError(err.message, config);
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
const _createError = (error, config) => {
|
||||||
|
return _createThing("hui-error-card", {
|
||||||
|
type: "error",
|
||||||
|
error,
|
||||||
|
config,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!config || typeof config !== "object" || !config.type)
|
||||||
|
return _createError(`No ${thing} type configured`, config);
|
||||||
|
let tag = config.type;
|
||||||
|
if (config.error) {
|
||||||
|
const err = config.error;
|
||||||
|
delete config.error;
|
||||||
|
return _createError(err, config);
|
||||||
|
}
|
||||||
|
if (tag.startsWith(CUSTOM_TYPE_PREFIX))
|
||||||
|
tag = tag.substr(CUSTOM_TYPE_PREFIX.length);
|
||||||
|
else tag = `hui-${tag}-${thing}`;
|
||||||
|
|
||||||
|
if (customElements.get(tag)) return _createThing(tag, config);
|
||||||
|
|
||||||
|
// If element doesn't exist (yet) create an error
|
||||||
|
const element = _createError(
|
||||||
|
`Custom element doesn't exist: ${tag}.`,
|
||||||
|
config
|
||||||
|
);
|
||||||
|
element.style.display = "None";
|
||||||
|
const time = setTimeout(() => {
|
||||||
|
element.style.display = "";
|
||||||
|
}, 2000);
|
||||||
|
// Remove error if element is defined later
|
||||||
|
customElements.whenDefined(tag).then(() => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
cardTools.fireEvent("rebuild-view");
|
||||||
|
});
|
||||||
|
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.createCard = (config) => {
|
||||||
|
return cardTools.createThing("card", config);
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.createElement = (config) => {
|
||||||
|
return cardTools.createThing("element", config);
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.createEntityRow = (config) => {
|
||||||
|
const SPECIAL_TYPES = new Set([
|
||||||
|
"call-service",
|
||||||
|
"divider",
|
||||||
|
"section",
|
||||||
|
"weblink",
|
||||||
|
]);
|
||||||
|
const DEFAULT_ROWS = {
|
||||||
|
alert: "toggle",
|
||||||
|
automation: "toggle",
|
||||||
|
climate: "toggle",
|
||||||
|
cover: "cover",
|
||||||
|
fan: "toggle",
|
||||||
|
group: "group",
|
||||||
|
input_boolean: "toggle",
|
||||||
|
input_number: "input-number",
|
||||||
|
input_select: "input-select",
|
||||||
|
input_text: "input-text",
|
||||||
|
light: "toggle",
|
||||||
|
media_player: "media-player",
|
||||||
|
lock: "lock",
|
||||||
|
scene: "scene",
|
||||||
|
script: "script",
|
||||||
|
sensor: "sensor",
|
||||||
|
timer: "timer",
|
||||||
|
switch: "toggle",
|
||||||
|
vacuum: "toggle",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
!config ||
|
||||||
|
typeof config !== "object" ||
|
||||||
|
(!config.entity && !config.type)
|
||||||
|
) {
|
||||||
|
Object.assign(config, { error: "Invalid config given" });
|
||||||
|
return cardTools.createThing("", config);
|
||||||
|
}
|
||||||
|
|
||||||
|
const type = config.type || "default";
|
||||||
|
if (SPECIAL_TYPES.has(type) || type.startsWith(CUSTOM_TYPE_PREFIX))
|
||||||
|
return cardTools.createThing("row", config);
|
||||||
|
|
||||||
|
const domain = config.entity.split(".", 1)[0];
|
||||||
|
Object.assign(config, { type: DEFAULT_ROWS[domain] || "text" });
|
||||||
|
return cardTools.createThing("entity-row", config);
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.deviceID = (() => {
|
||||||
|
const ID_STORAGE_KEY = "lovelace-player-device-id";
|
||||||
|
if (window["fully"] && typeof fully.getDeviceId === "function")
|
||||||
|
return fully.getDeviceId();
|
||||||
|
if (!localStorage[ID_STORAGE_KEY]) {
|
||||||
|
const s4 = () => {
|
||||||
|
return Math.floor((1 + Math.random()) * 100000)
|
||||||
|
.toString(16)
|
||||||
|
.substring(1);
|
||||||
|
};
|
||||||
|
localStorage[ID_STORAGE_KEY] = `${s4()}${s4()}-${s4()}${s4()}`;
|
||||||
|
}
|
||||||
|
return localStorage[ID_STORAGE_KEY];
|
||||||
|
})();
|
||||||
|
|
||||||
|
cardTools.moreInfo = (entity) => {
|
||||||
|
cardTools.fireEvent("hass-more-info", { entityId: entity });
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.longpress = (element) => {
|
||||||
|
customElements.whenDefined("long-press").then(() => {
|
||||||
|
const longpress = document.body.querySelector("long-press");
|
||||||
|
longpress.bind(element);
|
||||||
|
});
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.hasTemplate = (text) => {
|
||||||
|
return /\[\[\s+.*\s+\]\]/.test(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
cardTools.parseTemplate = (text, error) => {
|
||||||
|
const _parse = (str) => {
|
||||||
|
try {
|
||||||
|
str = str.replace(/^\[\[\s+|\s+\]\]$/g, "");
|
||||||
|
const parts = str.split(".");
|
||||||
|
let v = cardTools.hass().states[`${parts[0]}.${parts[1]}`];
|
||||||
|
parts.shift();
|
||||||
|
parts.shift();
|
||||||
|
parts.forEach((item) => (v = v[item]));
|
||||||
|
return v;
|
||||||
|
} catch (err) {
|
||||||
|
return error || `[[ Template matching failed ${str} ]]`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
text = text.replace(/(\[\[\s.*?\s\]\])/g, (str, p1, offset, s) =>
|
||||||
|
_parse(str)
|
||||||
|
);
|
||||||
|
return text;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.cardTools = cardTools;
|
||||||
|
cardTools.fireEvent("rebuild-view");
|
||||||
|
}
|
139
demo/src/custom-cards/ha-demo-card.ts
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import { LitElement, html, CSSResult, css } from "lit-element";
|
||||||
|
import { until } from "lit-html/directives/until";
|
||||||
|
import "@polymer/paper-icon-button";
|
||||||
|
import "../../../src/components/ha-card";
|
||||||
|
import { LovelaceCard, Lovelace } from "../../../src/panels/lovelace/types";
|
||||||
|
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
import {
|
||||||
|
demoConfigs,
|
||||||
|
selectedDemoConfig,
|
||||||
|
setDemoConfig,
|
||||||
|
selectedDemoConfigIndex,
|
||||||
|
} from "../configs/demo-configs";
|
||||||
|
|
||||||
|
export class HADemoCard extends LitElement implements LovelaceCard {
|
||||||
|
public lovelace?: Lovelace;
|
||||||
|
public hass?: MockHomeAssistant;
|
||||||
|
|
||||||
|
public getCardSize() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setConfig(
|
||||||
|
// @ts-ignore
|
||||||
|
config: LovelaceCardConfig
|
||||||
|
// tslint:disable-next-line:no-empty
|
||||||
|
) {}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
return html`
|
||||||
|
<ha-card header="Home Assistant Demo Switcher">
|
||||||
|
<div class="picker">
|
||||||
|
<paper-icon-button
|
||||||
|
@click=${this._prevConfig}
|
||||||
|
icon="hass:chevron-right"
|
||||||
|
style="transform: rotate(180deg)"
|
||||||
|
></paper-icon-button>
|
||||||
|
<div>
|
||||||
|
${
|
||||||
|
until(
|
||||||
|
selectedDemoConfig.then(
|
||||||
|
(conf) => html`
|
||||||
|
${conf.name}
|
||||||
|
<small>
|
||||||
|
by
|
||||||
|
<a target="_blank" href="${conf.authorUrl}">
|
||||||
|
${conf.authorName}
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
`
|
||||||
|
),
|
||||||
|
""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<paper-icon-button
|
||||||
|
@click=${this._nextConfig}
|
||||||
|
icon="hass:chevron-right"
|
||||||
|
></paper-icon-button>
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _prevConfig() {
|
||||||
|
this._updateConfig(
|
||||||
|
selectedDemoConfigIndex > 0
|
||||||
|
? selectedDemoConfigIndex - 1
|
||||||
|
: demoConfigs.length - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _nextConfig() {
|
||||||
|
this._updateConfig(
|
||||||
|
selectedDemoConfigIndex < demoConfigs.length - 1
|
||||||
|
? selectedDemoConfigIndex + 1
|
||||||
|
: 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateConfig(index: number) {
|
||||||
|
setDemoConfig(this.hass!, this.lovelace!, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [
|
||||||
|
css`
|
||||||
|
.content {
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding: 16px 16px 16px 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child {
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child {
|
||||||
|
margin-bottom: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker div {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker small {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-demo-card": HADemoCard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("ha-demo-card", HADemoCard);
|
19
demo/src/entrypoint.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import "@polymer/paper-styles/typography";
|
||||||
|
import "@polymer/polymer/lib/elements/dom-if";
|
||||||
|
import "@polymer/polymer/lib/elements/dom-repeat";
|
||||||
|
|
||||||
|
import "../../src/resources/hass-icons";
|
||||||
|
import "../../src/resources/ha-style";
|
||||||
|
import "../../src/resources/roboto";
|
||||||
|
import "../../src/components/ha-iconset-svg";
|
||||||
|
|
||||||
|
import "./ha-demo";
|
||||||
|
|
||||||
|
/* polyfill for paper-dropdown */
|
||||||
|
setTimeout(
|
||||||
|
() =>
|
||||||
|
import(/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min"),
|
||||||
|
1000
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.appendChild(document.createElement("ha-demo"));
|
80
demo/src/ha-demo.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import { HomeAssistant } from "../../src/layouts/app/home-assistant";
|
||||||
|
import { provideHass } from "../../src/fake_data/provide_hass";
|
||||||
|
import { navigate } from "../../src/common/navigate";
|
||||||
|
import { mockLovelace } from "./stubs/lovelace";
|
||||||
|
import { mockAuth } from "./stubs/auth";
|
||||||
|
import { selectedDemoConfig } from "./configs/demo-configs";
|
||||||
|
import { mockTranslations } from "./stubs/translations";
|
||||||
|
import { mockHistory } from "./stubs/history";
|
||||||
|
import { mockShoppingList } from "./stubs/shopping_list";
|
||||||
|
|
||||||
|
class HaDemo extends HomeAssistant {
|
||||||
|
protected async _handleConnProm() {
|
||||||
|
const initial: Partial<HomeAssistant> = {
|
||||||
|
panelUrl: (this as any).panelUrl,
|
||||||
|
};
|
||||||
|
|
||||||
|
const hass = provideHass(this, initial);
|
||||||
|
mockLovelace(hass);
|
||||||
|
mockAuth(hass);
|
||||||
|
mockTranslations(hass);
|
||||||
|
mockHistory(hass);
|
||||||
|
mockShoppingList(hass);
|
||||||
|
selectedDemoConfig.then((conf) => hass.addEntities(conf.entities()));
|
||||||
|
|
||||||
|
// Taken from polymer/pwa-helpers. BSD-3 licensed
|
||||||
|
document.body.addEventListener(
|
||||||
|
"click",
|
||||||
|
(e) => {
|
||||||
|
if (
|
||||||
|
e.defaultPrevented ||
|
||||||
|
e.button !== 0 ||
|
||||||
|
e.metaKey ||
|
||||||
|
e.ctrlKey ||
|
||||||
|
e.shiftKey
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const anchor = e
|
||||||
|
.composedPath()
|
||||||
|
.filter((n) => (n as HTMLElement).tagName === "A")[0] as
|
||||||
|
| HTMLAnchorElement
|
||||||
|
| undefined;
|
||||||
|
if (
|
||||||
|
!anchor ||
|
||||||
|
anchor.target ||
|
||||||
|
anchor.hasAttribute("download") ||
|
||||||
|
anchor.getAttribute("rel") === "external"
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let href = anchor.href;
|
||||||
|
if (!href || href.indexOf("mailto:") !== -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const location = window.location;
|
||||||
|
const origin =
|
||||||
|
location.origin || location.protocol + "//" + location.host;
|
||||||
|
if (href.indexOf(origin) !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
href = href.substr(origin.length);
|
||||||
|
|
||||||
|
if (href === "#") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
navigate(this as any, href);
|
||||||
|
},
|
||||||
|
{ capture: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
(this as any).hassConnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("ha-demo", HaDemo);
|
6
demo/src/stubs/auth.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockAuth = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("config/auth/list", () => []);
|
||||||
|
hass.mockWS("auth/refresh_tokens", () => []);
|
||||||
|
};
|
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/.+"), () => []);
|
||||||
|
};
|
28
demo/src/stubs/lovelace.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import "../custom-cards/ha-demo-card";
|
||||||
|
// Not duplicate, one is for typing.
|
||||||
|
// tslint:disable-next-line
|
||||||
|
import { HADemoCard } from "../custom-cards/ha-demo-card";
|
||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
import { HUIView } from "../../../src/panels/lovelace/hui-view";
|
||||||
|
import { selectedDemoConfig } from "../configs/demo-configs";
|
||||||
|
|
||||||
|
export const mockLovelace = (hass: MockHomeAssistant) => {
|
||||||
|
selectedDemoConfig.then((config) => hass.addEntities(config.entities()));
|
||||||
|
|
||||||
|
hass.mockWS("lovelace/config", () =>
|
||||||
|
selectedDemoConfig.then((config) => config.lovelace())
|
||||||
|
);
|
||||||
|
|
||||||
|
hass.mockWS("lovelace/config/save", () => Promise.resolve());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Patch HUI-VIEW to make the lovelace object available to the demo card
|
||||||
|
const oldCreateCard = HUIView.prototype.createCardElement;
|
||||||
|
|
||||||
|
HUIView.prototype.createCardElement = function(config) {
|
||||||
|
const el = oldCreateCard.call(this, config);
|
||||||
|
if (el.tagName === "HA-DEMO-CARD") {
|
||||||
|
(el as HADemoCard).lovelace = this.lovelace;
|
||||||
|
}
|
||||||
|
return el;
|
||||||
|
};
|
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");
|
||||||
|
});
|
||||||
|
};
|
474
demo/src/stubs/translations.ts
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("frontend/get_translations", () => ({
|
||||||
|
resources: {
|
||||||
|
"component.lifx.config.abort.no_devices_found":
|
||||||
|
"No LIFX devices found on the network.",
|
||||||
|
"component.lifx.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of LIFX is possible.",
|
||||||
|
"component.lifx.config.step.confirm.description":
|
||||||
|
"Do you want to set up LIFX?",
|
||||||
|
"component.lifx.config.step.confirm.title": "LIFX",
|
||||||
|
"component.lifx.config.title": "LIFX",
|
||||||
|
"component.hangouts.config.abort.already_configured":
|
||||||
|
"Google Hangouts is already configured",
|
||||||
|
"component.hangouts.config.abort.unknown": "Unknown error occurred.",
|
||||||
|
"component.hangouts.config.error.invalid_2fa":
|
||||||
|
"Invalid 2 Factor Authentication, please try again.",
|
||||||
|
"component.hangouts.config.error.invalid_2fa_method":
|
||||||
|
"Invalid 2FA Method (Verify on Phone).",
|
||||||
|
"component.hangouts.config.error.invalid_login":
|
||||||
|
"Invalid Login, please try again.",
|
||||||
|
"component.hangouts.config.step.2fa.data.2fa": "2FA Pin",
|
||||||
|
"component.hangouts.config.step.2fa.title": "2-Factor-Authentication",
|
||||||
|
"component.hangouts.config.step.user.data.email": "E-Mail Address",
|
||||||
|
"component.hangouts.config.step.user.data.password": "Password",
|
||||||
|
"component.hangouts.config.step.user.title": "Google Hangouts Login",
|
||||||
|
"component.hangouts.config.title": "Google Hangouts",
|
||||||
|
"component.rainmachine.config.error.identifier_exists":
|
||||||
|
"Account already registered",
|
||||||
|
"component.rainmachine.config.error.invalid_credentials":
|
||||||
|
"Invalid credentials",
|
||||||
|
"component.rainmachine.config.step.user.data.ip_address":
|
||||||
|
"Hostname or IP Address",
|
||||||
|
"component.rainmachine.config.step.user.data.password": "Password",
|
||||||
|
"component.rainmachine.config.step.user.data.port": "Port",
|
||||||
|
"component.rainmachine.config.step.user.title":
|
||||||
|
"Fill in your information",
|
||||||
|
"component.rainmachine.config.title": "RainMachine",
|
||||||
|
"component.homematicip_cloud.config.abort.already_configured":
|
||||||
|
"Access point is already configured",
|
||||||
|
"component.homematicip_cloud.config.abort.connection_aborted":
|
||||||
|
"Could not connect to HMIP server",
|
||||||
|
"component.homematicip_cloud.config.abort.unknown":
|
||||||
|
"Unknown error occurred.",
|
||||||
|
"component.homematicip_cloud.config.error.invalid_pin":
|
||||||
|
"Invalid PIN, please try again.",
|
||||||
|
"component.homematicip_cloud.config.error.press_the_button":
|
||||||
|
"Please press the blue button.",
|
||||||
|
"component.homematicip_cloud.config.error.register_failed":
|
||||||
|
"Failed to register, please try again.",
|
||||||
|
"component.homematicip_cloud.config.error.timeout_button":
|
||||||
|
"Blue button press timeout, please try again.",
|
||||||
|
"component.homematicip_cloud.config.step.init.data.hapid":
|
||||||
|
"Access point ID (SGTIN)",
|
||||||
|
"component.homematicip_cloud.config.step.init.data.name":
|
||||||
|
"Name (optional, used as name prefix for all devices)",
|
||||||
|
"component.homematicip_cloud.config.step.init.data.pin":
|
||||||
|
"Pin Code (optional)",
|
||||||
|
"component.homematicip_cloud.config.step.init.title":
|
||||||
|
"Pick HomematicIP Access point",
|
||||||
|
"component.homematicip_cloud.config.step.link.description":
|
||||||
|
"Press the blue button on the access point and the submit button to register HomematicIP with Home Assistant.\n\n",
|
||||||
|
"component.homematicip_cloud.config.step.link.title": "Link Access point",
|
||||||
|
"component.homematicip_cloud.config.title": "HomematicIP Cloud",
|
||||||
|
"component.daikin.config.abort.already_configured":
|
||||||
|
"Device is already configured",
|
||||||
|
"component.daikin.config.abort.device_fail":
|
||||||
|
"Unexpected error creating device.",
|
||||||
|
"component.daikin.config.abort.device_timeout":
|
||||||
|
"Timeout connecting to the device.",
|
||||||
|
"component.daikin.config.step.user.data.host": "Host",
|
||||||
|
"component.daikin.config.step.user.description":
|
||||||
|
"Enter IP address of your Daikin AC.",
|
||||||
|
"component.daikin.config.step.user.title": "Configure Daikin AC",
|
||||||
|
"component.daikin.config.title": "Daikin AC",
|
||||||
|
"component.unifi.config.abort.already_configured":
|
||||||
|
"Controller site is already configured",
|
||||||
|
"component.unifi.config.abort.user_privilege":
|
||||||
|
"User needs to be administrator",
|
||||||
|
"component.unifi.config.error.faulty_credentials": "Bad user credentials",
|
||||||
|
"component.unifi.config.error.service_unavailable":
|
||||||
|
"No service available",
|
||||||
|
"component.unifi.config.step.user.data.host": "Host",
|
||||||
|
"component.unifi.config.step.user.data.password": "Password",
|
||||||
|
"component.unifi.config.step.user.data.port": "Port",
|
||||||
|
"component.unifi.config.step.user.data.site": "Site ID",
|
||||||
|
"component.unifi.config.step.user.data.username": "User name",
|
||||||
|
"component.unifi.config.step.user.data.verify_ssl":
|
||||||
|
"Controller using proper certificate",
|
||||||
|
"component.unifi.config.step.user.title": "Set up UniFi Controller",
|
||||||
|
"component.unifi.config.title": "UniFi Controller",
|
||||||
|
"component.nest.config.abort.already_setup":
|
||||||
|
"You can only configure a single Nest account.",
|
||||||
|
"component.nest.config.abort.authorize_url_fail":
|
||||||
|
"Unknown error generating an authorize url.",
|
||||||
|
"component.nest.config.abort.authorize_url_timeout":
|
||||||
|
"Timeout generating authorize url.",
|
||||||
|
"component.nest.config.abort.no_flows":
|
||||||
|
"You need to configure Nest before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/nest/).",
|
||||||
|
"component.nest.config.error.internal_error":
|
||||||
|
"Internal error validating code",
|
||||||
|
"component.nest.config.error.invalid_code": "Invalid code",
|
||||||
|
"component.nest.config.error.timeout": "Timeout validating code",
|
||||||
|
"component.nest.config.error.unknown": "Unknown error validating code",
|
||||||
|
"component.nest.config.step.init.data.flow_impl": "Provider",
|
||||||
|
"component.nest.config.step.init.description":
|
||||||
|
"Pick via which authentication provider you want to authenticate with Nest.",
|
||||||
|
"component.nest.config.step.init.title": "Authentication Provider",
|
||||||
|
"component.nest.config.step.link.data.code": "Pin code",
|
||||||
|
"component.nest.config.step.link.description":
|
||||||
|
"To link your Nest account, [authorize your account]({url}).\n\nAfter authorization, copy-paste the provided pin code below.",
|
||||||
|
"component.nest.config.step.link.title": "Link Nest Account",
|
||||||
|
"component.nest.config.title": "Nest",
|
||||||
|
"component.mailgun.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive Mailgun messages.",
|
||||||
|
"component.mailgun.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.mailgun.config.create_entry.default":
|
||||||
|
"To send events to Home Assistant, you will need to setup [Webhooks with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.",
|
||||||
|
"component.mailgun.config.step.user.description":
|
||||||
|
"Are you sure you want to set up Mailgun?",
|
||||||
|
"component.mailgun.config.step.user.title": "Set up the Mailgun Webhook",
|
||||||
|
"component.mailgun.config.title": "Mailgun",
|
||||||
|
"component.tellduslive.config.abort.already_setup":
|
||||||
|
"TelldusLive is already configured",
|
||||||
|
"component.tellduslive.config.abort.authorize_url_fail":
|
||||||
|
"Unknown error generating an authorize url.",
|
||||||
|
"component.tellduslive.config.abort.authorize_url_timeout":
|
||||||
|
"Timeout generating authorize url.",
|
||||||
|
"component.tellduslive.config.abort.unknown": "Unknown error occurred",
|
||||||
|
"component.tellduslive.config.error.auth_error":
|
||||||
|
"Authentication error, please try again",
|
||||||
|
"component.tellduslive.config.step.auth.description":
|
||||||
|
"To link your TelldusLive account:\n 1. Click the link below\n 2. Login to Telldus Live\n 3. Authorize **{app_name}** (click **Yes**).\n 4. Come back here and click **SUBMIT**.\n\n [Link TelldusLive account]({auth_url})",
|
||||||
|
"component.tellduslive.config.step.auth.title":
|
||||||
|
"Authenticate against TelldusLive",
|
||||||
|
"component.tellduslive.config.step.user.data.host": "Host",
|
||||||
|
"component.tellduslive.config.step.user.title": "Pick endpoint.",
|
||||||
|
"component.tellduslive.config.title": "Telldus Live",
|
||||||
|
"component.esphome.config.abort.already_configured":
|
||||||
|
"ESP is already configured",
|
||||||
|
"component.esphome.config.error.connection_error":
|
||||||
|
"Can't connect to ESP. Please make sure your YAML file contains an 'api:' line.",
|
||||||
|
"component.esphome.config.error.invalid_password": "Invalid password!",
|
||||||
|
"component.esphome.config.error.resolve_error":
|
||||||
|
"Can't resolve address of the ESP. If this error persists, please set a static IP address: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips",
|
||||||
|
"component.esphome.config.step.authenticate.data.password": "Password",
|
||||||
|
"component.esphome.config.step.authenticate.description":
|
||||||
|
"Please enter the password you set in your configuration.",
|
||||||
|
"component.esphome.config.step.authenticate.title": "Enter Password",
|
||||||
|
"component.esphome.config.step.user.data.host": "Host",
|
||||||
|
"component.esphome.config.step.user.data.port": "Port",
|
||||||
|
"component.esphome.config.step.user.description":
|
||||||
|
"Please enter connection settings of your [ESPHome](https://esphomelib.com/) node.",
|
||||||
|
"component.esphome.config.step.user.title": "ESPHome",
|
||||||
|
"component.esphome.config.title": "ESPHome",
|
||||||
|
"component.luftdaten.config.error.communication_error":
|
||||||
|
"Unable to communicate with the Luftdaten API",
|
||||||
|
"component.luftdaten.config.error.invalid_sensor":
|
||||||
|
"Sensor not available or invalid",
|
||||||
|
"component.luftdaten.config.error.sensor_exists":
|
||||||
|
"Sensor already registered",
|
||||||
|
"component.luftdaten.config.step.user.data.show_on_map": "Show on map",
|
||||||
|
"component.luftdaten.config.step.user.data.station_id":
|
||||||
|
"Luftdaten Sensor ID",
|
||||||
|
"component.luftdaten.config.step.user.title": "Define Luftdaten",
|
||||||
|
"component.luftdaten.config.title": "Luftdaten",
|
||||||
|
"component.upnp.config.abort.already_configured":
|
||||||
|
"UPnP/IGD is already configured",
|
||||||
|
"component.upnp.config.abort.incomplete_device":
|
||||||
|
"Ignoring incomplete UPnP device",
|
||||||
|
"component.upnp.config.abort.no_devices_discovered":
|
||||||
|
"No UPnP/IGDs discovered",
|
||||||
|
"component.upnp.config.abort.no_devices_found":
|
||||||
|
"No UPnP/IGD devices found on the network.",
|
||||||
|
"component.upnp.config.abort.no_sensors_or_port_mapping":
|
||||||
|
"Enable at least sensors or port mapping",
|
||||||
|
"component.upnp.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of UPnP/IGD is necessary.",
|
||||||
|
"component.upnp.config.step.confirm.description":
|
||||||
|
"Do you want to set up UPnP/IGD?",
|
||||||
|
"component.upnp.config.step.confirm.title": "UPnP/IGD",
|
||||||
|
"component.upnp.config.step.init.title": "UPnP/IGD",
|
||||||
|
"component.upnp.config.step.user.data.enable_port_mapping":
|
||||||
|
"Enable port mapping for Home Assistant",
|
||||||
|
"component.upnp.config.step.user.data.enable_sensors":
|
||||||
|
"Add traffic sensors",
|
||||||
|
"component.upnp.config.step.user.data.igd": "UPnP/IGD",
|
||||||
|
"component.upnp.config.step.user.title":
|
||||||
|
"Configuration options for the UPnP/IGD",
|
||||||
|
"component.upnp.config.title": "UPnP/IGD",
|
||||||
|
"component.point.config.abort.already_setup":
|
||||||
|
"You can only configure a Point account.",
|
||||||
|
"component.point.config.abort.authorize_url_fail":
|
||||||
|
"Unknown error generating an authorize url.",
|
||||||
|
"component.point.config.abort.authorize_url_timeout":
|
||||||
|
"Timeout generating authorize url.",
|
||||||
|
"component.point.config.abort.external_setup":
|
||||||
|
"Point successfully configured from another flow.",
|
||||||
|
"component.point.config.abort.no_flows":
|
||||||
|
"You need to configure Point before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/components/point/).",
|
||||||
|
"component.point.config.create_entry.default":
|
||||||
|
"Successfully authenticated with Minut for your Point device(s)",
|
||||||
|
"component.point.config.error.follow_link":
|
||||||
|
"Please follow the link and authenticate before pressing Submit",
|
||||||
|
"component.point.config.error.no_token": "Not authenticated with Minut",
|
||||||
|
"component.point.config.step.auth.description":
|
||||||
|
"Please follow the link below and <b>Accept</b> access to your Minut account, then come back and press <b>Submit</b> below.\n\n[Link]({authorization_url})",
|
||||||
|
"component.point.config.step.auth.title": "Authenticate Point",
|
||||||
|
"component.point.config.step.user.data.flow_impl": "Provider",
|
||||||
|
"component.point.config.step.user.description":
|
||||||
|
"Pick via which authentication provider you want to authenticate with Point.",
|
||||||
|
"component.point.config.step.user.title": "Authentication Provider",
|
||||||
|
"component.point.config.title": "Minut Point",
|
||||||
|
"component.auth.mfa_setup.notify.abort.no_available_service":
|
||||||
|
"No notification services available.",
|
||||||
|
"component.auth.mfa_setup.notify.error.invalid_code":
|
||||||
|
"Invalid code, please try again.",
|
||||||
|
"component.auth.mfa_setup.notify.step.init.description":
|
||||||
|
"Please select one of the notification services:",
|
||||||
|
"component.auth.mfa_setup.notify.step.init.title":
|
||||||
|
"Set up one-time password delivered by notify component",
|
||||||
|
"component.auth.mfa_setup.notify.step.setup.description":
|
||||||
|
"A one-time password has been sent via **notify.{notify_service}**. Please enter it below:",
|
||||||
|
"component.auth.mfa_setup.notify.step.setup.title": "Verify setup",
|
||||||
|
"component.auth.mfa_setup.notify.title": "Notify One-Time Password",
|
||||||
|
"component.auth.mfa_setup.totp.error.invalid_code":
|
||||||
|
"Invalid code, please try again. If you get this error consistently, please make sure the clock of your Home Assistant system is accurate.",
|
||||||
|
"component.auth.mfa_setup.totp.step.init.description":
|
||||||
|
"To activate two factor authentication using time-based one-time passwords, scan the QR code with your authentication app. If you don't have one, we recommend either [Google Authenticator](https://support.google.com/accounts/answer/1066447) or [Authy](https://authy.com/).\n\n{qr_code}\n\nAfter scanning the code, enter the six digit code from your app to verify the setup. If you have problems scanning the QR code, do a manual setup with code **`{code}`**.",
|
||||||
|
"component.auth.mfa_setup.totp.step.init.title":
|
||||||
|
"Set up two-factor authentication using TOTP",
|
||||||
|
"component.auth.mfa_setup.totp.title": "TOTP",
|
||||||
|
"component.emulated_roku.config.abort.name_exists": "Name already exists",
|
||||||
|
"component.emulated_roku.config.step.user.data.advertise_ip":
|
||||||
|
"Advertise IP",
|
||||||
|
"component.emulated_roku.config.step.user.data.advertise_port":
|
||||||
|
"Advertise port",
|
||||||
|
"component.emulated_roku.config.step.user.data.host_ip": "Host IP",
|
||||||
|
"component.emulated_roku.config.step.user.data.listen_port":
|
||||||
|
"Listen port",
|
||||||
|
"component.emulated_roku.config.step.user.data.name": "Name",
|
||||||
|
"component.emulated_roku.config.step.user.data.upnp_bind_multicast":
|
||||||
|
"Bind multicast (True/False)",
|
||||||
|
"component.emulated_roku.config.step.user.title":
|
||||||
|
"Define server configuration",
|
||||||
|
"component.emulated_roku.config.title": "EmulatedRoku",
|
||||||
|
"component.owntracks.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.owntracks.config.create_entry.default":
|
||||||
|
"\n\nOn Android, open [the OwnTracks app]({android_url}), go to preferences -> connection. Change the following settings:\n - Mode: Private HTTP\n - Host: {webhook_url}\n - Identification:\n - Username: `<Your name>`\n - Device ID: `<Your device name>`\n\nOn iOS, open [the OwnTracks app]({ios_url}), tap (i) icon in top left -> settings. Change the following settings:\n - Mode: HTTP\n - URL: {webhook_url}\n - Turn on authentication\n - UserID: `<Your name>`\n\n{secret}\n\nSee [the documentation]({docs_url}) for more information.",
|
||||||
|
"component.owntracks.config.step.user.description":
|
||||||
|
"Are you sure you want to set up OwnTracks?",
|
||||||
|
"component.owntracks.config.step.user.title": "Set up OwnTracks",
|
||||||
|
"component.owntracks.config.title": "OwnTracks",
|
||||||
|
"component.zone.config.error.name_exists": "Name already exists",
|
||||||
|
"component.zone.config.step.init.data.icon": "Icon",
|
||||||
|
"component.zone.config.step.init.data.latitude": "Latitude",
|
||||||
|
"component.zone.config.step.init.data.longitude": "Longitude",
|
||||||
|
"component.zone.config.step.init.data.name": "Name",
|
||||||
|
"component.zone.config.step.init.data.passive": "Passive",
|
||||||
|
"component.zone.config.step.init.data.radius": "Radius",
|
||||||
|
"component.zone.config.step.init.title": "Define zone parameters",
|
||||||
|
"component.zone.config.title": "Zone",
|
||||||
|
"component.hue.config.abort.all_configured":
|
||||||
|
"All Philips Hue bridges are already configured",
|
||||||
|
"component.hue.config.abort.already_configured":
|
||||||
|
"Bridge is already configured",
|
||||||
|
"component.hue.config.abort.cannot_connect":
|
||||||
|
"Unable to connect to the bridge",
|
||||||
|
"component.hue.config.abort.discover_timeout":
|
||||||
|
"Unable to discover Hue bridges",
|
||||||
|
"component.hue.config.abort.no_bridges":
|
||||||
|
"No Philips Hue bridges discovered",
|
||||||
|
"component.hue.config.abort.unknown": "Unknown error occurred",
|
||||||
|
"component.hue.config.error.linking": "Unknown linking error occurred.",
|
||||||
|
"component.hue.config.error.register_failed":
|
||||||
|
"Failed to register, please try again",
|
||||||
|
"component.hue.config.step.init.data.host": "Host",
|
||||||
|
"component.hue.config.step.init.title": "Pick Hue bridge",
|
||||||
|
"component.hue.config.step.link.description":
|
||||||
|
"Press the button on the bridge to register Philips Hue with Home Assistant.\n\n",
|
||||||
|
"component.hue.config.step.link.title": "Link Hub",
|
||||||
|
"component.hue.config.title": "Philips Hue",
|
||||||
|
"component.tradfri.config.abort.already_configured":
|
||||||
|
"Bridge is already configured",
|
||||||
|
"component.tradfri.config.error.cannot_connect":
|
||||||
|
"Unable to connect to the gateway.",
|
||||||
|
"component.tradfri.config.error.invalid_key":
|
||||||
|
"Failed to register with provided key. If this keeps happening, try restarting the gateway.",
|
||||||
|
"component.tradfri.config.error.timeout": "Timeout validating the code.",
|
||||||
|
"component.tradfri.config.step.auth.data.host": "Host",
|
||||||
|
"component.tradfri.config.step.auth.data.security_code": "Security Code",
|
||||||
|
"component.tradfri.config.step.auth.description":
|
||||||
|
"You can find the security code on the back of your gateway.",
|
||||||
|
"component.tradfri.config.step.auth.title": "Enter security code",
|
||||||
|
"component.tradfri.config.title": "IKEA TRÅDFRI",
|
||||||
|
"component.mqtt.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of MQTT is allowed.",
|
||||||
|
"component.mqtt.config.error.cannot_connect":
|
||||||
|
"Unable to connect to the broker.",
|
||||||
|
"component.mqtt.config.step.broker.data.broker": "Broker",
|
||||||
|
"component.mqtt.config.step.broker.data.discovery": "Enable discovery",
|
||||||
|
"component.mqtt.config.step.broker.data.password": "Password",
|
||||||
|
"component.mqtt.config.step.broker.data.port": "Port",
|
||||||
|
"component.mqtt.config.step.broker.data.username": "Username",
|
||||||
|
"component.mqtt.config.step.broker.description":
|
||||||
|
"Please enter the connection information of your MQTT broker.",
|
||||||
|
"component.mqtt.config.step.broker.title": "MQTT",
|
||||||
|
"component.mqtt.config.step.hassio_confirm.data.discovery":
|
||||||
|
"Enable discovery",
|
||||||
|
"component.mqtt.config.step.hassio_confirm.description":
|
||||||
|
"Do you want to configure Home Assistant to connect to the MQTT broker provided by the hass.io add-on {addon}?",
|
||||||
|
"component.mqtt.config.step.hassio_confirm.title":
|
||||||
|
"MQTT Broker via Hass.io add-on",
|
||||||
|
"component.mqtt.config.title": "MQTT",
|
||||||
|
"component.geofency.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency.",
|
||||||
|
"component.geofency.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.geofency.config.create_entry.default":
|
||||||
|
"To send events to Home Assistant, you will need to setup the webhook feature in Geofency.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||||
|
"component.geofency.config.step.user.description":
|
||||||
|
"Are you sure you want to set up the Geofency Webhook?",
|
||||||
|
"component.geofency.config.step.user.title":
|
||||||
|
"Set up the Geofency Webhook",
|
||||||
|
"component.geofency.config.title": "Geofency Webhook",
|
||||||
|
"component.simplisafe.config.error.identifier_exists":
|
||||||
|
"Account already registered",
|
||||||
|
"component.simplisafe.config.error.invalid_credentials":
|
||||||
|
"Invalid credentials",
|
||||||
|
"component.simplisafe.config.step.user.data.code":
|
||||||
|
"Code (for Home Assistant)",
|
||||||
|
"component.simplisafe.config.step.user.data.password": "Password",
|
||||||
|
"component.simplisafe.config.step.user.data.username": "Email Address",
|
||||||
|
"component.simplisafe.config.step.user.title": "Fill in your information",
|
||||||
|
"component.simplisafe.config.title": "SimpliSafe",
|
||||||
|
"component.dialogflow.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive Dialogflow messages.",
|
||||||
|
"component.dialogflow.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.dialogflow.config.create_entry.default":
|
||||||
|
"To send events to Home Assistant, you will need to setup [webhook integration of Dialogflow]({dialogflow_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) for further details.",
|
||||||
|
"component.dialogflow.config.step.user.description":
|
||||||
|
"Are you sure you want to set up Dialogflow?",
|
||||||
|
"component.dialogflow.config.step.user.title":
|
||||||
|
"Set up the Dialogflow Webhook",
|
||||||
|
"component.dialogflow.config.title": "Dialogflow",
|
||||||
|
"component.deconz.config.abort.already_configured":
|
||||||
|
"Bridge is already configured",
|
||||||
|
"component.deconz.config.abort.no_bridges":
|
||||||
|
"No deCONZ bridges discovered",
|
||||||
|
"component.deconz.config.abort.one_instance_only":
|
||||||
|
"Component only supports one deCONZ instance",
|
||||||
|
"component.deconz.config.error.no_key": "Couldn't get an API key",
|
||||||
|
"component.deconz.config.step.init.data.host": "Host",
|
||||||
|
"component.deconz.config.step.init.data.port": "Port",
|
||||||
|
"component.deconz.config.step.init.title": "Define deCONZ gateway",
|
||||||
|
"component.deconz.config.step.link.description":
|
||||||
|
'Unlock your deCONZ gateway to register with Home Assistant.\n\n1. Go to deCONZ system settings\n2. Press "Unlock Gateway" button',
|
||||||
|
"component.deconz.config.step.link.title": "Link with deCONZ",
|
||||||
|
"component.deconz.config.step.options.data.allow_clip_sensor":
|
||||||
|
"Allow importing virtual sensors",
|
||||||
|
"component.deconz.config.step.options.data.allow_deconz_groups":
|
||||||
|
"Allow importing deCONZ groups",
|
||||||
|
"component.deconz.config.step.options.title":
|
||||||
|
"Extra configuration options for deCONZ",
|
||||||
|
"component.deconz.config.title": "deCONZ Zigbee gateway",
|
||||||
|
"component.openuv.config.error.identifier_exists":
|
||||||
|
"Coordinates already registered",
|
||||||
|
"component.openuv.config.error.invalid_api_key": "Invalid API key",
|
||||||
|
"component.openuv.config.step.user.data.api_key": "OpenUV API Key",
|
||||||
|
"component.openuv.config.step.user.data.elevation": "Elevation",
|
||||||
|
"component.openuv.config.step.user.data.latitude": "Latitude",
|
||||||
|
"component.openuv.config.step.user.data.longitude": "Longitude",
|
||||||
|
"component.openuv.config.step.user.title": "Fill in your information",
|
||||||
|
"component.openuv.config.title": "OpenUV",
|
||||||
|
"component.locative.config.title": "Locative Webhook",
|
||||||
|
"component.locative.config.step.user.title":
|
||||||
|
"Set up the Locative Webhook",
|
||||||
|
"component.locative.config.step.user.description":
|
||||||
|
"Are you sure you want to set up the Locative Webhook?",
|
||||||
|
"component.locative.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.locative.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive messages from Geofency.",
|
||||||
|
"component.locative.config.create_entry.default":
|
||||||
|
"To send locations to Home Assistant, you will need to setup the webhook feature in the Locative app.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||||
|
"component.ios.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of Home Assistant iOS is necessary.",
|
||||||
|
"component.ios.config.step.confirm.description":
|
||||||
|
"Do you want to set up the Home Assistant iOS component?",
|
||||||
|
"component.ios.config.step.confirm.title": "Home Assistant iOS",
|
||||||
|
"component.ios.config.title": "Home Assistant iOS",
|
||||||
|
"component.smhi.config.error.name_exists": "Name already exists",
|
||||||
|
"component.smhi.config.error.wrong_location": "Location Sweden only",
|
||||||
|
"component.smhi.config.step.user.data.latitude": "Latitude",
|
||||||
|
"component.smhi.config.step.user.data.longitude": "Longitude",
|
||||||
|
"component.smhi.config.step.user.data.name": "Name",
|
||||||
|
"component.smhi.config.step.user.title": "Location in Sweden",
|
||||||
|
"component.smhi.config.title": "Swedish weather service (SMHI)",
|
||||||
|
"component.sonos.config.abort.no_devices_found":
|
||||||
|
"No Sonos devices found on the network.",
|
||||||
|
"component.sonos.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of Sonos is necessary.",
|
||||||
|
"component.sonos.config.step.confirm.description":
|
||||||
|
"Do you want to set up Sonos?",
|
||||||
|
"component.sonos.config.step.confirm.title": "Sonos",
|
||||||
|
"component.sonos.config.title": "Sonos",
|
||||||
|
"component.ifttt.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive IFTTT messages.",
|
||||||
|
"component.ifttt.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.ifttt.config.create_entry.default":
|
||||||
|
'To send events to Home Assistant, you will need to use the "Make a web request" action from the [IFTTT Webhook applet]({applet_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/json\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.',
|
||||||
|
"component.ifttt.config.step.user.description":
|
||||||
|
"Are you sure you want to set up IFTTT?",
|
||||||
|
"component.ifttt.config.step.user.title":
|
||||||
|
"Set up the IFTTT Webhook Applet",
|
||||||
|
"component.ifttt.config.title": "IFTTT",
|
||||||
|
"component.twilio.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive Twilio messages.",
|
||||||
|
"component.twilio.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.twilio.config.create_entry.default":
|
||||||
|
"To send events to Home Assistant, you will need to setup [Webhooks with Twilio]({twilio_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data.",
|
||||||
|
"component.twilio.config.step.user.description":
|
||||||
|
"Are you sure you want to set up Twilio?",
|
||||||
|
"component.twilio.config.step.user.title": "Set up the Twilio Webhook",
|
||||||
|
"component.twilio.config.title": "Twilio",
|
||||||
|
"component.zha.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of ZHA is allowed.",
|
||||||
|
"component.zha.config.error.cannot_connect":
|
||||||
|
"Unable to connect to ZHA device.",
|
||||||
|
"component.zha.config.step.user.data.radio_type": "Radio Type",
|
||||||
|
"component.zha.config.step.user.data.usb_path": "USB Device Path",
|
||||||
|
"component.zha.config.step.user.title": "ZHA",
|
||||||
|
"component.zha.config.title": "ZHA",
|
||||||
|
"component.gpslogger.config.title": "GPSLogger Webhook",
|
||||||
|
"component.gpslogger.config.step.user.title":
|
||||||
|
"Set up the GPSLogger Webhook",
|
||||||
|
"component.gpslogger.config.step.user.description":
|
||||||
|
"Are you sure you want to set up the GPSLogger Webhook?",
|
||||||
|
"component.gpslogger.config.abort.one_instance_allowed":
|
||||||
|
"Only a single instance is necessary.",
|
||||||
|
"component.gpslogger.config.abort.not_internet_accessible":
|
||||||
|
"Your Home Assistant instance needs to be accessible from the internet to receive messages from GPSLogger.",
|
||||||
|
"component.gpslogger.config.create_entry.default":
|
||||||
|
"To send events to Home Assistant, you will need to setup the webhook feature in GPSLogger.\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n\nSee [the documentation]({docs_url}) for further details.",
|
||||||
|
"component.zwave.config.abort.already_configured":
|
||||||
|
"Z-Wave is already configured",
|
||||||
|
"component.zwave.config.abort.one_instance_only":
|
||||||
|
"Component only supports one Z-Wave instance",
|
||||||
|
"component.zwave.config.error.option_error":
|
||||||
|
"Z-Wave validation failed. Is the path to the USB stick correct?",
|
||||||
|
"component.zwave.config.step.user.data.network_key":
|
||||||
|
"Network Key (leave blank to auto-generate)",
|
||||||
|
"component.zwave.config.step.user.data.usb_path": "USB Path",
|
||||||
|
"component.zwave.config.step.user.description":
|
||||||
|
"See https://www.home-assistant.io/docs/z-wave/installation/ for information on the configuration variables",
|
||||||
|
"component.zwave.config.step.user.title": "Set up Z-Wave",
|
||||||
|
"component.zwave.config.title": "Z-Wave",
|
||||||
|
"component.cast.config.abort.no_devices_found":
|
||||||
|
"No Google Cast devices found on the network.",
|
||||||
|
"component.cast.config.abort.single_instance_allowed":
|
||||||
|
"Only a single configuration of Google Cast is necessary.",
|
||||||
|
"component.cast.config.step.confirm.description":
|
||||||
|
"Do you want to set up Google Cast?",
|
||||||
|
"component.cast.config.step.confirm.title": "Google Cast",
|
||||||
|
"component.cast.config.title": "Google Cast",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
};
|
100
demo/webpack.config.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
|
||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
const { babelLoaderConfig } = require("../config/babel.js");
|
||||||
|
|
||||||
|
const isProd = process.env.NODE_ENV === "production";
|
||||||
|
const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||||
|
const buildPath = path.resolve(__dirname, "dist");
|
||||||
|
const publicPath = isProd ? "./" : "http://localhost:8080/";
|
||||||
|
|
||||||
|
const latestBuild = false;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: isProd ? "production" : "development",
|
||||||
|
// Disabled in prod while we make Home Assistant able to serve the right files.
|
||||||
|
// Was source-map
|
||||||
|
devtool: isProd ? "none" : "inline-source-map",
|
||||||
|
entry: {
|
||||||
|
main: "./src/entrypoint.ts",
|
||||||
|
compatibility: "../src/entrypoints/compatibility.js",
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
babelLoaderConfig({ latestBuild }),
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: "raw-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(html)$/,
|
||||||
|
use: {
|
||||||
|
loader: "html-loader",
|
||||||
|
options: {
|
||||||
|
exportAsEs6Default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
__DEV__: false,
|
||||||
|
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||||
|
__VERSION__: JSON.stringify("DEMO"),
|
||||||
|
__DEMO__: true,
|
||||||
|
__STATIC_PATH__: "/static/",
|
||||||
|
"process.env.NODE_ENV": JSON.stringify(
|
||||||
|
isProd ? "production" : "development"
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
"public",
|
||||||
|
"../node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
|
||||||
|
{ from: "../public", to: "static" },
|
||||||
|
{ from: "../build-translations/output", to: "static/translations" },
|
||||||
|
{
|
||||||
|
from: "../node_modules/leaflet/dist/leaflet.css",
|
||||||
|
to: "static/images/leaflet/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "../node_modules/@polymer/font-roboto-local/fonts",
|
||||||
|
to: "static/fonts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "../node_modules/leaflet/dist/images",
|
||||||
|
to: "static/images/leaflet/",
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
isProd &&
|
||||||
|
new UglifyJsPlugin({
|
||||||
|
extractComments: true,
|
||||||
|
sourceMap: true,
|
||||||
|
uglifyOptions: {
|
||||||
|
// Disabling because it broke output
|
||||||
|
mangle: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
].filter(Boolean),
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".js", ".json"],
|
||||||
|
alias: {
|
||||||
|
react: "preact-compat",
|
||||||
|
"react-dom": "preact-compat",
|
||||||
|
// Not necessary unless you consume a module using `createClass`
|
||||||
|
"create-react-class": "preact-compat/lib/create-react-class",
|
||||||
|
// Not necessary unless you consume a module requiring `react-dom-factories`
|
||||||
|
"react-dom-factories": "preact-compat/lib/react-dom-factories",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "[name].js",
|
||||||
|
chunkFilename: chunkFilename,
|
||||||
|
path: buildPath,
|
||||||
|
publicPath,
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: "./public",
|
||||||
|
},
|
||||||
|
};
|
13
demo_data/bootstrap_data.js
vendored
@ -1,13 +0,0 @@
|
|||||||
import config from './config_data';
|
|
||||||
import events from './event_data';
|
|
||||||
import services from './service_data';
|
|
||||||
import states from './state_data';
|
|
||||||
import panels from './panel_data';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
config,
|
|
||||||
events,
|
|
||||||
panels,
|
|
||||||
services,
|
|
||||||
states,
|
|
||||||
};
|
|
@ -1,18 +0,0 @@
|
|||||||
export default {
|
|
||||||
components: [
|
|
||||||
'configurator',
|
|
||||||
'http',
|
|
||||||
'api',
|
|
||||||
'frontend',
|
|
||||||
'history',
|
|
||||||
'conversation',
|
|
||||||
'logbook',
|
|
||||||
'introduction',
|
|
||||||
],
|
|
||||||
latitude: 32.87336,
|
|
||||||
location_name: 'Home',
|
|
||||||
longitude: -117.22743,
|
|
||||||
temperature_unit: '\u00b0F',
|
|
||||||
time_zone: 'America/Los_Angeles',
|
|
||||||
version: '0.26',
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
import bootstrap from './bootstrap_data';
|
|
||||||
import logbook from './logbook_data';
|
|
||||||
import stateHistory from './state_history_data';
|
|
||||||
|
|
||||||
window.hassDemoData = { bootstrap, logbook, stateHistory };
|
|
@ -1,18 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
event: 'call_service',
|
|
||||||
listener_count: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
event: 'time_changed',
|
|
||||||
listener_count: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
event: 'state_changed',
|
|
||||||
listener_count: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
event: 'homeassistant_stop',
|
|
||||||
listener_count: 2,
|
|
||||||
},
|
|
||||||
];
|
|
@ -1,93 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
domain: 'sun',
|
|
||||||
entity_id: 'sun.sun',
|
|
||||||
message: 'has risen',
|
|
||||||
name: 'sun',
|
|
||||||
when: '2015-04-24T06:08:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'device_tracker',
|
|
||||||
entity_id: 'device_tracker.paulus',
|
|
||||||
message: 'left home',
|
|
||||||
name: 'Paulus',
|
|
||||||
when: '2015-04-24T08:54:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'device_tracker',
|
|
||||||
entity_id: 'device_tracker.anne_therese',
|
|
||||||
message: 'left home',
|
|
||||||
name: 'Anne Therese',
|
|
||||||
when: '2015-04-24T09:08:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'group',
|
|
||||||
entity_id: 'group.all_devices',
|
|
||||||
message: 'left home',
|
|
||||||
name: 'All devices',
|
|
||||||
when: '2015-04-24T09:08:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'thermostat',
|
|
||||||
entity_id: 'thermostat.nest',
|
|
||||||
message: 'changed to 17 \u00b0C',
|
|
||||||
name: 'Nest',
|
|
||||||
when: '2015-04-24T09:08:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'thermostat',
|
|
||||||
entity_id: 'thermostat.nest',
|
|
||||||
message: 'changed to 21 \u00b0C',
|
|
||||||
name: 'Nest',
|
|
||||||
when: '2015-04-24T16:00:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'device_tracker',
|
|
||||||
entity_id: 'device_tracker.anne_therese',
|
|
||||||
message: 'came home',
|
|
||||||
name: 'Anne Therese',
|
|
||||||
when: '2015-04-24T16:24:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'group',
|
|
||||||
entity_id: 'group.all_devices',
|
|
||||||
message: 'came home',
|
|
||||||
name: 'All devices',
|
|
||||||
when: '2015-04-24T16:24:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'light',
|
|
||||||
entity_id: 'light.bowl',
|
|
||||||
message: 'turned on',
|
|
||||||
name: 'Bowl',
|
|
||||||
when: '2015-04-24T18:01:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'light',
|
|
||||||
entity_id: 'light.ceiling',
|
|
||||||
message: 'turned on',
|
|
||||||
name: 'Ceiling',
|
|
||||||
when: '2015-04-24T18:16:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'light',
|
|
||||||
entity_id: 'light.tv_back_light',
|
|
||||||
message: 'turned on',
|
|
||||||
name: 'TV Back Light',
|
|
||||||
when: '2015-04-24T18:31:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'sun',
|
|
||||||
entity_id: 'sun.sun',
|
|
||||||
message: 'has set',
|
|
||||||
name: 'sun',
|
|
||||||
when: '2015-04-24T18:46:47.000Z',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'media_player',
|
|
||||||
entity_id: 'media_player.living_room',
|
|
||||||
message: 'changed to Plex',
|
|
||||||
name: 'Media Player',
|
|
||||||
when: '2015-04-24T19:12:47.000Z',
|
|
||||||
},
|
|
||||||
];
|
|
@ -1,48 +0,0 @@
|
|||||||
export default {
|
|
||||||
'dev-event': {
|
|
||||||
component_name: 'dev-event',
|
|
||||||
url: '/demo/panels/ha-panel-dev-event.html',
|
|
||||||
url_name: 'dev-event',
|
|
||||||
},
|
|
||||||
'dev-info': {
|
|
||||||
component_name: 'dev-info',
|
|
||||||
url: '/demo/panels/ha-panel-dev-info.html',
|
|
||||||
url_name: 'dev-info',
|
|
||||||
},
|
|
||||||
'dev-service': {
|
|
||||||
component_name: 'dev-service',
|
|
||||||
url: '/demo/panels/ha-panel-dev-service.html',
|
|
||||||
url_name: 'dev-service',
|
|
||||||
},
|
|
||||||
'dev-state': {
|
|
||||||
component_name: 'dev-state',
|
|
||||||
url: '/demo/panels/ha-panel-dev-state.html',
|
|
||||||
url_name: 'dev-state',
|
|
||||||
},
|
|
||||||
'dev-template': {
|
|
||||||
component_name: 'dev-template',
|
|
||||||
url: '/demo/panels/ha-panel-dev-template.html',
|
|
||||||
url_name: 'dev-template',
|
|
||||||
},
|
|
||||||
history: {
|
|
||||||
component_name: 'history',
|
|
||||||
icon: 'mdi:poll-box',
|
|
||||||
title: 'History',
|
|
||||||
url: '/demo/panels/ha-panel-history.html',
|
|
||||||
url_name: 'history',
|
|
||||||
},
|
|
||||||
logbook: {
|
|
||||||
component_name: 'logbook',
|
|
||||||
icon: 'mdi:format-list-bulleted-type',
|
|
||||||
title: 'Logbook',
|
|
||||||
url: '/demo/panels/ha-panel-logbook.html',
|
|
||||||
url_name: 'logbook',
|
|
||||||
},
|
|
||||||
map: {
|
|
||||||
component_name: 'map',
|
|
||||||
icon: 'mdi:account-location',
|
|
||||||
title: 'Map',
|
|
||||||
url: '/demo/panels/ha-panel-map.html',
|
|
||||||
url_name: 'map',
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,37 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
domain: 'homeassistant',
|
|
||||||
services: {
|
|
||||||
stop: { description: '', fields: {} },
|
|
||||||
turn_off: { description: '', fields: {} },
|
|
||||||
turn_on: { description: '', fields: {} },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'light',
|
|
||||||
services: {
|
|
||||||
turn_off: { description: '', fields: {} },
|
|
||||||
turn_on: { description: '', fields: {} },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'switch',
|
|
||||||
services: {
|
|
||||||
turn_off: { description: '', fields: {} },
|
|
||||||
turn_on: { description: '', fields: {} },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'input_boolean',
|
|
||||||
services: {
|
|
||||||
turn_off: { description: '', fields: {} },
|
|
||||||
turn_on: { description: '', fields: {} },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
domain: 'configurator',
|
|
||||||
services: {
|
|
||||||
configure: { description: '', fields: {} },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
@ -1,279 +0,0 @@
|
|||||||
function getRandomTime() {
|
|
||||||
const ts = new Date(new Date().getTime() - (Math.random() * 80 * 60 * 1000));
|
|
||||||
return ts.toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
const entities = [];
|
|
||||||
|
|
||||||
function addEntity(entityId, state, attributes = {}) {
|
|
||||||
entities.push({
|
|
||||||
state,
|
|
||||||
attributes,
|
|
||||||
entity_id: entityId,
|
|
||||||
last_changed: getRandomTime(),
|
|
||||||
last_updated: getRandomTime(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let groupOrder = 0;
|
|
||||||
|
|
||||||
function addGroup(objectId, state, entityIds, name, view) {
|
|
||||||
groupOrder++;
|
|
||||||
|
|
||||||
const attributes = {
|
|
||||||
entity_id: entityIds,
|
|
||||||
order: groupOrder,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (name) {
|
|
||||||
attributes.friendly_name = name;
|
|
||||||
}
|
|
||||||
if (view) {
|
|
||||||
attributes.view = view;
|
|
||||||
attributes.hidden = true;
|
|
||||||
}
|
|
||||||
addEntity(`group.${objectId}`, state, attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// HOME ASSISTANT
|
|
||||||
// ---------------------------------------------------
|
|
||||||
addEntity('a.demo_mode', 'enabled');
|
|
||||||
|
|
||||||
addEntity('configurator.philips_hue', 'configure', {
|
|
||||||
configure_id: '4415244496-1',
|
|
||||||
description: 'Press the button on the bridge to register Philips Hue with Home Assistant.',
|
|
||||||
description_image: '/demo/images/config_philips_hue.jpg',
|
|
||||||
fields: [],
|
|
||||||
submit_caption: 'I have pressed the button',
|
|
||||||
friendly_name: 'Philips Hue',
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// VIEWS
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addGroup(
|
|
||||||
'default_view', 'on', [
|
|
||||||
'a.demo_mode',
|
|
||||||
'sensor.humidity',
|
|
||||||
'sensor.temperature',
|
|
||||||
'device_tracker.paulus',
|
|
||||||
'device_tracker.anne_therese',
|
|
||||||
'configurator.philips_hue',
|
|
||||||
'group.cooking',
|
|
||||||
'group.general',
|
|
||||||
'group.rooms',
|
|
||||||
'camera.living_room',
|
|
||||||
'media_player.living_room',
|
|
||||||
'scene.romantic',
|
|
||||||
'scene.good_morning',
|
|
||||||
'script.water_lawn',
|
|
||||||
], 'Main', true);
|
|
||||||
|
|
||||||
addGroup(
|
|
||||||
'rooms_view', 'on', [
|
|
||||||
'group.living_room',
|
|
||||||
'group.bedroom',
|
|
||||||
], 'Rooms', true);
|
|
||||||
|
|
||||||
addGroup('rooms', 'on', ['group.living_room', 'group.bedroom'], 'Rooms');
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// DEVICE TRACKER + ZONES
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addEntity('device_tracker.anne_therese', 'school', {
|
|
||||||
entity_picture: 'https://graph.facebook.com/621994601/picture',
|
|
||||||
friendly_name: 'Anne Therese',
|
|
||||||
latitude: 32.879898,
|
|
||||||
longitude: -117.236776,
|
|
||||||
gps_accuracy: 250,
|
|
||||||
battery: 76,
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('device_tracker.paulus', 'not_home', {
|
|
||||||
entity_picture: 'https://graph.facebook.com/297400035/picture',
|
|
||||||
friendly_name: 'Paulus',
|
|
||||||
gps_accuracy: 75,
|
|
||||||
latitude: 32.892950,
|
|
||||||
longitude: -117.203431,
|
|
||||||
battery: 56,
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('zone.school', 'zoning', {
|
|
||||||
radius: 250,
|
|
||||||
latitude: 32.880834,
|
|
||||||
longitude: -117.237556,
|
|
||||||
icon: 'mdi:library',
|
|
||||||
hidden: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('zone.work', 'zoning', {
|
|
||||||
radius: 250,
|
|
||||||
latitude: 32.896844,
|
|
||||||
longitude: -117.202204,
|
|
||||||
icon: 'mdi:worker',
|
|
||||||
hidden: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('zone.home', 'zoning', {
|
|
||||||
radius: 100,
|
|
||||||
latitude: 32.873708,
|
|
||||||
longitude: -117.226590,
|
|
||||||
icon: 'mdi:home',
|
|
||||||
hidden: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// GENERAL
|
|
||||||
// ---------------------------------------------------
|
|
||||||
addGroup('general', 'on', [
|
|
||||||
'alarm_control_panel.home',
|
|
||||||
'garage_door.garage_door',
|
|
||||||
'lock.kitchen_door',
|
|
||||||
'thermostat.nest',
|
|
||||||
'camera.living_room',
|
|
||||||
]);
|
|
||||||
|
|
||||||
addEntity('camera.living_room', 'idle', {
|
|
||||||
entity_picture: '/demo/webcam.jpg?',
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('garage_door.garage_door', 'open', {
|
|
||||||
friendly_name: 'Garage Door',
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('alarm_control_panel.home', 'armed_home', {
|
|
||||||
friendly_name: 'Alarm',
|
|
||||||
code_format: '^\\d{4}',
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('lock.kitchen_door', 'open', {
|
|
||||||
friendly_name: 'Kitchen Door',
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// PRESETS
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addEntity('script.water_lawn', 'off', {
|
|
||||||
friendly_name: 'Water Lawn',
|
|
||||||
});
|
|
||||||
addEntity('scene.romantic', 'scening', {
|
|
||||||
friendly_name: 'Romantic',
|
|
||||||
});
|
|
||||||
// addEntity('scene.good_morning', 'scening', {
|
|
||||||
// friendly_name: 'Good Morning',
|
|
||||||
// });
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// LIVING ROOM
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addGroup(
|
|
||||||
'living_room', 'on',
|
|
||||||
[
|
|
||||||
'light.table_lamp',
|
|
||||||
'light.ceiling',
|
|
||||||
'light.tv_back_light',
|
|
||||||
'switch.ac',
|
|
||||||
'media_player.living_room',
|
|
||||||
],
|
|
||||||
'Living Room'
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity('light.tv_back_light', 'off', {
|
|
||||||
friendly_name: 'TV Back Light',
|
|
||||||
});
|
|
||||||
addEntity('light.ceiling', 'on', {
|
|
||||||
friendly_name: 'Ceiling Lights',
|
|
||||||
brightness: 200,
|
|
||||||
rgb_color: [255, 116, 155],
|
|
||||||
});
|
|
||||||
addEntity('light.table_lamp', 'on', {
|
|
||||||
brightness: 200,
|
|
||||||
rgb_color: [150, 212, 94],
|
|
||||||
friendly_name: 'Table Lamp',
|
|
||||||
});
|
|
||||||
addEntity('switch.ac', 'on', {
|
|
||||||
friendly_name: 'AC',
|
|
||||||
icon: 'mdi:air-conditioner',
|
|
||||||
});
|
|
||||||
addEntity('media_player.living_room', 'playing', {
|
|
||||||
entity_picture: '/demo/images/thrones.jpg',
|
|
||||||
friendly_name: 'Chromecast',
|
|
||||||
supported_features: 509,
|
|
||||||
media_content_type: 'tvshow',
|
|
||||||
media_title: 'The Dance of Dragons',
|
|
||||||
media_series_title: 'Game of Thrones',
|
|
||||||
media_season: 5,
|
|
||||||
media_episode: '09',
|
|
||||||
app_name: 'HBO Now',
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// BEDROOM
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addGroup(
|
|
||||||
'bedroom', 'off',
|
|
||||||
[
|
|
||||||
'light.bed_light',
|
|
||||||
'switch.decorative_lights',
|
|
||||||
'rollershutter.bedroom_window',
|
|
||||||
],
|
|
||||||
'Bedroom'
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity('switch.decorative_lights', 'off', {
|
|
||||||
friendly_name: 'Decorative Lights',
|
|
||||||
});
|
|
||||||
addEntity('light.bed_light', 'off', {
|
|
||||||
friendly_name: 'Bed Light',
|
|
||||||
});
|
|
||||||
addEntity('rollershutter.bedroom_window', 'closed', {
|
|
||||||
friendly_name: 'Window',
|
|
||||||
current_position: 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// SENSORS
|
|
||||||
// ---------------------------------------------------
|
|
||||||
|
|
||||||
addEntity('sensor.temperature', '15.6', {
|
|
||||||
unit_of_measurement: '\u00b0C',
|
|
||||||
friendly_name: 'Temperature',
|
|
||||||
});
|
|
||||||
addEntity('sensor.humidity', '54', {
|
|
||||||
unit_of_measurement: '%',
|
|
||||||
friendly_name: 'Humidity',
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('thermostat.nest', '23', {
|
|
||||||
away_mode: 'off',
|
|
||||||
temperature: '21',
|
|
||||||
current_temperature: '18',
|
|
||||||
unit_of_measurement: '\u00b0C',
|
|
||||||
friendly_name: 'Nest',
|
|
||||||
});
|
|
||||||
|
|
||||||
// ---------------------------------------------------
|
|
||||||
// COOKING AUTOMATION
|
|
||||||
// ---------------------------------------------------
|
|
||||||
addEntity('input_select.cook_today', 'Paulus', {
|
|
||||||
options: ['Paulus', 'Anne Therese'],
|
|
||||||
icon: 'mdi:panda',
|
|
||||||
});
|
|
||||||
|
|
||||||
addEntity('input_boolean.notify_cook', 'on', {
|
|
||||||
icon: 'mdi:alarm',
|
|
||||||
friendly_name: 'Notify Cook',
|
|
||||||
});
|
|
||||||
|
|
||||||
addGroup(
|
|
||||||
'cooking', 'unknown',
|
|
||||||
['input_select.cook_today', 'input_boolean.notify_cook']
|
|
||||||
);
|
|
||||||
|
|
||||||
export default entities;
|
|
@ -1,255 +0,0 @@
|
|||||||
import stateData from './state_data';
|
|
||||||
|
|
||||||
function getTime(minutesAgo) {
|
|
||||||
const ts = new Date(Date.now() - (minutesAgo * 60 * 1000));
|
|
||||||
return ts.toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefill with entities we do not want to track
|
|
||||||
const seen = {
|
|
||||||
'a.demo_mode': true,
|
|
||||||
'configurator.philips_hue': true,
|
|
||||||
'group.default_view': true,
|
|
||||||
'group.rooms_view': true,
|
|
||||||
'group.rooms': true,
|
|
||||||
'zone.school': true,
|
|
||||||
'zone.work': true,
|
|
||||||
'zone.home': true,
|
|
||||||
'group.general': true,
|
|
||||||
'camera.roundabout': true,
|
|
||||||
'script.water_lawn': true,
|
|
||||||
'scene.romantic': true,
|
|
||||||
'scene.good_morning': true,
|
|
||||||
'group.cooking': true,
|
|
||||||
};
|
|
||||||
const history = [];
|
|
||||||
|
|
||||||
function randomTimeAdjustment(diff) {
|
|
||||||
return Math.random() * diff - (diff / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxTime = 1440;
|
|
||||||
|
|
||||||
function addEntity(state, deltas) {
|
|
||||||
seen[state.entity_id] = true;
|
|
||||||
let changes;
|
|
||||||
if (typeof deltas[0] === 'string') {
|
|
||||||
changes = deltas.map(state_ => ({ state: state_ }));
|
|
||||||
} else {
|
|
||||||
changes = deltas;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timeDiff = (900 / changes.length);
|
|
||||||
|
|
||||||
history.push(changes.map(
|
|
||||||
(change, index) => {
|
|
||||||
let attributes;
|
|
||||||
if (!change.attributes && !state.attributes) {
|
|
||||||
attributes = {};
|
|
||||||
} else if (!change.attributes) {
|
|
||||||
attributes = state.attributes;
|
|
||||||
} else if (!state.attributes) {
|
|
||||||
attributes = change.attributes;
|
|
||||||
} else {
|
|
||||||
attributes = Object.assign({}, state.attributes, change.attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
const time = index === 0 ? getTime(maxTime) : getTime(maxTime - index * timeDiff +
|
|
||||||
randomTimeAdjustment(timeDiff));
|
|
||||||
|
|
||||||
return {
|
|
||||||
attributes,
|
|
||||||
entity_id: state.entity_id,
|
|
||||||
state: change.state || state.state,
|
|
||||||
last_changed: time,
|
|
||||||
last_updated: time,
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'sensor.humidity',
|
|
||||||
attributes: {
|
|
||||||
unit_of_measurement: '%',
|
|
||||||
},
|
|
||||||
}, ['45', '49', '52', '49', '52', '49', '45', '42']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'sensor.temperature',
|
|
||||||
attributes: {
|
|
||||||
unit_of_measurement: '\u00b0C',
|
|
||||||
},
|
|
||||||
}, ['23', '27', '25', '23', '24']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'thermostat.nest',
|
|
||||||
attributes: {
|
|
||||||
unit_of_measurement: '\u00b0C',
|
|
||||||
},
|
|
||||||
}, [
|
|
||||||
{
|
|
||||||
state: '23',
|
|
||||||
attributes: {
|
|
||||||
current_temperature: 20,
|
|
||||||
temperature: 23,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
state: '23',
|
|
||||||
attributes: {
|
|
||||||
current_temperature: 22,
|
|
||||||
temperature: 23,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
state: '20',
|
|
||||||
attributes: {
|
|
||||||
current_temperature: 21,
|
|
||||||
temperature: 20,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
state: '20',
|
|
||||||
attributes: {
|
|
||||||
current_temperature: 20,
|
|
||||||
temperature: 20,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
state: '20',
|
|
||||||
attributes: {
|
|
||||||
current_temperature: 19,
|
|
||||||
temperature: 20,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'media_player.living_room',
|
|
||||||
attributes: {
|
|
||||||
friendly_name: 'Chromecast',
|
|
||||||
},
|
|
||||||
}, ['Plex', 'idle', 'YouTube', 'Netflix', 'idle', 'Plex']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'group.all_devices',
|
|
||||||
}, ['home', 'not_home', 'home']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'device_tracker.paulus',
|
|
||||||
}, ['home', 'not_home', 'work', 'not_home']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'device_tracker.anne_therese',
|
|
||||||
}, ['home', 'not_home', 'home', 'not_home', 'school']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'garage_door.garage_door',
|
|
||||||
}, ['open', 'closed', 'open']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'alarm_control_panel.home',
|
|
||||||
}, ['disarmed', 'pending', 'armed_home', 'pending', 'disarmed', 'pending', 'armed_home']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'lock.kitchen_door',
|
|
||||||
}, ['unlocked', 'locked', 'unlocked', 'locked']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'light.tv_back_light',
|
|
||||||
}, ['on', 'off', 'on', 'off']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'light.ceiling',
|
|
||||||
}, ['on', 'off', 'on']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'light.table_lamp',
|
|
||||||
}, ['on', 'off', 'on']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'switch.ac',
|
|
||||||
}, ['on', 'off', 'on']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'group.bedroom',
|
|
||||||
}, ['on', 'off', 'on', 'off']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'group.living_room',
|
|
||||||
}, ['on', 'off', 'on']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'switch.decorative_lights',
|
|
||||||
}, ['on', 'off', 'on', 'off']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'light.bed_light',
|
|
||||||
}, ['on', 'off', 'on', 'off']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'rollershutter.bedroom_window',
|
|
||||||
}, ['open', 'closed', 'open', 'closed']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'input_select.cook_today',
|
|
||||||
}, ['Anne Therese', 'Paulus']
|
|
||||||
);
|
|
||||||
|
|
||||||
addEntity(
|
|
||||||
{
|
|
||||||
entity_id: 'input_boolean.notify_cook',
|
|
||||||
}, ['off', 'on']
|
|
||||||
);
|
|
||||||
|
|
||||||
if (__DEV__) {
|
|
||||||
for (let i = 0; i < stateData.length; i++) {
|
|
||||||
const entity = stateData[i];
|
|
||||||
if (!(entity.entity_id in seen)) {
|
|
||||||
/* eslint-disable no-console */
|
|
||||||
console.warn(`Missing history for ${entity.entity_id}`);
|
|
||||||
/* eslint-enable no-console */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default history;
|
|
Before Width: | Height: | Size: 111 KiB After Width: | Height: | Size: 111 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
@ -2,11 +2,6 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
import JsYaml from "js-yaml";
|
import JsYaml from "js-yaml";
|
||||||
|
|
||||||
import HomeAssistant from "../data/hass";
|
|
||||||
import { demoConfig } from "../data/demo_config";
|
|
||||||
import { demoServices } from "../data/demo_services";
|
|
||||||
import demoResources from "../data/demo_resources";
|
|
||||||
import demoStates from "../data/demo_states";
|
|
||||||
import { createCardElement } from "../../../src/panels/lovelace/common/create-card-element";
|
import { createCardElement } from "../../../src/panels/lovelace/common/create-card-element";
|
||||||
|
|
||||||
class DemoCard extends PolymerElement {
|
class DemoCard extends PolymerElement {
|
||||||
@ -68,23 +63,7 @@ class DemoCard extends PolymerElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const el = createCardElement(JsYaml.safeLoad(config.config)[0]);
|
const el = createCardElement(JsYaml.safeLoad(config.config)[0]);
|
||||||
|
el.hass = this.hass;
|
||||||
if (this.hass) {
|
|
||||||
el.hass = this.hass;
|
|
||||||
} else {
|
|
||||||
const hass = new HomeAssistant(demoStates);
|
|
||||||
hass.config = demoConfig;
|
|
||||||
hass.services = demoServices;
|
|
||||||
hass.resources = demoResources;
|
|
||||||
hass.language = "en";
|
|
||||||
hass.states = demoStates;
|
|
||||||
hass.themes = {
|
|
||||||
default_theme: "default",
|
|
||||||
themes: {},
|
|
||||||
};
|
|
||||||
el.hass = hass;
|
|
||||||
}
|
|
||||||
|
|
||||||
card.appendChild(el);
|
card.appendChild(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +0,0 @@
|
|||||||
export const demoConfig = {
|
|
||||||
elevation: 300,
|
|
||||||
latitude: 51.5287352,
|
|
||||||
longitude: -0.381773,
|
|
||||||
unit_system: {
|
|
||||||
length: "km",
|
|
||||||
mass: "kg",
|
|
||||||
temperature: "°C",
|
|
||||||
volume: "L",
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,264 +0,0 @@
|
|||||||
export default {
|
|
||||||
en: {
|
|
||||||
"state.default.off": "Off",
|
|
||||||
"state.default.on": "On",
|
|
||||||
"state.default.unknown": "Unknown",
|
|
||||||
"state.default.unavailable": "Unavailable",
|
|
||||||
"state.alarm_control_panel.armed": "Armed",
|
|
||||||
"state.alarm_control_panel.disarmed": "Disarmed",
|
|
||||||
"state.alarm_control_panel.armed_home": "Armed home",
|
|
||||||
"state.alarm_control_panel.armed_away": "Armed away",
|
|
||||||
"state.alarm_control_panel.armed_night": "Armed night",
|
|
||||||
"state.alarm_control_panel.armed_custom_bypass": "Armed custom bypass",
|
|
||||||
"state.alarm_control_panel.pending": "Pending",
|
|
||||||
"state.alarm_control_panel.arming": "Arming",
|
|
||||||
"state.alarm_control_panel.disarming": "Disarming",
|
|
||||||
"state.alarm_control_panel.triggered": "Triggered",
|
|
||||||
"state.automation.off": "Off",
|
|
||||||
"state.automation.on": "On",
|
|
||||||
"state.binary_sensor.default.off": "Off",
|
|
||||||
"state.binary_sensor.default.on": "On",
|
|
||||||
"state.binary_sensor.battery.off": "Normal",
|
|
||||||
"state.binary_sensor.battery.on": "Low",
|
|
||||||
"state.binary_sensor.cold.off": "Normal",
|
|
||||||
"state.binary_sensor.cold.on": "Cold",
|
|
||||||
"state.binary_sensor.connectivity.off": "Disconnected",
|
|
||||||
"state.binary_sensor.connectivity.on": "Connected",
|
|
||||||
"state.binary_sensor.door.off": "Closed",
|
|
||||||
"state.binary_sensor.door.on": "Open",
|
|
||||||
"state.binary_sensor.garage_door.off": "Closed",
|
|
||||||
"state.binary_sensor.garage_door.on": "Open",
|
|
||||||
"state.binary_sensor.gas.off": "Clear",
|
|
||||||
"state.binary_sensor.gas.on": "Detected",
|
|
||||||
"state.binary_sensor.heat.off": "Normal",
|
|
||||||
"state.binary_sensor.heat.on": "Hot",
|
|
||||||
"state.binary_sensor.lock.off": "Locked",
|
|
||||||
"state.binary_sensor.lock.on": "Unlocked",
|
|
||||||
"state.binary_sensor.moisture.off": "Dry",
|
|
||||||
"state.binary_sensor.moisture.on": "Wet",
|
|
||||||
"state.binary_sensor.motion.off": "Clear",
|
|
||||||
"state.binary_sensor.motion.on": "Detected",
|
|
||||||
"state.binary_sensor.occupancy.off": "Clear",
|
|
||||||
"state.binary_sensor.occupancy.on": "Detected",
|
|
||||||
"state.binary_sensor.opening.off": "Closed",
|
|
||||||
"state.binary_sensor.opening.on": "Open",
|
|
||||||
"state.binary_sensor.presence.off": "Away",
|
|
||||||
"state.binary_sensor.presence.on": "Home",
|
|
||||||
"state.binary_sensor.problem.off": "OK",
|
|
||||||
"state.binary_sensor.problem.on": "Problem",
|
|
||||||
"state.binary_sensor.safety.off": "Safe",
|
|
||||||
"state.binary_sensor.safety.on": "Unsafe",
|
|
||||||
"state.binary_sensor.smoke.off": "Clear",
|
|
||||||
"state.binary_sensor.smoke.on": "Detected",
|
|
||||||
"state.binary_sensor.sound.off": "Clear",
|
|
||||||
"state.binary_sensor.sound.on": "Detected",
|
|
||||||
"state.binary_sensor.vibration.off": "Clear",
|
|
||||||
"state.binary_sensor.vibration.on": "Detected",
|
|
||||||
"state.binary_sensor.window.off": "Closed",
|
|
||||||
"state.binary_sensor.window.on": "Open",
|
|
||||||
"state.calendar.off": "Off",
|
|
||||||
"state.calendar.on": "On",
|
|
||||||
"state.camera.recording": "Recording",
|
|
||||||
"state.camera.streaming": "Streaming",
|
|
||||||
"state.camera.idle": "Idle",
|
|
||||||
"state.climate.off": "Off",
|
|
||||||
"state.climate.on": "On",
|
|
||||||
"state.climate.heat": "Heat",
|
|
||||||
"state.climate.cool": "Cool",
|
|
||||||
"state.climate.idle": "Idle",
|
|
||||||
"state.climate.auto": "Auto",
|
|
||||||
"state.climate.dry": "Dry",
|
|
||||||
"state.climate.fan_only": "Fan only",
|
|
||||||
"state.climate.eco": "Eco",
|
|
||||||
"state.climate.electric": "Electric",
|
|
||||||
"state.climate.performance": "Performance",
|
|
||||||
"state.climate.high_demand": "High demand",
|
|
||||||
"state.climate.heat_pump": "Heat pump",
|
|
||||||
"state.climate.gas": "Gas",
|
|
||||||
"state.configurator.configure": "Configure",
|
|
||||||
"state.configurator.configured": "Configured",
|
|
||||||
"state.cover.open": "Open",
|
|
||||||
"state.cover.opening": "Opening",
|
|
||||||
"state.cover.closed": "Closed",
|
|
||||||
"state.cover.closing": "Closing",
|
|
||||||
"state.cover.stopped": "Stopped",
|
|
||||||
"state.device_tracker.home": "Home",
|
|
||||||
"state.device_tracker.not_home": "Away",
|
|
||||||
"state.fan.off": "Off",
|
|
||||||
"state.fan.on": "On",
|
|
||||||
"state.group.off": "Off",
|
|
||||||
"state.group.on": "On",
|
|
||||||
"state.group.home": "Home",
|
|
||||||
"state.group.not_home": "Away",
|
|
||||||
"state.group.open": "Open",
|
|
||||||
"state.group.opening": "Opening",
|
|
||||||
"state.group.closed": "Closed",
|
|
||||||
"state.group.closing": "Closing",
|
|
||||||
"state.group.stopped": "Stopped",
|
|
||||||
"state.group.locked": "Locked",
|
|
||||||
"state.group.unlocked": "Unlocked",
|
|
||||||
"state.group.ok": "OK",
|
|
||||||
"state.group.problem": "Problem",
|
|
||||||
"state.input_boolean.off": "Off",
|
|
||||||
"state.input_boolean.on": "On",
|
|
||||||
"state.light.off": "Off",
|
|
||||||
"state.light.on": "On",
|
|
||||||
"state.lock.locked": "Locked",
|
|
||||||
"state.lock.unlocked": "Unlocked",
|
|
||||||
"state.media_player.off": "Off",
|
|
||||||
"state.media_player.on": "On",
|
|
||||||
"state.media_player.playing": "Playing",
|
|
||||||
"state.media_player.paused": "Paused",
|
|
||||||
"state.media_player.idle": "Idle",
|
|
||||||
"state.media_player.standby": "Standby",
|
|
||||||
"state.plant.ok": "OK",
|
|
||||||
"state.plant.problem": "Problem",
|
|
||||||
"state.remote.off": "Off",
|
|
||||||
"state.remote.on": "On",
|
|
||||||
"state.scene.scening": "Scening",
|
|
||||||
"state.script.off": "Off",
|
|
||||||
"state.script.on": "On",
|
|
||||||
"state.sensor.off": "Off",
|
|
||||||
"state.sensor.on": "On",
|
|
||||||
"state.sun.above_horizon": "Above horizon",
|
|
||||||
"state.sun.below_horizon": "Below horizon",
|
|
||||||
"state.switch.off": "Off",
|
|
||||||
"state.switch.on": "On",
|
|
||||||
"state.weather.clear-night": "Clear, night",
|
|
||||||
"state.weather.cloudy": "Cloudy",
|
|
||||||
"state.weather.fog": "Fog",
|
|
||||||
"state.weather.hail": "Hail",
|
|
||||||
"state.weather.lightning": "Lightning",
|
|
||||||
"state.weather.lightning-rainy": "Lightning, rainy",
|
|
||||||
"state.weather.partlycloudy": "Partly cloudy",
|
|
||||||
"state.weather.pouring": "Pouring",
|
|
||||||
"state.weather.rainy": "Rainy",
|
|
||||||
"state.weather.snowy": "Snowy",
|
|
||||||
"state.weather.snowy-rainy": "Snowy, rainy",
|
|
||||||
"state.weather.sunny": "Sunny",
|
|
||||||
"state.weather.windy": "Windy",
|
|
||||||
"state.weather.windy-variant": "Windy",
|
|
||||||
"state.zwave.default.initializing": "Initializing",
|
|
||||||
"state.zwave.default.dead": "Dead",
|
|
||||||
"state.zwave.default.sleeping": "Sleeping",
|
|
||||||
"state.zwave.default.ready": "Ready",
|
|
||||||
"state.zwave.query_stage.initializing": "Initializing ({query_stage})",
|
|
||||||
"state.zwave.query_stage.dead": "Dead ({query_stage})",
|
|
||||||
"state_badge.default.unknown": "Unk",
|
|
||||||
"state_badge.default.unavailable": "Unavai",
|
|
||||||
"state_badge.alarm_control_panel.armed": "Armed",
|
|
||||||
"state_badge.alarm_control_panel.disarmed": "Disarm",
|
|
||||||
"state_badge.alarm_control_panel.armed_home": "Armed",
|
|
||||||
"state_badge.alarm_control_panel.armed_away": "Armed",
|
|
||||||
"state_badge.alarm_control_panel.armed_night": "Armed",
|
|
||||||
"state_badge.alarm_control_panel.armed_custom_bypass": "Armed",
|
|
||||||
"state_badge.alarm_control_panel.pending": "Pend",
|
|
||||||
"state_badge.alarm_control_panel.arming": "Arming",
|
|
||||||
"state_badge.alarm_control_panel.disarming": "Disarm",
|
|
||||||
"state_badge.alarm_control_panel.triggered": "Trig",
|
|
||||||
"state_badge.device_tracker.home": "Home",
|
|
||||||
"state_badge.device_tracker.not_home": "Away",
|
|
||||||
"ui.card.alarm_control_panel.code": "Code",
|
|
||||||
"ui.card.alarm_control_panel.clear_code": "Clear",
|
|
||||||
"ui.card.alarm_control_panel.disarm": "Disarm",
|
|
||||||
"ui.card.alarm_control_panel.arm_home": "Arm home",
|
|
||||||
"ui.card.alarm_control_panel.arm_away": "Arm away",
|
|
||||||
"ui.card.automation.last_triggered": "Last triggered",
|
|
||||||
"ui.card.automation.trigger": "Trigger",
|
|
||||||
"ui.card.camera.not_available": "Image not available",
|
|
||||||
"ui.card.climate.currently": "Currently",
|
|
||||||
"ui.card.climate.on_off": "On / off",
|
|
||||||
"ui.card.climate.target_temperature": "Target temperature",
|
|
||||||
"ui.card.climate.target_humidity": "Target humidity",
|
|
||||||
"ui.card.climate.operation": "Operation",
|
|
||||||
"ui.card.climate.fan_mode": "Fan mode",
|
|
||||||
"ui.card.climate.swing_mode": "Swing mode",
|
|
||||||
"ui.card.climate.away_mode": "Away mode",
|
|
||||||
"ui.card.climate.aux_heat": "Aux heat",
|
|
||||||
"ui.card.cover.position": "Position",
|
|
||||||
"ui.card.cover.tilt_position": "Tilt position",
|
|
||||||
"ui.card.fan.speed": "Speed",
|
|
||||||
"ui.card.fan.oscillate": "Oscillate",
|
|
||||||
"ui.card.fan.direction": "Direction",
|
|
||||||
"ui.card.light.brightness": "Brightness",
|
|
||||||
"ui.card.light.color_temperature": "Color temperature",
|
|
||||||
"ui.card.light.white_value": "White value",
|
|
||||||
"ui.card.light.effect": "Effect",
|
|
||||||
"ui.card.lock.code": "Code",
|
|
||||||
"ui.card.lock.lock": "Lock",
|
|
||||||
"ui.card.lock.unlock": "Unlock",
|
|
||||||
"ui.card.media_player.source": "Source",
|
|
||||||
"ui.card.media_player.sound_mode": "Sound mode",
|
|
||||||
"ui.card.media_player.text_to_speak": "Text to speak",
|
|
||||||
"ui.card.persistent_notification.dismiss": "Dismiss",
|
|
||||||
"ui.card.scene.activate": "Activate",
|
|
||||||
"ui.card.script.execute": "Execute",
|
|
||||||
"ui.card.weather.attributes.air_pressure": "Air pressure",
|
|
||||||
"ui.card.weather.attributes.humidity": "Humidity",
|
|
||||||
"ui.card.weather.attributes.temperature": "Temperature",
|
|
||||||
"ui.card.weather.attributes.visibility": "Visibility",
|
|
||||||
"ui.card.weather.attributes.wind_speed": "Wind speed",
|
|
||||||
"ui.card.weather.cardinal_direction.e": "E",
|
|
||||||
"ui.card.weather.cardinal_direction.ene": "ENE",
|
|
||||||
"ui.card.weather.cardinal_direction.ese": "ESE",
|
|
||||||
"ui.card.weather.cardinal_direction.n": "N",
|
|
||||||
"ui.card.weather.cardinal_direction.ne": "NE",
|
|
||||||
"ui.card.weather.cardinal_direction.nne": "NNE",
|
|
||||||
"ui.card.weather.cardinal_direction.nw": "NW",
|
|
||||||
"ui.card.weather.cardinal_direction.nnw": "NNW",
|
|
||||||
"ui.card.weather.cardinal_direction.s": "S",
|
|
||||||
"ui.card.weather.cardinal_direction.se": "SE",
|
|
||||||
"ui.card.weather.cardinal_direction.sse": "SSE",
|
|
||||||
"ui.card.weather.cardinal_direction.ssw": "SSW",
|
|
||||||
"ui.card.weather.cardinal_direction.sw": "SW",
|
|
||||||
"ui.card.weather.cardinal_direction.w": "W",
|
|
||||||
"ui.card.weather.cardinal_direction.wnw": "WNW",
|
|
||||||
"ui.card.weather.cardinal_direction.wsw": "WSW",
|
|
||||||
"ui.card.weather.forecast": "Forecast",
|
|
||||||
"ui.common.loading": "Loading",
|
|
||||||
"ui.common.cancel": "Cancel",
|
|
||||||
"ui.components.entity.entity-picker.entity": "Entity",
|
|
||||||
"ui.components.relative_time.past": "{time} ago",
|
|
||||||
"ui.components.relative_time.future": "In {time}",
|
|
||||||
"ui.components.relative_time.never": "Never",
|
|
||||||
"ui.components.relative_time.duration.second":
|
|
||||||
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
|
|
||||||
"ui.components.relative_time.duration.minute":
|
|
||||||
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
|
||||||
"ui.components.relative_time.duration.hour":
|
|
||||||
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
|
|
||||||
"ui.components.relative_time.duration.day":
|
|
||||||
"{count} {count, plural,\n one {day}\n other {days}\n}",
|
|
||||||
"ui.components.relative_time.duration.week":
|
|
||||||
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
|
|
||||||
"ui.components.history_charts.loading_history": "Loading state history...",
|
|
||||||
"ui.components.history_charts.no_history_found": "No state history found.",
|
|
||||||
"ui.components.service-picker.service": "Service",
|
|
||||||
"ui.dialogs.more_info_settings.save": "Save",
|
|
||||||
"ui.dialogs.more_info_settings.name": "Name",
|
|
||||||
"ui.duration.second":
|
|
||||||
"{count} {count, plural,\n one {second}\n other {seconds}\n}",
|
|
||||||
"ui.duration.minute":
|
|
||||||
"{count} {count, plural,\n one {minute}\n other {minutes}\n}",
|
|
||||||
"ui.duration.hour":
|
|
||||||
"{count} {count, plural,\n one {hour}\n other {hours}\n}",
|
|
||||||
"ui.duration.day":
|
|
||||||
"{count} {count, plural,\n one {day}\n other {days}\n}",
|
|
||||||
"ui.duration.week":
|
|
||||||
"{count} {count, plural,\n one {week}\n other {weeks}\n}",
|
|
||||||
"ui.login-form.password": "Password",
|
|
||||||
"ui.login-form.remember": "Remember",
|
|
||||||
"ui.login-form.log_in": "Log in",
|
|
||||||
"ui.notification_toast.entity_turned_on": "Turned on {entity}.",
|
|
||||||
"ui.notification_toast.entity_turned_off": "Turned off {entity}.",
|
|
||||||
"ui.notification_toast.service_called": "Service {service} called.",
|
|
||||||
"ui.notification_toast.service_call_failed":
|
|
||||||
"Failed to call service {service}.",
|
|
||||||
"ui.notification_toast.connection_lost": "Connection lost. Reconnecting…",
|
|
||||||
"ui.sidebar.developer_tools": "Developer tools",
|
|
||||||
"ui.sidebar.log_out": "Log out",
|
|
||||||
"attribute.weather.humidity": "Humidity",
|
|
||||||
"attribute.weather.visibility": "Visibility",
|
|
||||||
"attribute.weather.wind_speed": "Wind speed",
|
|
||||||
},
|
|
||||||
};
|
|
@ -1,96 +0,0 @@
|
|||||||
export const demoServices = {
|
|
||||||
configurator: ["configure"],
|
|
||||||
tts: ["demo_say", "clear_cache"],
|
|
||||||
cover: [
|
|
||||||
"open_cover",
|
|
||||||
"close_cover",
|
|
||||||
"open_cover_tilt",
|
|
||||||
"close_cover_tilt",
|
|
||||||
"set_cover_tilt_position",
|
|
||||||
"set_cover_position",
|
|
||||||
"stop_cover_tilt",
|
|
||||||
"stop_cover",
|
|
||||||
],
|
|
||||||
group: ["set", "reload", "remove", "set_visibility"],
|
|
||||||
alarm_control_panel: [
|
|
||||||
"alarm_arm_night",
|
|
||||||
"alarm_disarm",
|
|
||||||
"alarm_trigger",
|
|
||||||
"alarm_arm_home",
|
|
||||||
"alarm_arm_away",
|
|
||||||
"alarm_arm_custom_bypass",
|
|
||||||
],
|
|
||||||
conversation: ["process"],
|
|
||||||
notify: ["demo_test_target_name", "notify"],
|
|
||||||
lock: ["open", "lock", "unlock"],
|
|
||||||
input_select: [
|
|
||||||
"select_previous",
|
|
||||||
"set_options",
|
|
||||||
"select_next",
|
|
||||||
"select_option",
|
|
||||||
],
|
|
||||||
recorder: ["purge"],
|
|
||||||
persistent_notification: ["create", "dismiss"],
|
|
||||||
timer: ["pause", "cancel", "finish", "start"],
|
|
||||||
input_boolean: ["turn_off", "toggle", "turn_on"],
|
|
||||||
fan: [
|
|
||||||
"set_speed",
|
|
||||||
"turn_on",
|
|
||||||
"turn_off",
|
|
||||||
"set_direction",
|
|
||||||
"oscillate",
|
|
||||||
"toggle",
|
|
||||||
],
|
|
||||||
climate: [
|
|
||||||
"set_humidity",
|
|
||||||
"set_operation_mode",
|
|
||||||
"set_aux_heat",
|
|
||||||
"turn_on",
|
|
||||||
"set_hold_mode",
|
|
||||||
"set_away_mode",
|
|
||||||
"turn_off",
|
|
||||||
"set_fan_mode",
|
|
||||||
"set_temperature",
|
|
||||||
"set_swing_mode",
|
|
||||||
],
|
|
||||||
switch: ["turn_off", "toggle", "turn_on"],
|
|
||||||
script: ["turn_off", "demo", "reload", "toggle", "turn_on"],
|
|
||||||
scene: ["turn_on"],
|
|
||||||
system_log: ["clear", "write"],
|
|
||||||
camera: ["disable_motion_detection", "enable_motion_detection", "snapshot"],
|
|
||||||
image_processing: ["scan"],
|
|
||||||
media_player: [
|
|
||||||
"media_previous_track",
|
|
||||||
"clear_playlist",
|
|
||||||
"shuffle_set",
|
|
||||||
"media_seek",
|
|
||||||
"turn_on",
|
|
||||||
"media_play_pause",
|
|
||||||
"media_next_track",
|
|
||||||
"media_pause",
|
|
||||||
"volume_down",
|
|
||||||
"volume_set",
|
|
||||||
"media_stop",
|
|
||||||
"toggle",
|
|
||||||
"media_play",
|
|
||||||
"play_media",
|
|
||||||
"volume_mute",
|
|
||||||
"turn_off",
|
|
||||||
"select_sound_mode",
|
|
||||||
"select_source",
|
|
||||||
"volume_up",
|
|
||||||
],
|
|
||||||
input_number: ["set_value", "increment", "decrement"],
|
|
||||||
device_tracker: ["see"],
|
|
||||||
homeassistant: [
|
|
||||||
"stop",
|
|
||||||
"check_config",
|
|
||||||
"reload_core_config",
|
|
||||||
"turn_on",
|
|
||||||
"turn_off",
|
|
||||||
"restart",
|
|
||||||
"toggle",
|
|
||||||
],
|
|
||||||
light: ["turn_off", "toggle", "turn_on"],
|
|
||||||
input_text: ["set_value"],
|
|
||||||
};
|
|
@ -1,112 +0,0 @@
|
|||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
|
||||||
|
|
||||||
import { demoConfig } from "./demo_config";
|
|
||||||
import { demoServices } from "./demo_services";
|
|
||||||
import demoResources from "./demo_resources";
|
|
||||||
|
|
||||||
const ensureArray = (val) => (Array.isArray(val) ? val : [val]);
|
|
||||||
|
|
||||||
export default (elements, { initialStates = {} } = {}) => {
|
|
||||||
elements = ensureArray(elements);
|
|
||||||
|
|
||||||
const wsCommands = {};
|
|
||||||
const restResponses = {};
|
|
||||||
let hass;
|
|
||||||
const entities = {};
|
|
||||||
|
|
||||||
function updateHass(obj) {
|
|
||||||
hass = Object.assign({}, hass, obj);
|
|
||||||
elements.forEach((el) => {
|
|
||||||
el.hass = hass;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateHass({
|
|
||||||
// Home Assistant properties
|
|
||||||
config: demoConfig,
|
|
||||||
services: demoServices,
|
|
||||||
language: "en",
|
|
||||||
resources: demoResources,
|
|
||||||
states: initialStates,
|
|
||||||
themes: {},
|
|
||||||
connection: {
|
|
||||||
subscribeEvents: async (callback, event) => {
|
|
||||||
console.log("subscribeEvents", event);
|
|
||||||
return () => console.log("unsubscribeEvents", event);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Mock properties
|
|
||||||
mockEntities: entities,
|
|
||||||
|
|
||||||
// Home Assistant functions
|
|
||||||
async callService(domain, service, data) {
|
|
||||||
fireEvent(elements[0], "show-notification", {
|
|
||||||
message: `Called service ${domain}/${service}`,
|
|
||||||
});
|
|
||||||
if (data.entity_id) {
|
|
||||||
await Promise.all(
|
|
||||||
ensureArray(data.entity_id).map((ent) =>
|
|
||||||
entities[ent].handleService(domain, service, data)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
console.log("unmocked callService", domain, service, data);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
async callWS(msg) {
|
|
||||||
const callback = wsCommands[msg.type];
|
|
||||||
return callback
|
|
||||||
? callback(msg)
|
|
||||||
: Promise.reject({
|
|
||||||
code: "command_not_mocked",
|
|
||||||
message: "This command is not implemented in the gallery.",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
async sendWS(msg) {
|
|
||||||
const callback = wsCommands[msg.type];
|
|
||||||
|
|
||||||
if (callback) {
|
|
||||||
callback(msg);
|
|
||||||
} else {
|
|
||||||
console.error(`Unknown command: ${msg.type}`);
|
|
||||||
}
|
|
||||||
console.log("sendWS", msg);
|
|
||||||
},
|
|
||||||
|
|
||||||
async callApi(method, path, parameters) {
|
|
||||||
const callback = restResponses[path];
|
|
||||||
|
|
||||||
return callback
|
|
||||||
? callback(method, path, parameters)
|
|
||||||
: Promise.reject(`Mock for {path} is not implemented`);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Mock functions
|
|
||||||
updateHass,
|
|
||||||
updateStates(newStates) {
|
|
||||||
updateHass({
|
|
||||||
states: Object.assign({}, hass.states, newStates),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addEntities(newEntities) {
|
|
||||||
const states = {};
|
|
||||||
ensureArray(newEntities).forEach((ent) => {
|
|
||||||
ent.hass = hass;
|
|
||||||
entities[ent.entityId] = ent;
|
|
||||||
states[ent.entityId] = ent.toState();
|
|
||||||
});
|
|
||||||
this.updateStates(states);
|
|
||||||
},
|
|
||||||
mockWS(type, callback) {
|
|
||||||
wsCommands[type] = callback;
|
|
||||||
},
|
|
||||||
mockAPI(path, callback) {
|
|
||||||
restResponses[path] = callback;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return hass;
|
|
||||||
};
|
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
@ -48,7 +48,8 @@ const CONFIGS = [
|
|||||||
config: `
|
config: `
|
||||||
- type: entity-button
|
- type: entity-button
|
||||||
entity: light.bed_light
|
entity: light.bed_light
|
||||||
tap_action: toggle
|
tap_action:
|
||||||
|
action: toggle
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
import "../components/demo-cards";
|
import "../components/demo-cards";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
|
@ -4,8 +4,8 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|||||||
import "../../../src/dialogs/more-info/controls/more-info-content";
|
import "../../../src/dialogs/more-info/controls/more-info-content";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
|
|
||||||
import getEntity from "../data/entity";
|
import { getEntity } from "../../../src/fake_data/entity";
|
||||||
import provideHass from "../data/provide_hass";
|
import { provideHass } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
import "../components/demo-more-infos";
|
import "../components/demo-more-infos";
|
||||||
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
|
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
|
||||||
|
@ -2,12 +2,13 @@ const path = require("path");
|
|||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const foreach = require("gulp-foreach");
|
const foreach = require("gulp-foreach");
|
||||||
const hash = require("gulp-hash");
|
const hash = require("gulp-hash");
|
||||||
const insert = require("gulp-insert");
|
|
||||||
const merge = require("gulp-merge-json");
|
const merge = require("gulp-merge-json");
|
||||||
const minify = require("gulp-jsonminify");
|
const minify = require("gulp-jsonminify");
|
||||||
const rename = require("gulp-rename");
|
const rename = require("gulp-rename");
|
||||||
const transform = require("gulp-json-transform");
|
const transform = require("gulp-json-transform");
|
||||||
|
|
||||||
|
const isDemo = process.env.DEMO === "1";
|
||||||
|
|
||||||
const inDir = "translations";
|
const inDir = "translations";
|
||||||
const workDir = "build-translations";
|
const workDir = "build-translations";
|
||||||
const fullDir = workDir + "/full";
|
const fullDir = workDir + "/full";
|
||||||
@ -230,7 +231,7 @@ gulp.task(taskName, ["build-flattened-translations"], function() {
|
|||||||
hash({
|
hash({
|
||||||
algorithm: "md5",
|
algorithm: "md5",
|
||||||
hashLength: 32,
|
hashLength: 32,
|
||||||
template: "<%= name %>-<%= hash %>.json",
|
template: isDemo ? "<%= name %>.json" : "<%= name %>-<%= hash %>.json",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(hash.manifest("translationFingerprints.json"))
|
.pipe(hash.manifest("translationFingerprints.json"))
|
||||||
|