Compare commits
860 Commits
20190601.0
...
remove-lig
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c1eabeb29f | ||
![]() |
5ff8fe68ba | ||
![]() |
a2a039ebc5 | ||
![]() |
1064aed1b0 | ||
![]() |
7025592e8e | ||
![]() |
4966354b62 | ||
![]() |
68d6faf4af | ||
![]() |
e3346483b9 | ||
![]() |
e8fb79e5ce | ||
![]() |
d612162ab1 | ||
![]() |
86f8ef3a70 | ||
![]() |
0e43435362 | ||
![]() |
aaefe0b09f | ||
![]() |
bc731a9dc3 | ||
![]() |
da25701dca | ||
![]() |
21ae483dc9 | ||
![]() |
38b6e9ca10 | ||
![]() |
d31245866c | ||
![]() |
4e08d8f3b3 | ||
![]() |
1e717ab33e | ||
![]() |
995fb4974e | ||
![]() |
ffb76132f8 | ||
![]() |
acba3af54b | ||
![]() |
40ac456937 | ||
![]() |
5c32413bf7 | ||
![]() |
22792c70c5 | ||
![]() |
a8ed87298a | ||
![]() |
b15270dfe2 | ||
![]() |
58ad949bc8 | ||
![]() |
adce40de56 | ||
![]() |
0f487ae4bf | ||
![]() |
2848e3a63b | ||
![]() |
5a172a64c5 | ||
![]() |
433aa16ea6 | ||
![]() |
50cb8cf3cc | ||
![]() |
4e5406b27b | ||
![]() |
80eb80619a | ||
![]() |
bf71b3a869 | ||
![]() |
ff270c4b7d | ||
![]() |
5415068917 | ||
![]() |
357a67c00d | ||
![]() |
cbe4269320 | ||
![]() |
fbd5185ce2 | ||
![]() |
a33cf97e2c | ||
![]() |
7e7da26543 | ||
![]() |
79058e893b | ||
![]() |
2eb548bb74 | ||
![]() |
08baf8a757 | ||
![]() |
f02fa6a94b | ||
![]() |
2ed6d0e73c | ||
![]() |
35d9b2ac3c | ||
![]() |
18d09c6f04 | ||
![]() |
70b81de49d | ||
![]() |
f0808c1f54 | ||
![]() |
e779f0747e | ||
![]() |
bdd18775c3 | ||
![]() |
711d51c022 | ||
![]() |
1b0d8bba29 | ||
![]() |
2988cc512f | ||
![]() |
a2f8e5f3e7 | ||
![]() |
680bf06a4b | ||
![]() |
ff0b1881e2 | ||
![]() |
de653e1f7b | ||
![]() |
bb41170765 | ||
![]() |
0ed2bc93aa | ||
![]() |
04770f8ee2 | ||
![]() |
15a2790b9f | ||
![]() |
83880791b1 | ||
![]() |
4dca3289f6 | ||
![]() |
083a3ebfc4 | ||
![]() |
6117c4e989 | ||
![]() |
609763e658 | ||
![]() |
2c57ab60f1 | ||
![]() |
dd17a153d2 | ||
![]() |
c2d551bb7c | ||
![]() |
e0b1921108 | ||
![]() |
fcf39ceb96 | ||
![]() |
3cc979a077 | ||
![]() |
9972973774 | ||
![]() |
20ae32bc26 | ||
![]() |
a29892023b | ||
![]() |
b283fec482 | ||
![]() |
e0116a8236 | ||
![]() |
d1990a4bac | ||
![]() |
cbba1849e2 | ||
![]() |
43393d1647 | ||
![]() |
b47ee1051c | ||
![]() |
393adacc9e | ||
![]() |
073428849e | ||
![]() |
e6ac0258e3 | ||
![]() |
d7e7798a55 | ||
![]() |
2557414b11 | ||
![]() |
f7065fbce9 | ||
![]() |
016564eee9 | ||
![]() |
ff3087c39c | ||
![]() |
239438ee5d | ||
![]() |
5458cda31f | ||
![]() |
36f49e66fd | ||
![]() |
2bafd38ea8 | ||
![]() |
73b3262491 | ||
![]() |
808cde033f | ||
![]() |
fa8f6b7b91 | ||
![]() |
94c120cdb1 | ||
![]() |
7b2be54f8f | ||
![]() |
4b56db5255 | ||
![]() |
93165c9111 | ||
![]() |
caa604d5ca | ||
![]() |
e7e9e2cf85 | ||
![]() |
daa04e9973 | ||
![]() |
5355269f5d | ||
![]() |
2665a75250 | ||
![]() |
8a39d18323 | ||
![]() |
b8a026397b | ||
![]() |
bd5fe302eb | ||
![]() |
de0f1b2b65 | ||
![]() |
defaa2b276 | ||
![]() |
60efe00a1f | ||
![]() |
fe93b993db | ||
![]() |
f6afc92d3c | ||
![]() |
e4c635c855 | ||
![]() |
a3e59e168f | ||
![]() |
e56355b406 | ||
![]() |
8ef15c50b4 | ||
![]() |
81588469b8 | ||
![]() |
70a920af3c | ||
![]() |
1329e60c89 | ||
![]() |
9b7c095080 | ||
![]() |
654ff99cd1 | ||
![]() |
0511bc360e | ||
![]() |
ea9e8cc392 | ||
![]() |
8433678371 | ||
![]() |
757bc00854 | ||
![]() |
2551393821 | ||
![]() |
0acd41b7f0 | ||
![]() |
85ca73db84 | ||
![]() |
444cbd00d9 | ||
![]() |
15b500886c | ||
![]() |
3aac834e72 | ||
![]() |
6edf23b91f | ||
![]() |
e445251b02 | ||
![]() |
693151b590 | ||
![]() |
1249c0eea9 | ||
![]() |
3133118870 | ||
![]() |
de5c1a0545 | ||
![]() |
c61e2fb459 | ||
![]() |
64a2a19da3 | ||
![]() |
74fe1f820c | ||
![]() |
69929f5dc3 | ||
![]() |
fcd793fc9e | ||
![]() |
8a3b1d76a1 | ||
![]() |
9f520d7628 | ||
![]() |
258cfddc3f | ||
![]() |
3697500402 | ||
![]() |
b4942ad27e | ||
![]() |
1e217e8d2f | ||
![]() |
0056237d85 | ||
![]() |
920ee741f3 | ||
![]() |
6ecc60423f | ||
![]() |
09e7638c89 | ||
![]() |
b82b4a639e | ||
![]() |
d08aa51c16 | ||
![]() |
385ffe6d8f | ||
![]() |
564e6d4073 | ||
![]() |
a4bd816eb5 | ||
![]() |
13c18a9bb7 | ||
![]() |
562d7a7cf4 | ||
![]() |
89f33a1730 | ||
![]() |
ff7309f5c4 | ||
![]() |
1c614c855f | ||
![]() |
6a3238951d | ||
![]() |
0dab5828fb | ||
![]() |
d0b9c09f8f | ||
![]() |
55f4629256 | ||
![]() |
004565217e | ||
![]() |
c07b39ebde | ||
![]() |
8b17b6ed1c | ||
![]() |
1d16bdbe54 | ||
![]() |
9e2a0c77d5 | ||
![]() |
4f41508110 | ||
![]() |
eaedb2e5ae | ||
![]() |
75ad1f51a9 | ||
![]() |
142175c6ab | ||
![]() |
f1980d6bcf | ||
![]() |
5a7b5200fe | ||
![]() |
d284d53b93 | ||
![]() |
bc01df42d8 | ||
![]() |
901752bec3 | ||
![]() |
e3ef3cfae1 | ||
![]() |
ab476d2f1b | ||
![]() |
5ca82fd39c | ||
![]() |
da35c263d2 | ||
![]() |
2a617a9639 | ||
![]() |
c730aab28f | ||
![]() |
274c2016c0 | ||
![]() |
9b3891f778 | ||
![]() |
b705de956e | ||
![]() |
e37201f84f | ||
![]() |
f53eea81c4 | ||
![]() |
0fa8db1682 | ||
![]() |
46f5224e70 | ||
![]() |
12be2a9775 | ||
![]() |
6196bbdc5e | ||
![]() |
b41f4777d4 | ||
![]() |
f2812bc706 | ||
![]() |
04500bc237 | ||
![]() |
2a6b877cf1 | ||
![]() |
c3896a4613 | ||
![]() |
c6fb896fe4 | ||
![]() |
669fbb7e77 | ||
![]() |
971865e4f9 | ||
![]() |
9078e41855 | ||
![]() |
466c48a7d0 | ||
![]() |
31a047ce9e | ||
![]() |
bd24ffa5d0 | ||
![]() |
99f4bd7398 | ||
![]() |
417177b097 | ||
![]() |
c407cab501 | ||
![]() |
044cf22f47 | ||
![]() |
75aa940d44 | ||
![]() |
7be8080726 | ||
![]() |
13fbc813cd | ||
![]() |
44d1458229 | ||
![]() |
f06f3ee2e5 | ||
![]() |
a889a02e15 | ||
![]() |
6bf3d6a689 | ||
![]() |
1d7dcca495 | ||
![]() |
ad8f049570 | ||
![]() |
73c56a68b6 | ||
![]() |
b34b52f305 | ||
![]() |
39d052273d | ||
![]() |
e435b9153b | ||
![]() |
0792278927 | ||
![]() |
06d59b3cde | ||
![]() |
1e7497ad33 | ||
![]() |
49d0f2359b | ||
![]() |
bb73039205 | ||
![]() |
d4d6b7e2ce | ||
![]() |
7b5201599d | ||
![]() |
11c08e9a69 | ||
![]() |
731bb176f7 | ||
![]() |
b0fce93de8 | ||
![]() |
fdbe89e87e | ||
![]() |
a8d0a2293f | ||
![]() |
8ac278bc59 | ||
![]() |
70d6c6b902 | ||
![]() |
0621218e16 | ||
![]() |
2424376fba | ||
![]() |
3973374f3f | ||
![]() |
c25a38b82f | ||
![]() |
3c0ba1d7eb | ||
![]() |
be678b02c5 | ||
![]() |
0078b48e3c | ||
![]() |
540f1d9bce | ||
![]() |
5e3cb812ec | ||
![]() |
6d10a5dd4c | ||
![]() |
96d14b7ab7 | ||
![]() |
b96b026905 | ||
![]() |
c25f2d3941 | ||
![]() |
785453aa79 | ||
![]() |
4dbf5327bd | ||
![]() |
603240c467 | ||
![]() |
bbc3e7d93f | ||
![]() |
fbee4937a0 | ||
![]() |
0a77728652 | ||
![]() |
e3ed0cf436 | ||
![]() |
d05dc2e4dc | ||
![]() |
c437cd3865 | ||
![]() |
442171169b | ||
![]() |
cc12dbb6ee | ||
![]() |
60b3a960ae | ||
![]() |
5a957c3c9e | ||
![]() |
be4d431dc3 | ||
![]() |
0005c75091 | ||
![]() |
880b382a16 | ||
![]() |
d012512a79 | ||
![]() |
e2ac842690 | ||
![]() |
67d8d48855 | ||
![]() |
00f2d36cb5 | ||
![]() |
035057b185 | ||
![]() |
982966c8d9 | ||
![]() |
f5e3a9ad40 | ||
![]() |
141c3f1ea4 | ||
![]() |
4ea483e3de | ||
![]() |
8eca956cd1 | ||
![]() |
c9242a5075 | ||
![]() |
df29a5becb | ||
![]() |
fb589337f8 | ||
![]() |
ea5ee6189d | ||
![]() |
a39e47cced | ||
![]() |
49d69f65ad | ||
![]() |
424d677bcb | ||
![]() |
59e4cdc62a | ||
![]() |
9d3dfad98c | ||
![]() |
555b746f4b | ||
![]() |
ce6a97d065 | ||
![]() |
88567df36d | ||
![]() |
f55cbd9e9a | ||
![]() |
7d00cc1eff | ||
![]() |
29301ddee7 | ||
![]() |
978b773968 | ||
![]() |
4f30cae6aa | ||
![]() |
5f29b66a8d | ||
![]() |
b94da1bd19 | ||
![]() |
f9b0a0fc13 | ||
![]() |
300ffdae04 | ||
![]() |
476525e0d4 | ||
![]() |
edecf9d58f | ||
![]() |
38bf2e116b | ||
![]() |
0719c4d1ae | ||
![]() |
12840231be | ||
![]() |
4728c12225 | ||
![]() |
90526ac563 | ||
![]() |
6f7ea03e35 | ||
![]() |
78900e05ad | ||
![]() |
495f4aa19c | ||
![]() |
88c480759f | ||
![]() |
ab75365636 | ||
![]() |
0266617c71 | ||
![]() |
aef45c5043 | ||
![]() |
deeb0146c7 | ||
![]() |
5dea674f20 | ||
![]() |
646fe34d09 | ||
![]() |
c67907aa58 | ||
![]() |
e78f4c5ace | ||
![]() |
e891fdc3eb | ||
![]() |
95a258c2a5 | ||
![]() |
f1fabd09a6 | ||
![]() |
0d77bdaf32 | ||
![]() |
320be2e5d9 | ||
![]() |
6a098ad0b5 | ||
![]() |
e895e91a11 | ||
![]() |
fc3f7ca4b2 | ||
![]() |
1f09d848c5 | ||
![]() |
4d794f6088 | ||
![]() |
9ad7f0dbac | ||
![]() |
9f39610153 | ||
![]() |
12d8a04c15 | ||
![]() |
73b0f5949e | ||
![]() |
0f7a3887a7 | ||
![]() |
ac75ce038a | ||
![]() |
8de9a73741 | ||
![]() |
ef51f29e28 | ||
![]() |
b61bbee35a | ||
![]() |
64dd8c463d | ||
![]() |
d2a95e9f06 | ||
![]() |
0cb0525516 | ||
![]() |
dcaf4fdfe2 | ||
![]() |
0c13757910 | ||
![]() |
0cdcd74c9d | ||
![]() |
db3968399f | ||
![]() |
7494a49238 | ||
![]() |
55d2a3c8b1 | ||
![]() |
be4e45c22c | ||
![]() |
efb28d337a | ||
![]() |
edd77e1f32 | ||
![]() |
848dd7e071 | ||
![]() |
59d4a4247a | ||
![]() |
ba79633758 | ||
![]() |
860973bdbd | ||
![]() |
d4d897e79e | ||
![]() |
4850f3d588 | ||
![]() |
8bc53c235f | ||
![]() |
c74793b1d5 | ||
![]() |
56bac8a8c1 | ||
![]() |
184575fd54 | ||
![]() |
e148559d3e | ||
![]() |
95b76dbb85 | ||
![]() |
496bb9dc39 | ||
![]() |
351ba3e701 | ||
![]() |
260f428bc6 | ||
![]() |
3622514131 | ||
![]() |
391b2dcf6a | ||
![]() |
a02bf1fd48 | ||
![]() |
4cf9472bf4 | ||
![]() |
74d1de7313 | ||
![]() |
cd6fd6a46c | ||
![]() |
a6dda90b13 | ||
![]() |
7add8a2ea0 | ||
![]() |
b927a3ef29 | ||
![]() |
76d3218130 | ||
![]() |
8b6d8f9086 | ||
![]() |
ffaecb29b7 | ||
![]() |
fa74295c0b | ||
![]() |
ea50d486da | ||
![]() |
3cf4b890b6 | ||
![]() |
313b984a53 | ||
![]() |
7d09e29d60 | ||
![]() |
7e979f0cf1 | ||
![]() |
64366dc99a | ||
![]() |
c69585db98 | ||
![]() |
2dd5cd586b | ||
![]() |
05a258c886 | ||
![]() |
f4bd42dfd4 | ||
![]() |
41e5e7c1ae | ||
![]() |
95dfcafce3 | ||
![]() |
111d1afc21 | ||
![]() |
886c6dd88c | ||
![]() |
38b817bd67 | ||
![]() |
c59b6626f2 | ||
![]() |
2cc196e3fb | ||
![]() |
a08884fed6 | ||
![]() |
2fe4a02b6b | ||
![]() |
7c793c1cdb | ||
![]() |
a0b848acc4 | ||
![]() |
a1b9a092d0 | ||
![]() |
993d390ea5 | ||
![]() |
1f4d359050 | ||
![]() |
f871387fa6 | ||
![]() |
9a92ed31f6 | ||
![]() |
37129adfab | ||
![]() |
ec52e71c71 | ||
![]() |
5e28e1b320 | ||
![]() |
9a7eb3d406 | ||
![]() |
eee0c2e53f | ||
![]() |
145259e82f | ||
![]() |
d0cc4c2715 | ||
![]() |
4d97a47e08 | ||
![]() |
4ef5a8da70 | ||
![]() |
cdfd0afdf4 | ||
![]() |
d250a931e6 | ||
![]() |
cd2b92a449 | ||
![]() |
c617cb5b12 | ||
![]() |
e7ac95e314 | ||
![]() |
7bab9cb464 | ||
![]() |
bb5ab958c1 | ||
![]() |
2d92ffaa4d | ||
![]() |
7a7a0f772a | ||
![]() |
c898db5010 | ||
![]() |
b6fbf4da3a | ||
![]() |
0bfc61629e | ||
![]() |
e594fcfc42 | ||
![]() |
84ed6d8fb3 | ||
![]() |
31ae115062 | ||
![]() |
fca885a17a | ||
![]() |
29dff42de4 | ||
![]() |
f5b3a82922 | ||
![]() |
54beaad7e5 | ||
![]() |
e30f9d4a66 | ||
![]() |
27264b27a9 | ||
![]() |
2b1f9460a8 | ||
![]() |
4641cd65ca | ||
![]() |
1f6fe5dfcf | ||
![]() |
058b4ba658 | ||
![]() |
24baa87b18 | ||
![]() |
fad2f1790f | ||
![]() |
8fd8274d15 | ||
![]() |
f4f1e24ad5 | ||
![]() |
42626ba2f8 | ||
![]() |
29ab04fc7a | ||
![]() |
722e9bcda7 | ||
![]() |
065e42c8fd | ||
![]() |
bf343647d4 | ||
![]() |
3b51e55f2d | ||
![]() |
125616aa99 | ||
![]() |
1341fe9ae9 | ||
![]() |
b195df0bfa | ||
![]() |
1109d18576 | ||
![]() |
b1a6580afb | ||
![]() |
1d95b9d779 | ||
![]() |
202782e741 | ||
![]() |
a4663d438c | ||
![]() |
eab3e6091a | ||
![]() |
6627a96a05 | ||
![]() |
16ae52c321 | ||
![]() |
9792572370 | ||
![]() |
4bb65b8ae1 | ||
![]() |
2f3b399450 | ||
![]() |
3e98b8e4f1 | ||
![]() |
493198f530 | ||
![]() |
ce9e3ae9e9 | ||
![]() |
a2c2f6a1e2 | ||
![]() |
b46c9406ff | ||
![]() |
9f213cf055 | ||
![]() |
3254478d05 | ||
![]() |
e78fb35593 | ||
![]() |
321b852079 | ||
![]() |
8b44998e1f | ||
![]() |
4aeca70f49 | ||
![]() |
7912f0bf9e | ||
![]() |
abc849f623 | ||
![]() |
e6671299fe | ||
![]() |
8c5beb0042 | ||
![]() |
eba3c535bf | ||
![]() |
34d50f0c90 | ||
![]() |
9eae637814 | ||
![]() |
a29d598027 | ||
![]() |
5448cbf1c5 | ||
![]() |
f2999c30f3 | ||
![]() |
8a710202f1 | ||
![]() |
11f917d5f8 | ||
![]() |
2d8d6119bd | ||
![]() |
1a5ae99c42 | ||
![]() |
c4d888f060 | ||
![]() |
594ee7ce9b | ||
![]() |
7f10bcbfd1 | ||
![]() |
fe31f532b6 | ||
![]() |
7e7158b816 | ||
![]() |
e19c210af2 | ||
![]() |
a2f23c068b | ||
![]() |
205e12150f | ||
![]() |
b7ea66c30f | ||
![]() |
11ac8e4b08 | ||
![]() |
d5f0ae8ae2 | ||
![]() |
4c37c76a8f | ||
![]() |
cdfc3f8faf | ||
![]() |
44ca37c1dc | ||
![]() |
535308bf96 | ||
![]() |
6328f15032 | ||
![]() |
2f96a096f7 | ||
![]() |
cbd01f2d68 | ||
![]() |
2ff4d0fa4b | ||
![]() |
3aba2e3408 | ||
![]() |
b473c9c2aa | ||
![]() |
b97e24283c | ||
![]() |
c8d3293ae9 | ||
![]() |
8e0c39e451 | ||
![]() |
46968bb565 | ||
![]() |
011219b727 | ||
![]() |
9205837b67 | ||
![]() |
4eed3508ce | ||
![]() |
460a56aa0a | ||
![]() |
3927eb53ac | ||
![]() |
2a596666c8 | ||
![]() |
0008a100f4 | ||
![]() |
164e433592 | ||
![]() |
abb9190c98 | ||
![]() |
c4fca84ded | ||
![]() |
48a010563e | ||
![]() |
4378904243 | ||
![]() |
ba66bf88d3 | ||
![]() |
5282a6504a | ||
![]() |
4f3abe1025 | ||
![]() |
5bcba95c25 | ||
![]() |
a9c9d4ca51 | ||
![]() |
f00ad84c16 | ||
![]() |
3b2e02562c | ||
![]() |
7bc947ffb0 | ||
![]() |
15564a1b26 | ||
![]() |
753e069323 | ||
![]() |
b37a0e2d43 | ||
![]() |
87b35010e0 | ||
![]() |
4e383e3e67 | ||
![]() |
0e82178973 | ||
![]() |
fe2046c6cd | ||
![]() |
af0304bf78 | ||
![]() |
fcd206e94b | ||
![]() |
cf7a300614 | ||
![]() |
a97ce49f0b | ||
![]() |
5bfdc98217 | ||
![]() |
b022128031 | ||
![]() |
1bc2e6fc17 | ||
![]() |
6b5c9efb39 | ||
![]() |
be0c035ba1 | ||
![]() |
12173388a0 | ||
![]() |
ba0d7cb156 | ||
![]() |
c3e29e359a | ||
![]() |
6259e45128 | ||
![]() |
6998cce8eb | ||
![]() |
f43abb5a9d | ||
![]() |
a7fdbc069b | ||
![]() |
b154903691 | ||
![]() |
15a88385c2 | ||
![]() |
6ddf364093 | ||
![]() |
fccb97ede8 | ||
![]() |
cfc6bf4da9 | ||
![]() |
02e250cd04 | ||
![]() |
d29eacb268 | ||
![]() |
62ae7df097 | ||
![]() |
0d43bef600 | ||
![]() |
3709c13975 | ||
![]() |
b624b363bd | ||
![]() |
d841cc92ef | ||
![]() |
cdcafe9e6f | ||
![]() |
a66960fa00 | ||
![]() |
38cc7b1090 | ||
![]() |
ac443c2fa0 | ||
![]() |
ee0388708f | ||
![]() |
0717a3dadd | ||
![]() |
6b0b66af99 | ||
![]() |
7e5f28b3cc | ||
![]() |
c9307ab76a | ||
![]() |
ecfbfbf56b | ||
![]() |
9b321124bb | ||
![]() |
512b76f450 | ||
![]() |
5de8c713c8 | ||
![]() |
7482059373 | ||
![]() |
f64062d17b | ||
![]() |
afd6fddad7 | ||
![]() |
e8ad975212 | ||
![]() |
831b23347e | ||
![]() |
5edee41c5b | ||
![]() |
c04a091f59 | ||
![]() |
3bbd45079c | ||
![]() |
01da25d2d6 | ||
![]() |
355e3d7911 | ||
![]() |
6c109c15ef | ||
![]() |
c542b242fe | ||
![]() |
bcb26bd960 | ||
![]() |
3a3c705343 | ||
![]() |
46f3a38b7c | ||
![]() |
864175bde9 | ||
![]() |
f458bdffe0 | ||
![]() |
200e099035 | ||
![]() |
07b8518162 | ||
![]() |
b3525abf21 | ||
![]() |
f7bb85d332 | ||
![]() |
b8a18a27a4 | ||
![]() |
88bea10b26 | ||
![]() |
807dff99af | ||
![]() |
9fa8544972 | ||
![]() |
806e70b6c9 | ||
![]() |
204bd803bf | ||
![]() |
52712f65c2 | ||
![]() |
8c3f8656fe | ||
![]() |
1f3a5b1396 | ||
![]() |
c15629b81b | ||
![]() |
ef3892de92 | ||
![]() |
47d6bb69b0 | ||
![]() |
f10fab7e22 | ||
![]() |
e2dfac48d0 | ||
![]() |
53f5a29151 | ||
![]() |
a042cd2d48 | ||
![]() |
8533f9372f | ||
![]() |
a4e96a4f3f | ||
![]() |
fa40135a27 | ||
![]() |
d85f9f9021 | ||
![]() |
dc2ee2e63f | ||
![]() |
f3729759b7 | ||
![]() |
f108e279cd | ||
![]() |
8dce24ddfc | ||
![]() |
d2e780dda2 | ||
![]() |
c382768008 | ||
![]() |
f369045f35 | ||
![]() |
17921c18b6 | ||
![]() |
42c6cecf89 | ||
![]() |
4799fdee9c | ||
![]() |
2049687590 | ||
![]() |
aca5ae9f67 | ||
![]() |
de04f60821 | ||
![]() |
98b882d599 | ||
![]() |
5b02a43c3f | ||
![]() |
2da844a1fb | ||
![]() |
0544027c38 | ||
![]() |
2389f92448 | ||
![]() |
1f13c00937 | ||
![]() |
2fda2ee742 | ||
![]() |
17a3affb6f | ||
![]() |
f6be398fb9 | ||
![]() |
87e24d658b | ||
![]() |
abf70c3a3e | ||
![]() |
b9afa69ee5 | ||
![]() |
d9628fd9a2 | ||
![]() |
a617eac284 | ||
![]() |
7d90429fa9 | ||
![]() |
fa6d0949a2 | ||
![]() |
aab967798a | ||
![]() |
c523bae2c8 | ||
![]() |
b77372fc9a | ||
![]() |
70b06861d1 | ||
![]() |
b158f15d93 | ||
![]() |
4edcd5f2ef | ||
![]() |
689e37782e | ||
![]() |
dcfed5d7e1 | ||
![]() |
54ea6176aa | ||
![]() |
a91bb3cdbb | ||
![]() |
6abbe72e4d | ||
![]() |
dae0ecce6a | ||
![]() |
c3118eada9 | ||
![]() |
0f6d0b164f | ||
![]() |
87293e4b15 | ||
![]() |
ff80eef25d | ||
![]() |
973c190bb6 | ||
![]() |
0cd263c532 | ||
![]() |
3c366b2b85 | ||
![]() |
a59f0086b5 | ||
![]() |
1f1a3acc03 | ||
![]() |
d09cf9c8ab | ||
![]() |
f32eb971a4 | ||
![]() |
56c08a1d07 | ||
![]() |
a44b1d01ed | ||
![]() |
2fd75742f1 | ||
![]() |
70b18344b6 | ||
![]() |
5ec58a723e | ||
![]() |
8dd44bca32 | ||
![]() |
dcb975c8ce | ||
![]() |
ea0a0f510d | ||
![]() |
9476557aee | ||
![]() |
4555bd4240 | ||
![]() |
75c7445dd9 | ||
![]() |
da741238d2 | ||
![]() |
3d0c994b9a | ||
![]() |
ab4b4796c0 | ||
![]() |
a7077dbcb4 | ||
![]() |
a66013ecd7 | ||
![]() |
8265a55838 | ||
![]() |
95d6cbd130 | ||
![]() |
1ee9811644 | ||
![]() |
99c5f2a88a | ||
![]() |
cdfd9cea5c | ||
![]() |
4f2b82d787 | ||
![]() |
3fd0ee9d75 | ||
![]() |
c7f7e72340 | ||
![]() |
1205322342 | ||
![]() |
4cefb9715c | ||
![]() |
35b38db57f | ||
![]() |
4f72eb5416 | ||
![]() |
f3d1a421f4 | ||
![]() |
f3c24dc0b3 | ||
![]() |
e4cbdc29a2 | ||
![]() |
c985977efc | ||
![]() |
8fb991c5ce | ||
![]() |
210c63ad14 | ||
![]() |
8167b05cad | ||
![]() |
e5a916032a | ||
![]() |
56745b3723 | ||
![]() |
ddf2c6cc0f | ||
![]() |
84df2bd531 | ||
![]() |
42c3e3e46c | ||
![]() |
5141e0e923 | ||
![]() |
b87c94e395 | ||
![]() |
55aa5a0d12 | ||
![]() |
eaaeb10c6d | ||
![]() |
567769be5a | ||
![]() |
3ebb30bd48 | ||
![]() |
09a19d2e7f | ||
![]() |
fabc49d17e | ||
![]() |
00e9155546 | ||
![]() |
8238b700b0 | ||
![]() |
5ff33224ed | ||
![]() |
07dee9c5bb | ||
![]() |
9eaeafdd6a | ||
![]() |
beb1fe1e64 | ||
![]() |
cdb2a1a424 | ||
![]() |
8bbc442b7e | ||
![]() |
7a12cbf96e | ||
![]() |
e36454f08f | ||
![]() |
3865c1943c | ||
![]() |
e7e3edfd97 | ||
![]() |
4bdc82f0ed | ||
![]() |
8e3b41885d | ||
![]() |
8f3d5fdb7d | ||
![]() |
f258aa2818 | ||
![]() |
b4dd971829 | ||
![]() |
e99d6f8e6a | ||
![]() |
cc969e547c | ||
![]() |
0e1ae3926b | ||
![]() |
60c2bcc483 | ||
![]() |
5d8e34e8be | ||
![]() |
14a430a059 | ||
![]() |
4ae347949a | ||
![]() |
cdd007cc54 | ||
![]() |
2929db5ba4 | ||
![]() |
628692b2e9 | ||
![]() |
7cfdc24a8c | ||
![]() |
1c69aa122b | ||
![]() |
25afb73ed7 | ||
![]() |
5b5384032d | ||
![]() |
a9d221147f | ||
![]() |
4fdbec93b3 | ||
![]() |
0a8703ad0a | ||
![]() |
ddc11c1b12 | ||
![]() |
317f43277e | ||
![]() |
bf90642c9b | ||
![]() |
6f77992387 | ||
![]() |
deaccd6cd4 | ||
![]() |
d7371ace6a | ||
![]() |
453b1000c1 | ||
![]() |
8c1aff7505 | ||
![]() |
adf002c154 | ||
![]() |
ed7b81e7a4 | ||
![]() |
c0f6ee6a32 | ||
![]() |
9408df6099 | ||
![]() |
157bfd6f80 | ||
![]() |
99da7ebfe6 | ||
![]() |
6911df9ac4 | ||
![]() |
8daeaab40b | ||
![]() |
45c3c78b31 | ||
![]() |
a64a35b861 | ||
![]() |
5a25627219 | ||
![]() |
203b14613f | ||
![]() |
0a7cb39500 | ||
![]() |
42e75e7cdf | ||
![]() |
58e6be12af | ||
![]() |
618d25ce48 | ||
![]() |
9974510067 | ||
![]() |
2faa0c5979 | ||
![]() |
1479647062 | ||
![]() |
3becefaf8b | ||
![]() |
e804e62e66 | ||
![]() |
2c3cc1fbc7 | ||
![]() |
58cc76ab5a | ||
![]() |
5783cdb0d2 | ||
![]() |
4f07caebc6 | ||
![]() |
c4b75b4534 | ||
![]() |
ae82eabaec | ||
![]() |
f8d3e55fe0 | ||
![]() |
1462db0a76 | ||
![]() |
86b36fb76b | ||
![]() |
c6194622b1 | ||
![]() |
be5c3efb23 | ||
![]() |
999c243c94 | ||
![]() |
483f82e554 | ||
![]() |
e91f4567c2 | ||
![]() |
029467139d | ||
![]() |
29649abe3d | ||
![]() |
266c80320b | ||
![]() |
ae51300446 | ||
![]() |
cbdb222f72 | ||
![]() |
98c419ff03 | ||
![]() |
88b9348a81 | ||
![]() |
3e8606781e | ||
![]() |
875afbd7ae | ||
![]() |
3139b914d7 | ||
![]() |
212a44b6ae | ||
![]() |
60551168a2 | ||
![]() |
32d9a6884f | ||
![]() |
7002ab27c0 | ||
![]() |
15c101109e | ||
![]() |
316fed953a | ||
![]() |
93934449c0 | ||
![]() |
894a25c98e | ||
![]() |
90f0d9fa00 | ||
![]() |
83889a8fd7 | ||
![]() |
4cfc429e75 | ||
![]() |
2df829b79d | ||
![]() |
7baf6382ac | ||
![]() |
7d1f689ed9 | ||
![]() |
4f448553f6 | ||
![]() |
dd56671974 | ||
![]() |
d8e0fd0ba5 | ||
![]() |
a9320d4baf | ||
![]() |
42475becf1 | ||
![]() |
c30aca8484 | ||
![]() |
25bdf50737 | ||
![]() |
4a60479b74 | ||
![]() |
f6d651304c | ||
![]() |
85990c20ed | ||
![]() |
8ea98023a5 | ||
![]() |
acceaea410 | ||
![]() |
d609155022 | ||
![]() |
1add5077af | ||
![]() |
a9cac343b0 | ||
![]() |
1b441a752e | ||
![]() |
03fee95f68 | ||
![]() |
7fa4b18843 | ||
![]() |
7b0fb949fd | ||
![]() |
df10cff842 | ||
![]() |
8b93af1b56 | ||
![]() |
a396a4e666 | ||
![]() |
8f278ec4bc | ||
![]() |
032ebce0bc | ||
![]() |
bb60b42f98 | ||
![]() |
21ed717287 | ||
![]() |
2d056bad81 | ||
![]() |
8297e9e215 | ||
![]() |
4ccf450ad4 | ||
![]() |
fc056869a7 | ||
![]() |
0bd5ff34d4 | ||
![]() |
ffd272d3fe | ||
![]() |
1eee186e79 |
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": ["airbnb-base", "prettier"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": "2020",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true,
|
||||
"modules": true
|
||||
|
@@ -1,12 +1,9 @@
|
||||
{
|
||||
"extends": "./.eslintrc-hound.json",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"plugins": ["react"],
|
||||
"env": {
|
||||
"browser": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"rules": {
|
||||
"import/no-unresolved": 2,
|
||||
"linebreak-style": 0,
|
||||
|
@@ -1,11 +1,24 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ""
|
||||
labels: bug
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
<!-- READ THIS FIRST:
|
||||
- If you need additional help with this template please refer to https://www.home-assistant.io/help/reporting_issues/
|
||||
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/home-assistant/releases
|
||||
- This is for bugs only. Feature and enhancement requests should go in our community forum: https://community.home-assistant.io/c/feature-requests
|
||||
- Provide as many details as possible. Do not delete any text from this template!
|
||||
-->
|
||||
|
||||
**Checklist:**
|
||||
|
||||
- [ ] I updated to the latest version available
|
||||
- [ ] I cleared the cache of my browser
|
||||
|
||||
**Home Assistant release with the issue:**
|
||||
|
||||
<!--
|
||||
- Frontend -> Developer tools -> Info
|
||||
- Or use this command: hass --version
|
||||
@@ -14,22 +27,50 @@
|
||||
**Last working Home Assistant release (if known):**
|
||||
|
||||
**UI (States or Lovelace UI?):**
|
||||
|
||||
<!--
|
||||
- Frontend -> Developer tools -> Info
|
||||
-->
|
||||
|
||||
**Browser and Operating System:**
|
||||
|
||||
<!--
|
||||
Provide details about what browser (and version) you are seeing the issue in. And also which operating system this is on. If possible try to replicate the issue in other browsers and include your findings here.
|
||||
-->
|
||||
|
||||
**Description of problem:**
|
||||
|
||||
<!--
|
||||
Explain what the issue is, and how things should look/behave. If possible provide a screenshot with a description.
|
||||
Explain what the issue is, and what is the current behaviour. If possible provide a screenshot with a description.
|
||||
-->
|
||||
|
||||
**Expected behaviour:**
|
||||
|
||||
<!--
|
||||
Explain how things should look/behave. If possible provide a screenshot with a description.
|
||||
-->
|
||||
|
||||
**Relevant config:**
|
||||
|
||||
<!--
|
||||
Give the config of both the integration that is used, the Lovelace config, scene, automation or otherwise relevant configuration.
|
||||
-->
|
||||
|
||||
**Steps to reproduce this problem:**
|
||||
|
||||
<!--
|
||||
Sum up all steps that are necessary to reproduce this bug.
|
||||
For example:
|
||||
1. Add a climate integration
|
||||
2. Navigate to Lovelace
|
||||
3. Click more info of the climate entity
|
||||
4. Set the hvac action to heat
|
||||
5. Set the temperature higher than the current temperature
|
||||
6. Set the hvac action to cool
|
||||
-->
|
||||
|
||||
**Javascript errors shown in the web inspector (if applicable):**
|
||||
|
||||
```
|
||||
|
||||
```
|
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ""
|
||||
labels: feature request
|
||||
assignees: ""
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
27
.github/lock.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
|
||||
|
||||
# Number of days of inactivity before a closed issue or pull request is locked
|
||||
daysUntilLock: 1
|
||||
|
||||
# Skip issues and pull requests created before a given timestamp. Timestamp must
|
||||
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
|
||||
skipCreatedBefore: 2020-01-01
|
||||
|
||||
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
|
||||
exemptLabels: []
|
||||
|
||||
# Label to add before locking, such as `outdated`. Set to `false` to disable
|
||||
lockLabel: false
|
||||
|
||||
# Comment to post before locking. Set to `false` to disable
|
||||
lockComment: false
|
||||
|
||||
# Assign `resolved` as the reason for locking. Set to `false` to disable
|
||||
setLockReason: false
|
||||
|
||||
# Limit to only `issues` or `pulls`
|
||||
only: pulls
|
||||
|
||||
# Optionally, specify configuration settings just for `issues` or `pulls`
|
||||
issues:
|
||||
daysUntilLock: 30
|
3
.gitignore
vendored
@@ -25,6 +25,9 @@ dist
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
|
||||
# Cast dev settings
|
||||
src/cast/dev_const.ts
|
||||
|
||||
# Secrets
|
||||
.lokalise_token
|
||||
yarn-error.log
|
||||
|
12
.travis.yml
@@ -8,19 +8,11 @@ install: yarn install
|
||||
script:
|
||||
- npm run build
|
||||
- hassio/script/build_hassio
|
||||
# Because else eslint fails because hassio has cleaned that build
|
||||
- ./node_modules/.bin/gulp gen-icons-app
|
||||
- npm run test
|
||||
# - xvfb-run wct --module-resolution=node --npm
|
||||
# - 'if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct --module-resolution=node --npm --plugin sauce; fi'
|
||||
services:
|
||||
- docker
|
||||
before_deploy:
|
||||
- 'docker pull lokalise/lokalise-cli@sha256:2198814ebddfda56ee041a4b427521757dd57f75415ea9693696a64c550cef21'
|
||||
deploy:
|
||||
provider: script
|
||||
script: script/travis_deploy
|
||||
'on':
|
||||
branch: master
|
||||
dist: trusty
|
||||
addons:
|
||||
sauce_connect: true
|
||||
|
||||
|
@@ -2,9 +2,9 @@
|
||||
|
||||
This is the repository for the official [Home Assistant](https://home-assistant.io) frontend.
|
||||
|
||||
[](https://home-assistant.io/demo/)
|
||||
[](https://demo.home-assistant.io/)
|
||||
|
||||
- [View demo of the Polymer frontend](https://home-assistant.io/demo/)
|
||||
- [View demo of Home Assistant](https://demo.home-assistant.io/)
|
||||
- [More information about Home Assistant](https://home-assistant.io)
|
||||
- [Frontend development instructions](https://developers.home-assistant.io/docs/en/frontend_index.html)
|
||||
|
||||
@@ -31,3 +31,5 @@ It is possible to compile the project and/or run commands in the development env
|
||||
## License
|
||||
|
||||
Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects.
|
||||
|
||||
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variation of devices.
|
||||
|
64
azure-pipelines-release.yml
Normal file
@@ -0,0 +1,64 @@
|
||||
# https://dev.azure.com/home-assistant
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
tags:
|
||||
include:
|
||||
- "*"
|
||||
pr: none
|
||||
variables:
|
||||
- name: versionWheels
|
||||
value: '1.3-3.7-alpine3.10'
|
||||
- name: versionNode
|
||||
value: '12.1'
|
||||
- group: twine
|
||||
resources:
|
||||
repositories:
|
||||
- repository: azure
|
||||
type: github
|
||||
name: 'home-assistant/ci-azure'
|
||||
endpoint: 'home-assistant'
|
||||
|
||||
|
||||
stages:
|
||||
- stage: "Validate"
|
||||
jobs:
|
||||
- template: templates/azp-job-version.yaml@azure
|
||||
|
||||
- stage: "Build"
|
||||
jobs:
|
||||
- job: "ReleasePython"
|
||||
pool:
|
||||
vmImage: "ubuntu-latest"
|
||||
steps:
|
||||
- task: UsePythonVersion@0
|
||||
displayName: "Use Python 3.7"
|
||||
inputs:
|
||||
versionSpec: "3.7"
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node $(versionNode)"
|
||||
inputs:
|
||||
versionSpec: "$(versionNode)"
|
||||
- script: pip install twine wheel
|
||||
displayName: "Install tools"
|
||||
- script: |
|
||||
export TWINE_USERNAME="$(twineUser)"
|
||||
export TWINE_PASSWORD="$(twinePassword)"
|
||||
|
||||
script/release
|
||||
displayName: "Build and release package"
|
||||
- template: templates/azp-job-wheels.yaml@azure
|
||||
parameters:
|
||||
builderVersion: '$(versionWheels)'
|
||||
builderApk: 'build-base'
|
||||
wheelsLocal: true
|
||||
preBuild:
|
||||
- task: NodeTool@0
|
||||
displayName: "Use Node $(versionNode)"
|
||||
inputs:
|
||||
versionSpec: "$(versionNode)"
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
yarn install
|
||||
script/build_frontend
|
70
azure-pipelines-translation.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
# https://dev.azure.com/home-assistant
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- dev
|
||||
paths:
|
||||
include:
|
||||
- translations/en.json
|
||||
pr: none
|
||||
schedules:
|
||||
- cron: "30 0 * * *"
|
||||
displayName: "translation update"
|
||||
branches:
|
||||
include:
|
||||
- dev
|
||||
always: true
|
||||
variables:
|
||||
- group: translation
|
||||
resources:
|
||||
repositories:
|
||||
- repository: azure
|
||||
type: github
|
||||
name: 'home-assistant/ci-azure'
|
||||
endpoint: 'home-assistant'
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
- job: 'Upload'
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Use Node 12.x'
|
||||
inputs:
|
||||
versionSpec: '12.x'
|
||||
- script: |
|
||||
export LOKALISE_TOKEN="$(lokaliseToken)"
|
||||
export AZURE_BRANCH="$(Build.SourceBranchName)"
|
||||
|
||||
./script/translations_upload_base
|
||||
displayName: 'Upload Translation'
|
||||
|
||||
- job: 'Download'
|
||||
dependsOn:
|
||||
- 'Upload'
|
||||
condition: or(eq(variables['Build.Reason'], 'Schedule'), eq(variables['Build.Reason'], 'Manual'))
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Use Node 12.x'
|
||||
inputs:
|
||||
versionSpec: '12.x'
|
||||
- template: templates/azp-step-git-init.yaml@azure
|
||||
- script: |
|
||||
export LOKALISE_TOKEN="$(lokaliseToken)"
|
||||
export AZURE_BRANCH="$(Build.SourceBranchName)"
|
||||
|
||||
npm install
|
||||
./script/translations_download
|
||||
displayName: 'Download Translation'
|
||||
- script: |
|
||||
git checkout dev
|
||||
git add translation
|
||||
git commit -am "[ci skip] Translation update"
|
||||
git push
|
||||
displayName: 'Update translation'
|
@@ -33,6 +33,7 @@ module.exports.babelLoaderConfig = ({ latestBuild }) => {
|
||||
pragma: "h",
|
||||
},
|
||||
],
|
||||
"@babel/plugin-proposal-optional-chaining",
|
||||
[
|
||||
require("@babel/plugin-proposal-decorators").default,
|
||||
{ decoratorsBeforeExport: true },
|
||||
|
6
build-scripts/env.js
Normal file
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
isProdBuild: process.env.NODE_ENV === "production",
|
||||
isStatsBuild: process.env.STATS === "1",
|
||||
isTravis: process.env.TRAVIS === "true",
|
||||
isNetlify: process.env.NETLIFY === "true",
|
||||
};
|
@@ -1,10 +1,13 @@
|
||||
// Run HA develop mode
|
||||
const gulp = require("gulp");
|
||||
|
||||
const envVars = require("../env");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./compress.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
require("./entry-html.js");
|
||||
@@ -18,7 +21,7 @@ gulp.task(
|
||||
"clean",
|
||||
gulp.parallel(
|
||||
"gen-service-worker-dev",
|
||||
"gen-icons",
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi"),
|
||||
"gen-pages-dev",
|
||||
"gen-index-app-dev",
|
||||
gulp.series("create-test-translation", "build-translations")
|
||||
@@ -35,13 +38,11 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean",
|
||||
gulp.parallel("gen-icons", "build-translations"),
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static",
|
||||
gulp.parallel(
|
||||
"webpack-prod-app",
|
||||
// Do not compress static files in CI, it's SLOW.
|
||||
...(process.env.CI === "true" ? [] : ["compress-static"])
|
||||
),
|
||||
"webpack-prod-app",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTravis ? [] : ["compress-app"]),
|
||||
gulp.parallel(
|
||||
"gen-pages-prod",
|
||||
"gen-index-app-prod",
|
||||
|
41
build-scripts/gulp/cast.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
require("./entry-html.js");
|
||||
|
||||
gulp.task(
|
||||
"develop-cast",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-cast",
|
||||
gulp.parallel(
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-index-cast-dev",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-cast",
|
||||
"webpack-dev-server-cast"
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"build-cast",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-cast",
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static-cast",
|
||||
"webpack-prod-cast",
|
||||
"gen-index-cast-prod"
|
||||
)
|
||||
);
|
@@ -1,6 +1,39 @@
|
||||
const del = require("del");
|
||||
const gulp = require("gulp");
|
||||
const config = require("../paths");
|
||||
require("./translations");
|
||||
|
||||
gulp.task("clean", () => del([config.root, config.build_dir]));
|
||||
gulp.task("clean-demo", () => del([config.demo_root, config.build_dir]));
|
||||
gulp.task(
|
||||
"clean",
|
||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||
return del([config.root, config.build_dir]);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-demo",
|
||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||
return del([config.demo_root, config.build_dir]);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-cast",
|
||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||
return del([config.cast_root, config.build_dir]);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-hassio",
|
||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||
return del([config.hassio_root, config.build_dir]);
|
||||
})
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-gallery",
|
||||
gulp.parallel("clean-translations", function cleanOutputAndBuildDir() {
|
||||
return del([config.gallery_root, config.build_dir]);
|
||||
})
|
||||
);
|
||||
|
38
build-scripts/gulp/compress.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// Tasks to compress
|
||||
|
||||
const gulp = require("gulp");
|
||||
const zopfli = require("gulp-zopfli-green");
|
||||
const merge = require("merge-stream");
|
||||
const path = require("path");
|
||||
const paths = require("../paths");
|
||||
|
||||
gulp.task("compress-app", function compressApp() {
|
||||
const jsLatest = gulp
|
||||
.src(path.resolve(paths.output, "**/*.js"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(paths.output));
|
||||
|
||||
const jsEs5 = gulp
|
||||
.src(path.resolve(paths.output_es5, "**/*.js"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(paths.output_es5));
|
||||
|
||||
const polyfills = gulp
|
||||
.src(path.resolve(paths.static, "polyfills/*.js"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(path.resolve(paths.static, "polyfills")));
|
||||
|
||||
const translations = gulp
|
||||
.src(path.resolve(paths.static, "translations/*.json"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(path.resolve(paths.static, "translations")));
|
||||
|
||||
return merge(jsLatest, jsEs5, polyfills, translations);
|
||||
});
|
||||
|
||||
gulp.task("compress-hassio", function compressApp() {
|
||||
return gulp
|
||||
.src(path.resolve(paths.hassio_root, "**/*.js"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(paths.hassio_root));
|
||||
});
|
@@ -1,4 +1,4 @@
|
||||
// Run HA develop mode
|
||||
// Run demo develop mode
|
||||
const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
@@ -17,7 +17,8 @@ gulp.task(
|
||||
},
|
||||
"clean-demo",
|
||||
gulp.parallel(
|
||||
"gen-icons",
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-icons-demo",
|
||||
"gen-index-demo-dev",
|
||||
"build-translations"
|
||||
@@ -34,7 +35,12 @@ gulp.task(
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-demo",
|
||||
gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"),
|
||||
gulp.parallel(
|
||||
"gen-icons-app",
|
||||
"gen-icons-mdi",
|
||||
"gen-icons-demo",
|
||||
"build-translations"
|
||||
),
|
||||
"copy-static-demo",
|
||||
"webpack-prod-demo",
|
||||
"gen-index-demo-prod"
|
||||
|
73
build-scripts/gulp/download_translations.js
Normal file
@@ -0,0 +1,73 @@
|
||||
const del = require("del");
|
||||
const gulp = require("gulp");
|
||||
const mapStream = require("map-stream");
|
||||
|
||||
const inDir = "translations";
|
||||
const downloadDir = inDir + "/downloads";
|
||||
|
||||
const tasks = [];
|
||||
|
||||
function hasHtml(data) {
|
||||
return /<[a-z][\s\S]*>/i.test(data);
|
||||
}
|
||||
|
||||
function recursiveCheckHasHtml(file, data, errors, recKey) {
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (typeof data[key] === "object") {
|
||||
const nextRecKey = recKey ? `${recKey}.${key}` : key;
|
||||
recursiveCheckHasHtml(file, data[key], errors, nextRecKey);
|
||||
} else if (hasHtml(data[key])) {
|
||||
errors.push(`HTML found in ${file.path} at key ${recKey}.${key}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function checkHtml() {
|
||||
const errors = [];
|
||||
|
||||
return mapStream(function(file, cb) {
|
||||
const content = file.contents;
|
||||
let error;
|
||||
if (content) {
|
||||
if (hasHtml(String(content))) {
|
||||
const data = JSON.parse(String(content));
|
||||
recursiveCheckHasHtml(file, data, errors);
|
||||
if (errors.length > 0) {
|
||||
error = errors.join("\r\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
cb(error, file);
|
||||
});
|
||||
}
|
||||
|
||||
let taskName = "clean-downloaded-translations";
|
||||
gulp.task(taskName, function() {
|
||||
return del([`${downloadDir}/**`]);
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "check-translations-html";
|
||||
gulp.task(taskName, function() {
|
||||
return gulp.src(`${downloadDir}/*.json`).pipe(checkHtml());
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "move-downloaded-translations";
|
||||
gulp.task(taskName, function() {
|
||||
return gulp.src(`${downloadDir}/*.json`).pipe(gulp.dest(inDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "check-downloaded-translations";
|
||||
gulp.task(
|
||||
taskName,
|
||||
gulp.series(
|
||||
"check-translations-html",
|
||||
"move-downloaded-translations",
|
||||
"clean-downloaded-translations"
|
||||
)
|
||||
);
|
||||
tasks.push(taskName);
|
||||
|
||||
module.exports = tasks;
|
@@ -11,9 +11,6 @@ const config = require("../paths.js");
|
||||
const templatePath = (tpl) =>
|
||||
path.resolve(config.polymer_dir, "src/html/", `${tpl}.html.template`);
|
||||
|
||||
const demoTemplatePath = (tpl) =>
|
||||
path.resolve(config.demo_dir, "src/html/", `${tpl}.html.template`);
|
||||
|
||||
const readFile = (pth) => fs.readFileSync(pth).toString();
|
||||
|
||||
const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
||||
@@ -22,7 +19,19 @@ const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
|
||||
};
|
||||
|
||||
const renderDemoTemplate = (pth, data = {}) =>
|
||||
renderTemplate(pth, data, demoTemplatePath);
|
||||
renderTemplate(pth, data, (tpl) =>
|
||||
path.resolve(config.demo_dir, "src/html/", `${tpl}.html.template`)
|
||||
);
|
||||
|
||||
const renderCastTemplate = (pth, data = {}) =>
|
||||
renderTemplate(pth, data, (tpl) =>
|
||||
path.resolve(config.cast_dir, "src/html/", `${tpl}.html.template`)
|
||||
);
|
||||
|
||||
const renderGalleryTemplate = (pth, data = {}) =>
|
||||
renderTemplate(pth, data, (tpl) =>
|
||||
path.resolve(config.gallery_dir, "src/html/", `${tpl}.html.template`)
|
||||
);
|
||||
|
||||
const minifyHtml = (content) =>
|
||||
minify(content, {
|
||||
@@ -86,7 +95,7 @@ gulp.task("gen-index-app-dev", (done) => {
|
||||
es5CoreJS: "/frontend_es5/core.js",
|
||||
es5CustomPanelJS: "/frontend_es5/custom-panel.js",
|
||||
es5HassIconsJS: "/frontend_es5/hass-icons.js",
|
||||
});
|
||||
}).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||
|
||||
fs.outputFileSync(path.resolve(config.root, "index.html"), content);
|
||||
done();
|
||||
@@ -113,17 +122,64 @@ gulp.task("gen-index-app-prod", (done) => {
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-demo-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderDemoTemplate("index", {
|
||||
latestDemoJS: "/frontend_latest/main.js",
|
||||
|
||||
es5Compatibility: "/frontend_es5/compatibility.js",
|
||||
es5DemoJS: "/frontend_es5/main.js",
|
||||
gulp.task("gen-index-cast-dev", (done) => {
|
||||
const contentReceiver = renderCastTemplate("receiver", {
|
||||
latestReceiverJS: "/frontend_latest/receiver.js",
|
||||
});
|
||||
fs.outputFileSync(
|
||||
path.resolve(config.cast_root, "receiver.html"),
|
||||
contentReceiver
|
||||
);
|
||||
|
||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), content);
|
||||
const contentFAQ = renderCastTemplate("launcher-faq", {
|
||||
latestLauncherJS: "/frontend_latest/launcher.js",
|
||||
es5LauncherJS: "/frontend_es5/launcher.js",
|
||||
});
|
||||
fs.outputFileSync(path.resolve(config.cast_root, "faq.html"), contentFAQ);
|
||||
|
||||
const contentLauncher = renderCastTemplate("launcher", {
|
||||
latestLauncherJS: "/frontend_latest/launcher.js",
|
||||
es5LauncherJS: "/frontend_es5/launcher.js",
|
||||
});
|
||||
fs.outputFileSync(
|
||||
path.resolve(config.cast_root, "index.html"),
|
||||
contentLauncher
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-cast-prod", (done) => {
|
||||
const latestManifest = require(path.resolve(
|
||||
config.cast_output,
|
||||
"manifest.json"
|
||||
));
|
||||
const es5Manifest = require(path.resolve(
|
||||
config.cast_output_es5,
|
||||
"manifest.json"
|
||||
));
|
||||
|
||||
const contentReceiver = renderCastTemplate("receiver", {
|
||||
latestReceiverJS: latestManifest["receiver.js"],
|
||||
});
|
||||
fs.outputFileSync(
|
||||
path.resolve(config.cast_root, "receiver.html"),
|
||||
contentReceiver
|
||||
);
|
||||
|
||||
const contentFAQ = renderCastTemplate("launcher-faq", {
|
||||
latestLauncherJS: latestManifest["launcher.js"],
|
||||
es5LauncherJS: es5Manifest["launcher.js"],
|
||||
});
|
||||
fs.outputFileSync(path.resolve(config.cast_root, "faq.html"), contentFAQ);
|
||||
|
||||
const contentLauncher = renderCastTemplate("launcher", {
|
||||
latestLauncherJS: latestManifest["launcher.js"],
|
||||
es5LauncherJS: es5Manifest["launcher.js"],
|
||||
});
|
||||
fs.outputFileSync(
|
||||
path.resolve(config.cast_root, "index.html"),
|
||||
contentLauncher
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -156,8 +212,33 @@ gulp.task("gen-index-demo-prod", (done) => {
|
||||
es5Compatibility: es5Manifest["compatibility.js"],
|
||||
es5DemoJS: es5Manifest["main.js"],
|
||||
});
|
||||
const minified = minifyHtml(content).replace(/#THEMEC/g, "{{ theme_color }}");
|
||||
const minified = minifyHtml(content);
|
||||
|
||||
fs.outputFileSync(path.resolve(config.demo_root, "index.html"), minified);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-gallery-dev", (done) => {
|
||||
// In dev mode we don't mangle names, so we hardcode urls. That way we can
|
||||
// run webpack as last in watch mode, which blocks output.
|
||||
const content = renderGalleryTemplate("index", {
|
||||
latestGalleryJS: "./entrypoint.js",
|
||||
});
|
||||
|
||||
fs.outputFileSync(path.resolve(config.gallery_root, "index.html"), content);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-index-gallery-prod", (done) => {
|
||||
const latestManifest = require(path.resolve(
|
||||
config.gallery_output,
|
||||
"manifest.json"
|
||||
));
|
||||
const content = renderGalleryTemplate("index", {
|
||||
latestGalleryJS: latestManifest["entrypoint.js"],
|
||||
});
|
||||
const minified = minifyHtml(content);
|
||||
|
||||
fs.outputFileSync(path.resolve(config.gallery_root, "index.html"), minified);
|
||||
done();
|
||||
});
|
||||
|
38
build-scripts/gulp/gallery.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// Run demo develop mode
|
||||
const gulp = require("gulp");
|
||||
|
||||
require("./clean.js");
|
||||
require("./translations.js");
|
||||
require("./gen-icons.js");
|
||||
require("./gather-static.js");
|
||||
require("./webpack.js");
|
||||
require("./service-worker.js");
|
||||
require("./entry-html.js");
|
||||
|
||||
gulp.task(
|
||||
"develop-gallery",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-gallery",
|
||||
gulp.parallel("gen-icons-app", "gen-icons-app", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
"gen-index-gallery-dev",
|
||||
"webpack-dev-server-gallery"
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"build-gallery",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-gallery",
|
||||
gulp.parallel("gen-icons-app", "gen-icons-mdi", "build-translations"),
|
||||
"copy-static-gallery",
|
||||
"webpack-prod-gallery",
|
||||
"gen-index-gallery-prod"
|
||||
)
|
||||
);
|
@@ -2,9 +2,8 @@
|
||||
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const cpx = require("cpx");
|
||||
const fs = require("fs-extra");
|
||||
const zopfli = require("gulp-zopfli-green");
|
||||
const merge = require("merge-stream");
|
||||
const paths = require("../paths");
|
||||
|
||||
const npmPath = (...parts) =>
|
||||
@@ -48,25 +47,22 @@ function copyPolyfills(staticDir) {
|
||||
function copyFonts(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
// Local fonts
|
||||
fs.copySync(npmPath("@polymer/font-roboto-local/fonts"), staticPath("fonts"));
|
||||
cpx.copySync(
|
||||
npmPath("roboto-fontface/fonts/roboto/*.woff2"),
|
||||
staticPath("fonts/roboto")
|
||||
);
|
||||
}
|
||||
|
||||
function compressStatic(staticDir) {
|
||||
function copyMapPanel(staticDir) {
|
||||
const staticPath = genStaticPath(staticDir);
|
||||
const fonts = gulp
|
||||
.src(staticPath("fonts/**/*.ttf"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(staticPath("fonts")));
|
||||
const polyfills = gulp
|
||||
.src(staticPath("polyfills/*.js"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(staticPath("polyfills")));
|
||||
const translations = gulp
|
||||
.src(staticPath("translations/*.json"))
|
||||
.pipe(zopfli())
|
||||
.pipe(gulp.dest(staticPath("translations")));
|
||||
|
||||
return merge(fonts, polyfills, translations);
|
||||
copyFileDir(
|
||||
npmPath("leaflet/dist/leaflet.css"),
|
||||
staticPath("images/leaflet/")
|
||||
);
|
||||
fs.copySync(
|
||||
npmPath("leaflet/dist/images"),
|
||||
staticPath("images/leaflet/images/")
|
||||
);
|
||||
}
|
||||
|
||||
gulp.task("copy-static", (done) => {
|
||||
@@ -84,27 +80,46 @@ gulp.task("copy-static", (done) => {
|
||||
npmPath("react-big-calendar/lib/css/react-big-calendar.css"),
|
||||
staticPath("panels/calendar/")
|
||||
);
|
||||
copyFileDir(
|
||||
npmPath("leaflet/dist/leaflet.css"),
|
||||
staticPath("images/leaflet/")
|
||||
);
|
||||
fs.copySync(
|
||||
npmPath("leaflet/dist/images"),
|
||||
staticPath("images/leaflet/images/")
|
||||
);
|
||||
copyMapPanel(staticDir);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("compress-static", () => compressStatic(paths.static));
|
||||
|
||||
gulp.task("copy-static-demo", (done) => {
|
||||
// Copy app static files
|
||||
fs.copySync(polyPath("public"), paths.demo_root);
|
||||
fs.copySync(
|
||||
polyPath("public/static"),
|
||||
path.resolve(paths.demo_root, "static")
|
||||
);
|
||||
// Copy demo static files
|
||||
fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_root);
|
||||
|
||||
copyPolyfills(paths.demo_static);
|
||||
copyMapPanel(paths.demo_static);
|
||||
copyFonts(paths.demo_static);
|
||||
copyTranslations(paths.demo_static);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("copy-static-cast", (done) => {
|
||||
// Copy app static files
|
||||
fs.copySync(polyPath("public/static"), paths.cast_static);
|
||||
// Copy cast static files
|
||||
fs.copySync(path.resolve(paths.cast_dir, "public"), paths.cast_root);
|
||||
|
||||
copyMapPanel(paths.cast_static);
|
||||
copyFonts(paths.cast_static);
|
||||
copyTranslations(paths.cast_static);
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("copy-static-gallery", (done) => {
|
||||
// Copy app static files
|
||||
fs.copySync(polyPath("public/static"), paths.gallery_static);
|
||||
// Copy gallery static files
|
||||
fs.copySync(path.resolve(paths.gallery_dir, "public"), paths.gallery_root);
|
||||
|
||||
copyMapPanel(paths.gallery_static);
|
||||
copyFonts(paths.gallery_static);
|
||||
copyTranslations(paths.gallery_static);
|
||||
done();
|
||||
});
|
||||
|
@@ -22,6 +22,7 @@ const BUILT_IN_PANEL_ICONS = [
|
||||
"mailbox", // Mailbox
|
||||
"tooltip-account", // Map
|
||||
"cart", // Shopping List
|
||||
"hammer", // developer-tools
|
||||
];
|
||||
|
||||
// Given an icon name, load the SVG file
|
||||
@@ -56,18 +57,6 @@ function generateIconset(iconsetName, iconNames) {
|
||||
return `<ha-iconset-svg name="${iconsetName}" size="24"><svg><defs>${iconDefs}</defs></svg></ha-iconset-svg>`;
|
||||
}
|
||||
|
||||
// Generate the full MDI iconset
|
||||
function genMDIIcons() {
|
||||
const meta = JSON.parse(
|
||||
fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
|
||||
);
|
||||
const iconNames = meta.map((iconInfo) => iconInfo.name);
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
|
||||
}
|
||||
|
||||
// Helper function to map recursively over files in a folder and it's subfolders
|
||||
function mapFiles(startPath, filter, mapFunc) {
|
||||
const files = fs.readdirSync(startPath);
|
||||
@@ -100,24 +89,27 @@ function findIcons(searchPath, iconsetName) {
|
||||
return icons;
|
||||
}
|
||||
|
||||
function genHassIcons() {
|
||||
gulp.task("gen-icons-mdi", (done) => {
|
||||
const meta = JSON.parse(
|
||||
fs.readFileSync(path.resolve(ICON_PACKAGE_PATH, META_PATH), "UTF-8")
|
||||
);
|
||||
const iconNames = meta.map((iconInfo) => iconInfo.name);
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
fs.writeFileSync(MDI_OUTPUT_PATH, generateIconset("mdi", iconNames));
|
||||
done();
|
||||
});
|
||||
|
||||
gulp.task("gen-icons-app", (done) => {
|
||||
const iconNames = findIcons("./src", "hass");
|
||||
BUILT_IN_PANEL_ICONS.forEach((name) => iconNames.add(name));
|
||||
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||
fs.mkdirSync(OUTPUT_DIR);
|
||||
}
|
||||
fs.writeFileSync(HASS_OUTPUT_PATH, generateIconset("hass", iconNames));
|
||||
}
|
||||
|
||||
gulp.task("gen-icons-mdi", (done) => {
|
||||
genMDIIcons();
|
||||
done();
|
||||
});
|
||||
gulp.task("gen-icons-hass", (done) => {
|
||||
genHassIcons();
|
||||
done();
|
||||
});
|
||||
gulp.task("gen-icons", gulp.series("gen-icons-hass", "gen-icons-mdi"));
|
||||
|
||||
gulp.task("gen-icons-demo", (done) => {
|
||||
const iconNames = findIcons(path.resolve(paths.demo_dir, "./src"), "hademo");
|
||||
@@ -128,8 +120,21 @@ gulp.task("gen-icons-demo", (done) => {
|
||||
done();
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
findIcons,
|
||||
generateIconset,
|
||||
genMDIIcons,
|
||||
};
|
||||
gulp.task("gen-icons-hassio", (done) => {
|
||||
const iconNames = findIcons(
|
||||
path.resolve(paths.hassio_dir, "./src"),
|
||||
"hassio"
|
||||
);
|
||||
// Find hassio icons inside HA main repo.
|
||||
for (const item of findIcons(
|
||||
path.resolve(paths.polymer_dir, "./src"),
|
||||
"hassio"
|
||||
)) {
|
||||
iconNames.add(item);
|
||||
}
|
||||
fs.writeFileSync(
|
||||
path.resolve(paths.hassio_dir, "hassio-icons.html"),
|
||||
generateIconset("hassio", iconNames)
|
||||
);
|
||||
done();
|
||||
});
|
||||
|
34
build-scripts/gulp/hassio.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const gulp = require("gulp");
|
||||
|
||||
const envVars = require("../env");
|
||||
|
||||
require("./clean.js");
|
||||
require("./gen-icons.js");
|
||||
require("./webpack.js");
|
||||
require("./compress.js");
|
||||
|
||||
gulp.task(
|
||||
"develop-hassio",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "development";
|
||||
},
|
||||
"clean-hassio",
|
||||
gulp.parallel("gen-icons-hassio", "gen-icons-mdi"),
|
||||
"webpack-watch-hassio"
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"build-hassio",
|
||||
gulp.series(
|
||||
async function setEnv() {
|
||||
process.env.NODE_ENV = "production";
|
||||
},
|
||||
"clean-hassio",
|
||||
gulp.parallel("gen-icons-hassio", "gen-icons-mdi"),
|
||||
"webpack-prod-hassio",
|
||||
...// Don't compress running tests
|
||||
(envVars.isTravis ? [] : ["compress-hassio"])
|
||||
)
|
||||
);
|
@@ -15,6 +15,10 @@ gulp.task("gen-service-worker-dev", (done) => {
|
||||
writeSW(
|
||||
`
|
||||
console.debug('Service worker disabled in development');
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
`
|
||||
);
|
||||
done();
|
||||
|
@@ -34,7 +34,9 @@ const TRANSLATION_FRAGMENTS = [
|
||||
"profile",
|
||||
"shopping-list",
|
||||
"page-authorize",
|
||||
"page-demo",
|
||||
"page-onboarding",
|
||||
"developer-tools",
|
||||
];
|
||||
|
||||
const tasks = [];
|
||||
@@ -43,11 +45,10 @@ function recursiveFlatten(prefix, data) {
|
||||
let output = {};
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (typeof data[key] === "object") {
|
||||
output = Object.assign(
|
||||
{},
|
||||
output,
|
||||
recursiveFlatten(prefix + key + ".", data[key])
|
||||
);
|
||||
output = {
|
||||
...output,
|
||||
...recursiveFlatten(prefix + key + ".", data[key]),
|
||||
};
|
||||
} else {
|
||||
output[prefix + key] = data[key];
|
||||
}
|
||||
@@ -97,18 +98,16 @@ function recursiveEmpty(data) {
|
||||
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
|
||||
*/
|
||||
const re_key_reference = /\[%key:([^%]+)%\]/;
|
||||
function lokalise_transform(data, original) {
|
||||
function lokaliseTransform(data, original, file) {
|
||||
const output = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
if (value instanceof Object) {
|
||||
output[key] = lokalise_transform(value, original);
|
||||
output[key] = lokaliseTransform(value, original, file);
|
||||
} else {
|
||||
output[key] = value.replace(re_key_reference, (match, key) => {
|
||||
const replace = key.split("::").reduce((tr, k) => tr[k], original);
|
||||
if (typeof replace !== "string") {
|
||||
throw Error(
|
||||
`Invalid key placeholder ${key} in src/translations/en.json`
|
||||
);
|
||||
throw Error(`Invalid key placeholder ${key} in ${file.path}`);
|
||||
}
|
||||
return replace;
|
||||
});
|
||||
@@ -123,18 +122,28 @@ gulp.task(taskName, function() {
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "create-test-metadata";
|
||||
gulp.task(taskName, function(cb) {
|
||||
fs.writeFile(
|
||||
workDir + "/testMetadata.json",
|
||||
JSON.stringify({
|
||||
test: {
|
||||
nativeName: "Test",
|
||||
},
|
||||
}),
|
||||
cb
|
||||
);
|
||||
gulp.task("ensure-translations-build-dir", (done) => {
|
||||
if (!fs.existsSync(workDir)) {
|
||||
fs.mkdirSync(workDir);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
taskName = "create-test-metadata";
|
||||
gulp.task(
|
||||
taskName,
|
||||
gulp.series("ensure-translations-build-dir", function writeTestMetaData(cb) {
|
||||
fs.writeFile(
|
||||
workDir + "/testMetadata.json",
|
||||
JSON.stringify({
|
||||
test: {
|
||||
nativeName: "Test",
|
||||
},
|
||||
}),
|
||||
cb
|
||||
);
|
||||
})
|
||||
);
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = "create-test-translation";
|
||||
@@ -171,7 +180,7 @@ gulp.task(
|
||||
.src("src/translations/en.json")
|
||||
.pipe(
|
||||
transform(function(data, file) {
|
||||
return lokalise_transform(data, data);
|
||||
return lokaliseTransform(data, data, file);
|
||||
})
|
||||
)
|
||||
.pipe(rename("translationMaster.json"))
|
||||
@@ -186,6 +195,11 @@ gulp.task(
|
||||
gulp.series("build-master-translation", function() {
|
||||
return gulp
|
||||
.src([inDir + "/*.json", workDir + "/test.json"], { allowEmpty: true })
|
||||
.pipe(
|
||||
transform(function(data, file) {
|
||||
return lokaliseTransform(data, data, file);
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
foreach(function(stream, file) {
|
||||
// For each language generate a merged json file. It begins with the master
|
||||
@@ -202,7 +216,7 @@ gulp.task(
|
||||
const lang = subtags.slice(0, i).join("-");
|
||||
if (lang === "test") {
|
||||
src.push(workDir + "/test.json");
|
||||
} else {
|
||||
} else if (lang !== "en") {
|
||||
src.push(inDir + "/" + lang + ".json");
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,39 @@
|
||||
// Tasks to run webpack.
|
||||
const gulp = require("gulp");
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const WebpackDevServer = require("webpack-dev-server");
|
||||
const log = require("fancy-log");
|
||||
const paths = require("../paths");
|
||||
const { createAppConfig, createDemoConfig } = require("../webpack");
|
||||
const {
|
||||
createAppConfig,
|
||||
createDemoConfig,
|
||||
createCastConfig,
|
||||
createHassioConfig,
|
||||
createGalleryConfig,
|
||||
} = require("../webpack");
|
||||
|
||||
const bothBuilds = (createConfigFunc, params) => [
|
||||
createConfigFunc({ ...params, latestBuild: true }),
|
||||
createConfigFunc({ ...params, latestBuild: false }),
|
||||
];
|
||||
|
||||
const runDevServer = ({
|
||||
compiler,
|
||||
contentBase,
|
||||
port,
|
||||
listenHost = "localhost",
|
||||
}) =>
|
||||
new WebpackDevServer(compiler, {
|
||||
open: true,
|
||||
watchContentBase: true,
|
||||
contentBase,
|
||||
}).listen(port, listenHost, function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// Server listening
|
||||
log("[webpack-dev-server]", `http://localhost:${port}`);
|
||||
});
|
||||
|
||||
const handler = (done) => (err, stats) => {
|
||||
if (err) {
|
||||
@@ -28,20 +56,11 @@ const handler = (done) => (err, stats) => {
|
||||
};
|
||||
|
||||
gulp.task("webpack-watch-app", () => {
|
||||
const compiler = webpack([
|
||||
createAppConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: true,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
createAppConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: false,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
]);
|
||||
compiler.watch({}, handler());
|
||||
// we are not calling done, so this command will run forever
|
||||
webpack(bothBuilds(createAppConfig, { isProdBuild: false })).watch(
|
||||
{},
|
||||
handler()
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
@@ -49,47 +68,17 @@ gulp.task(
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
[
|
||||
createAppConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: true,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
createAppConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: false,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
],
|
||||
bothBuilds(createAppConfig, { isProdBuild: true }),
|
||||
handler(resolve)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("webpack-dev-server-demo", () => {
|
||||
const compiler = webpack([
|
||||
createDemoConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: false,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
createDemoConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: true,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
new WebpackDevServer(compiler, {
|
||||
open: true,
|
||||
watchContentBase: true,
|
||||
contentBase: path.resolve(paths.demo_dir, "dist"),
|
||||
}).listen(8080, "localhost", function(err) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
// Server listening
|
||||
log("[webpack-dev-server]", "http://localhost:8080");
|
||||
runDevServer({
|
||||
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
||||
contentBase: paths.demo_root,
|
||||
port: 8090,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,18 +87,82 @@ gulp.task(
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
[
|
||||
createDemoConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: false,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
createDemoConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: true,
|
||||
isStatsBuild: false,
|
||||
}),
|
||||
],
|
||||
bothBuilds(createDemoConfig, {
|
||||
isProdBuild: true,
|
||||
}),
|
||||
handler(resolve)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("webpack-dev-server-cast", () => {
|
||||
runDevServer({
|
||||
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
||||
contentBase: paths.cast_root,
|
||||
port: 8080,
|
||||
// Accessible from the network, because that's how Cast hits it.
|
||||
listenHost: "0.0.0.0",
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"webpack-prod-cast",
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
bothBuilds(createCastConfig, {
|
||||
isProdBuild: true,
|
||||
}),
|
||||
|
||||
handler(resolve)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("webpack-watch-hassio", () => {
|
||||
// we are not calling done, so this command will run forever
|
||||
webpack(
|
||||
createHassioConfig({
|
||||
isProdBuild: false,
|
||||
latestBuild: false,
|
||||
})
|
||||
).watch({}, handler());
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"webpack-prod-hassio",
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
createHassioConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: false,
|
||||
}),
|
||||
handler(resolve)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("webpack-dev-server-gallery", () => {
|
||||
runDevServer({
|
||||
compiler: webpack(
|
||||
createGalleryConfig({ latestBuild: true, isProdBuild: false })
|
||||
),
|
||||
contentBase: paths.gallery_root,
|
||||
port: 8100,
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"webpack-prod-gallery",
|
||||
() =>
|
||||
new Promise((resolve) =>
|
||||
webpack(
|
||||
createGalleryConfig({
|
||||
isProdBuild: true,
|
||||
latestBuild: true,
|
||||
}),
|
||||
|
||||
handler(resolve)
|
||||
)
|
||||
)
|
||||
|
@@ -14,4 +14,19 @@ module.exports = {
|
||||
demo_static: path.resolve(__dirname, "../demo/dist/static"),
|
||||
demo_output: path.resolve(__dirname, "../demo/dist/frontend_latest"),
|
||||
demo_output_es5: path.resolve(__dirname, "../demo/dist/frontend_es5"),
|
||||
|
||||
cast_dir: path.resolve(__dirname, "../cast"),
|
||||
cast_root: path.resolve(__dirname, "../cast/dist"),
|
||||
cast_static: path.resolve(__dirname, "../cast/dist/static"),
|
||||
cast_output: path.resolve(__dirname, "../cast/dist/frontend_latest"),
|
||||
cast_output_es5: path.resolve(__dirname, "../cast/dist/frontend_es5"),
|
||||
|
||||
gallery_dir: path.resolve(__dirname, "../gallery"),
|
||||
gallery_root: path.resolve(__dirname, "../gallery/dist"),
|
||||
gallery_output: path.resolve(__dirname, "../gallery/dist/frontend_latest"),
|
||||
gallery_static: path.resolve(__dirname, "../gallery/dist/static"),
|
||||
|
||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||
hassio_root: path.resolve(__dirname, "../hassio/build"),
|
||||
hassio_publicPath: "/api/hassio/app/",
|
||||
};
|
||||
|
@@ -3,8 +3,6 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const TerserPlugin = require("terser-webpack-plugin");
|
||||
const WorkboxPlugin = require("workbox-webpack-plugin");
|
||||
const CompressionPlugin = require("compression-webpack-plugin");
|
||||
const zopfli = require("@gfx/zopfli");
|
||||
const ManifestPlugin = require("webpack-manifest-plugin");
|
||||
const paths = require("./paths.js");
|
||||
const { babelLoaderConfig } = require("./babel.js");
|
||||
@@ -17,206 +15,246 @@ if (!version) {
|
||||
}
|
||||
version = version[0];
|
||||
|
||||
const genMode = (isProdBuild) => (isProdBuild ? "production" : "development");
|
||||
const genDevTool = (isProdBuild) =>
|
||||
isProdBuild ? "cheap-source-map" : "inline-cheap-module-source-map";
|
||||
const genFilename = (isProdBuild, dontHash = new Set()) => ({ chunk }) => {
|
||||
if (!isProdBuild || dontHash.has(chunk.name)) {
|
||||
return `${chunk.name}.js`;
|
||||
}
|
||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||
};
|
||||
const genChunkFilename = (isProdBuild, isStatsBuild) =>
|
||||
isProdBuild && !isStatsBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||
|
||||
const resolve = {
|
||||
extensions: [".ts", ".js", ".json", ".tsx"],
|
||||
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",
|
||||
},
|
||||
};
|
||||
|
||||
const cssLoader = {
|
||||
test: /\.css$/,
|
||||
use: "raw-loader",
|
||||
};
|
||||
const htmlLoader = {
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const plugins = [
|
||||
// Ignore moment.js locales
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Color.js is bloated, it contains all color definitions for all material color sets.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@polymer\/paper-styles\/color\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
// Ignore roboto pointing at CDN. We use local font-roboto-local.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@polymer\/font-roboto\/roboto\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
// Ignore mwc icons pointing at CDN.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@material\/mwc-icon\/mwc-icon-font\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
];
|
||||
|
||||
const optimization = (latestBuild) => ({
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
terserOptions: {
|
||||
safari10: true,
|
||||
ecma: latestBuild ? undefined : 5,
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
const isCI = process.env.CI === "true";
|
||||
|
||||
// Create an object mapping browser urls to their paths during build
|
||||
const translationMetadata = require("../build-translations/translationMetadata.json");
|
||||
const workBoxTranslationsTemplatedURLs = {};
|
||||
const englishFP = translationMetadata["translations"]["en"]["fingerprints"];
|
||||
Object.keys(englishFP).forEach((key) => {
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${englishFP[key]}`
|
||||
] = `build-translations/output/${key}.json`;
|
||||
});
|
||||
|
||||
const entry = {
|
||||
app: "./src/entrypoints/app.ts",
|
||||
authorize: "./src/entrypoints/authorize.ts",
|
||||
onboarding: "./src/entrypoints/onboarding.ts",
|
||||
core: "./src/entrypoints/core.ts",
|
||||
compatibility: "./src/entrypoints/compatibility.ts",
|
||||
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
||||
"hass-icons": "./src/entrypoints/hass-icons.ts",
|
||||
};
|
||||
|
||||
const createWebpackConfig = ({
|
||||
entry,
|
||||
outputRoot,
|
||||
defineOverlay,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
isStatsBuild,
|
||||
}) => {
|
||||
return {
|
||||
mode: genMode(isProdBuild),
|
||||
devtool: genDevTool(isProdBuild),
|
||||
mode: isProdBuild ? "production" : "development",
|
||||
devtool: isProdBuild ? "source-map" : "inline-cheap-module-source-map",
|
||||
entry,
|
||||
module: {
|
||||
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
|
||||
rules: [
|
||||
babelLoaderConfig({ latestBuild }),
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: "raw-loader",
|
||||
},
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: optimization(latestBuild),
|
||||
plugins: [
|
||||
new ManifestPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: JSON.stringify(!isProdBuild),
|
||||
__DEMO__: false,
|
||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||
__VERSION__: JSON.stringify(version),
|
||||
__STATIC_PATH__: "/static/",
|
||||
"process.env.NODE_ENV": JSON.stringify(
|
||||
isProdBuild ? "production" : "development"
|
||||
),
|
||||
}),
|
||||
...plugins,
|
||||
isProdBuild &&
|
||||
!isCI &&
|
||||
!isStatsBuild &&
|
||||
new CompressionPlugin({
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
exclude: [/\.js\.map$/, /\.LICENSE$/, /\.py$/, /\.txt$/],
|
||||
algorithm(input, compressionOptions, callback) {
|
||||
return zopfli.gzip(input, compressionOptions, callback);
|
||||
parallel: true,
|
||||
extractComments: true,
|
||||
sourceMap: true,
|
||||
terserOptions: {
|
||||
safari10: true,
|
||||
ecma: latestBuild ? undefined : 5,
|
||||
},
|
||||
}),
|
||||
latestBuild &&
|
||||
new WorkboxPlugin.InjectManifest({
|
||||
swSrc: "./src/entrypoints/service-worker-hass.js",
|
||||
swDest: "service_worker.js",
|
||||
importWorkboxFrom: "local",
|
||||
include: [/\.js$/],
|
||||
templatedURLs: {
|
||||
...workBoxTranslationsTemplatedURLs,
|
||||
"/static/icons/favicon-192x192.png":
|
||||
"public/icons/favicon-192x192.png",
|
||||
"/static/fonts/roboto/Roboto-Light.ttf":
|
||||
"node_modules/@polymer/font-roboto-local/fonts/roboto/Roboto-Light.ttf",
|
||||
"/static/fonts/roboto/Roboto-Medium.ttf":
|
||||
"node_modules/@polymer/font-roboto-local/fonts/roboto/Roboto-Medium.ttf",
|
||||
"/static/fonts/roboto/Roboto-Regular.ttf":
|
||||
"node_modules/@polymer/font-roboto-local/fonts/roboto/Roboto-Regular.ttf",
|
||||
"/static/fonts/roboto/Roboto-Bold.ttf":
|
||||
"node_modules/@polymer/font-roboto-local/fonts/roboto/Roboto-Bold.ttf",
|
||||
},
|
||||
}),
|
||||
].filter(Boolean),
|
||||
output: {
|
||||
filename: genFilename(isProdBuild),
|
||||
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
|
||||
path: latestBuild ? paths.output : paths.output_es5,
|
||||
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
|
||||
],
|
||||
},
|
||||
resolve,
|
||||
};
|
||||
};
|
||||
|
||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
return {
|
||||
mode: genMode(isProdBuild),
|
||||
devtool: genDevTool(isProdBuild),
|
||||
entry: {
|
||||
main: "./demo/src/entrypoint.ts",
|
||||
compatibility: "./src/entrypoints/compatibility.ts",
|
||||
},
|
||||
module: {
|
||||
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
|
||||
},
|
||||
optimization: optimization(latestBuild),
|
||||
plugins: [
|
||||
new ManifestPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__DEV__: !isProdBuild,
|
||||
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
|
||||
__VERSION__: JSON.stringify("DEMO"),
|
||||
__DEMO__: true,
|
||||
__VERSION__: JSON.stringify(version),
|
||||
__DEMO__: false,
|
||||
__STATIC_PATH__: "/static/",
|
||||
"process.env.NODE_ENV": JSON.stringify(
|
||||
isProdBuild ? "production" : "development"
|
||||
),
|
||||
...defineOverlay,
|
||||
}),
|
||||
...plugins,
|
||||
// Ignore moment.js locales
|
||||
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
||||
// Color.js is bloated, it contains all color definitions for all material color sets.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@polymer\/paper-styles\/color\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
// Ignore roboto pointing at CDN. We use local font-roboto-local.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@polymer\/font-roboto\/roboto\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
// Ignore mwc icons pointing at CDN.
|
||||
new webpack.NormalModuleReplacementPlugin(
|
||||
/@material\/mwc-icon\/mwc-icon-font\.js$/,
|
||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||
),
|
||||
].filter(Boolean),
|
||||
resolve,
|
||||
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: genFilename(isProdBuild),
|
||||
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
|
||||
filename: ({ chunk }) => {
|
||||
const dontHash = new Set();
|
||||
|
||||
if (!isProdBuild || dontHash.has(chunk.name)) {
|
||||
return `${chunk.name}.js`;
|
||||
}
|
||||
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
|
||||
},
|
||||
chunkFilename:
|
||||
isProdBuild && !isStatsBuild
|
||||
? "chunk.[chunkhash].js"
|
||||
: "[name].chunk.js",
|
||||
path: path.resolve(
|
||||
paths.demo_root,
|
||||
outputRoot,
|
||||
latestBuild ? "frontend_latest" : "frontend_es5"
|
||||
),
|
||||
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
|
||||
// For workerize loader
|
||||
globalObject: "self",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
const config = createWebpackConfig({
|
||||
entry: {
|
||||
app: "./src/entrypoints/app.ts",
|
||||
authorize: "./src/entrypoints/authorize.ts",
|
||||
onboarding: "./src/entrypoints/onboarding.ts",
|
||||
core: "./src/entrypoints/core.ts",
|
||||
compatibility: "./src/entrypoints/compatibility.ts",
|
||||
"custom-panel": "./src/entrypoints/custom-panel.ts",
|
||||
"hass-icons": "./src/entrypoints/hass-icons.ts",
|
||||
},
|
||||
outputRoot: paths.root,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
isStatsBuild,
|
||||
});
|
||||
|
||||
if (latestBuild) {
|
||||
// Create an object mapping browser urls to their paths during build
|
||||
const translationMetadata = require("../build-translations/translationMetadata.json");
|
||||
const workBoxTranslationsTemplatedURLs = {};
|
||||
const englishFP = translationMetadata.translations.en.fingerprints;
|
||||
Object.keys(englishFP).forEach((key) => {
|
||||
workBoxTranslationsTemplatedURLs[
|
||||
`/static/translations/${englishFP[key]}`
|
||||
] = `build-translations/output/${key}.json`;
|
||||
});
|
||||
|
||||
config.plugins.push(
|
||||
new WorkboxPlugin.InjectManifest({
|
||||
swSrc: "./src/entrypoints/service-worker-hass.js",
|
||||
swDest: "service_worker.js",
|
||||
importWorkboxFrom: "local",
|
||||
include: [/\.js$/],
|
||||
templatedURLs: {
|
||||
...workBoxTranslationsTemplatedURLs,
|
||||
"/static/icons/favicon-192x192.png":
|
||||
"public/icons/favicon-192x192.png",
|
||||
"/static/fonts/roboto/Roboto-Light.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2",
|
||||
"/static/fonts/roboto/Roboto-Medium.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2",
|
||||
"/static/fonts/roboto/Roboto-Regular.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2",
|
||||
"/static/fonts/roboto/Roboto-Bold.woff2":
|
||||
"node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
|
||||
return createWebpackConfig({
|
||||
entry: {
|
||||
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
|
||||
compatibility: path.resolve(
|
||||
paths.polymer_dir,
|
||||
"src/entrypoints/compatibility.ts"
|
||||
),
|
||||
},
|
||||
outputRoot: paths.demo_root,
|
||||
defineOverlay: {
|
||||
__VERSION__: JSON.stringify(`DEMO-${version}`),
|
||||
__DEMO__: true,
|
||||
},
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
isStatsBuild,
|
||||
});
|
||||
};
|
||||
|
||||
const createCastConfig = ({ isProdBuild, latestBuild }) => {
|
||||
const entry = {
|
||||
launcher: path.resolve(paths.cast_dir, "src/launcher/entrypoint.ts"),
|
||||
};
|
||||
|
||||
if (latestBuild) {
|
||||
entry.receiver = path.resolve(paths.cast_dir, "src/receiver/entrypoint.ts");
|
||||
}
|
||||
|
||||
return createWebpackConfig({
|
||||
entry,
|
||||
outputRoot: paths.cast_root,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
});
|
||||
};
|
||||
|
||||
const createHassioConfig = ({ isProdBuild, latestBuild }) => {
|
||||
if (latestBuild) {
|
||||
throw new Error("Hass.io does not support latest build!");
|
||||
}
|
||||
const config = createWebpackConfig({
|
||||
entry: {
|
||||
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.js"),
|
||||
},
|
||||
outputRoot: "",
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
config.output.path = paths.hassio_root;
|
||||
config.output.publicPath = paths.hassio_publicPath;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
const createGalleryConfig = ({ isProdBuild, latestBuild }) => {
|
||||
if (!latestBuild) {
|
||||
throw new Error("Gallery only supports latest build!");
|
||||
}
|
||||
const config = createWebpackConfig({
|
||||
entry: {
|
||||
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
|
||||
},
|
||||
outputRoot: paths.gallery_root,
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
});
|
||||
|
||||
return config;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
resolve,
|
||||
plugins,
|
||||
optimization,
|
||||
createAppConfig,
|
||||
createDemoConfig,
|
||||
createCastConfig,
|
||||
createHassioConfig,
|
||||
createGalleryConfig,
|
||||
};
|
||||
|
56
cast/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Home Assistant Cast
|
||||
|
||||
Home Assistant Cast is made up of two separate applications:
|
||||
|
||||
- Chromecast receiver application that can connect to Home Assistant and display relevant information.
|
||||
- Launcher website that allows users to authorize with their Home Assistant installation and launch the receiver app on their Chromecast.
|
||||
|
||||
## Development
|
||||
|
||||
- Run `script/develop_cast` to launch the Cast receiver dev server. Keep this running.
|
||||
- Navigate to http://localhost:8080 to start the launcher
|
||||
- Debug the receiver running on the Chromecast via [chrome://inspect/#devices](chrome://inspect/#devices)
|
||||
|
||||
## Setting up development environment
|
||||
|
||||
### Registering development cast app
|
||||
|
||||
- Go to https://cast.google.com/publish and enroll your account for the Google Cast SDK (costs \$5)
|
||||
- Register your Chromecast as a testing device by entering the serial
|
||||
- Add new application -> Custom Receiver
|
||||
- Name: Home Assistant Dev
|
||||
- Receiver Application URL: http://IP-OF-DEV-MACHINE:8080/receiver.html
|
||||
- Guest Mode: off
|
||||
- Google Case for Audio: off
|
||||
|
||||
### Setting dev variables
|
||||
|
||||
Open `src/cast/dev_const.ts` and change `CAST_DEV_APP_ID` to the ID of the app you just created. And set the `CAST_DEV_HASS_URL` to the url of you development machine.
|
||||
|
||||
### Changing configuration
|
||||
|
||||
In `configuration.yaml`, configure CORS for the HTTP integration:
|
||||
|
||||
```yaml
|
||||
http:
|
||||
cors_allowed_origins:
|
||||
- https://cast.home-assistant.io
|
||||
- http://IP-OF-DEV-MACHINE:8080
|
||||
```
|
||||
|
||||
## Running development
|
||||
|
||||
```bash
|
||||
cd cast
|
||||
script/develop_cast
|
||||
```
|
||||
|
||||
The launcher application will be accessible at [http://localhost:8080](http://localhost:8080) and the receiver application will be accessible at [http://localhost:8080/receiver.html](http://localhost:8080/receiver.html) (but only works if accessed by a Chromecast).
|
||||
|
||||
### Developing cast widgets in HA ui
|
||||
|
||||
If your work involves interaction with the Cast parts from the normal Home Assistant UI, you will need to have that development script running too (`script/develop`).
|
||||
|
||||
### Developing the cast demo
|
||||
|
||||
The cast demo is triggered from the Home Assistant demo. To work on that, you will also need to run the development script for the demo (`script/develop_demo`).
|
20
cast/public/_headers
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
Cache-Control: public, max-age: 0, s-maxage=3600, must-revalidate
|
||||
Content-Security-Policy: form-action https:
|
||||
Feature-Policy: vibrate 'none'; geolocation 'none'; midi 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; vibrate 'none'; payment 'none'
|
||||
Referrer-Policy: no-referrer-when-downgrade
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: DENY
|
||||
X-XSS-Protection: 1; mode=block
|
||||
|
||||
/images/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
||||
|
||||
/manifest.json
|
||||
Cache-Control: public, max-age: 3600, s-maxage=3600
|
||||
|
||||
/frontend_es5/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
||||
|
||||
/frontend_latest/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
BIN
cast/public/images/arsaboo.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
cast/public/images/favicon.ico
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
cast/public/images/google-nest-hub.png
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
cast/public/images/ha-cast-icon.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
cast/public/images/melody.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
18
cast/public/manifest.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"background_color": "#FFFFFF",
|
||||
"description": "Show Home Assistant on your Chromecast or Google Assistant devices with a screen.",
|
||||
"dir": "ltr",
|
||||
"display": "standalone",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/ha-cast-icon.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"lang": "en-US",
|
||||
"name": "Home Assistant Cast",
|
||||
"short_name": "HA Cast",
|
||||
"start_url": "/?homescreen=1",
|
||||
"theme_color": "#03A9F4"
|
||||
}
|
3
cast/public/service_worker.js
Normal file
@@ -0,0 +1,3 @@
|
||||
self.addEventListener("fetch", function(event) {
|
||||
event.respondWith(fetch(event.request));
|
||||
});
|
9
cast/script/build_cast
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Build the cast receiver
|
||||
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
./node_modules/.bin/gulp build-cast
|
9
cast/script/develop_cast
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Develop the cast receiver
|
||||
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
./node_modules/.bin/gulp develop-cast
|
5
cast/script/upload
Executable file
@@ -0,0 +1,5 @@
|
||||
# Run it twice, second time we just delete.
|
||||
aws s3 sync dist s3://cast.home-assistant.io --acl public-read
|
||||
# Don't delete as it might break open sites that need to load code splitted things.
|
||||
# aws s3 sync dist s3://cast.home-assistant.io --acl public-read --delete
|
||||
# Todo : update JS first, HTML last.
|
261
cast/src/html/launcher-faq.html.template
Normal file
@@ -0,0 +1,261 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home Assistant Cast - FAQ</title>
|
||||
<link rel="icon" href="/images/ha-cast-icon.png" type="image/png" />
|
||||
<%= renderTemplate('_style_base') %>
|
||||
<style>
|
||||
body {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
</style>
|
||||
<meta property="fb:app_id" content="338291289691179" />
|
||||
<meta property="og:title" content="FAQ - Home Assistant Cast" />
|
||||
<meta property="og:site_name" content="Home Assistant Cast" />
|
||||
<meta property="og:url" content="https://cast.home-assistant.io/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Frequently asked questions about Home Assistant Cast."
|
||||
/>
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://cast.home-assistant.io/images/google-nest-hub.png"
|
||||
/>
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:site" content="@home_assistant" />
|
||||
<meta name="twitter:title" content="FAQ - Home Assistant Cast" />
|
||||
<meta
|
||||
name="twitter:description"
|
||||
content="Frequently asked questions about Home Assistant Cast."
|
||||
/>
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content="https://cast.home-assistant.io/images/google-nest-hub.png"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<%= renderTemplate('_js_base') %>
|
||||
|
||||
<script type="module" crossorigin="use-credentials">
|
||||
import "<%= latestLauncherJS %>";
|
||||
</script>
|
||||
|
||||
<script nomodule>
|
||||
(function() {
|
||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||
if (!isS101) {
|
||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<hc-layout subtitle="FAQ">
|
||||
<style>
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
</style>
|
||||
<div class="card-content">
|
||||
<p><a href="/">« Back to Home Assistant Cast</a></p>
|
||||
</div>
|
||||
|
||||
<div class="section-header">What is Home Assistant Cast?</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant Cast allows you to show your Home Assistant data on a
|
||||
Chromecast device and allows you to interact with Home Assistant on
|
||||
Google Assistant devices with a screen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header">
|
||||
What are the Home Assistant Cast requirements?
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant Cast requires a Home Assistant installation that is
|
||||
accessible via HTTPS (the url starts with "https://").
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header">What is Home Assistant?</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant is worlds biggest open source home automation platform
|
||||
with a focus on privacy and local control. You can install Home
|
||||
Assistant for free.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://www.home-assistant.io" target="_blank"
|
||||
>Visit the Home Assistant website.</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header" id="https">
|
||||
Why does my Home Assistant needs to be served using HTTPS?
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
The Chromecast only works with websites served over HTTPS. This means
|
||||
that the Home Assistant Cast app that runs on your Chromecast is
|
||||
served over HTTPS. Websites served over HTTPS are restricted on what
|
||||
content can be accessed on websites served over HTTP. This is called
|
||||
mixed active content (<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content#Mixed_active_content"
|
||||
target="_blank"
|
||||
>learn more @ MDN</a
|
||||
>).
|
||||
</p>
|
||||
<p>
|
||||
The easiest way to get your Home Assistant installation served over
|
||||
HTTPS is by signing up for
|
||||
<a href="https://www.nabucasa.com" target="_blank"
|
||||
>Home Assistant Cloud by Nabu Casa</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header" id="https">
|
||||
Why does Home Assistant Cast require me to authorize my Home Assistant
|
||||
instance?
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
You're currently looking at the Home Assistant Cast launcher
|
||||
application. This is a standalone application to launch Home Assistant
|
||||
Cast on your Chromecast. Because Chromecasts do not allow us to log in
|
||||
to Home Assistant, we need to supply authentication to it from the
|
||||
launcher. This authentication is obtained when you authorize your
|
||||
instance. Your authentication credentials will remain in your browser
|
||||
and on your Cast device.
|
||||
</p>
|
||||
<p>
|
||||
Your authentication credentials or Home Assistant url are never sent
|
||||
to the Cloud. You can validate this behavior in
|
||||
<a
|
||||
href="https://github.com/home-assistant/home-assistant-polymer/tree/dev/cast"
|
||||
target="_blank"
|
||||
>the source code</a
|
||||
>.
|
||||
</p>
|
||||
<p>
|
||||
The launcher application exists to make it possible to use Home
|
||||
Assistant Cast with older versions of Home Assistant.
|
||||
</p>
|
||||
<p>
|
||||
Starting with Home Assistant 0.97, Home Assistant Cast is also built
|
||||
into the Lovelace UI as a special entities card row. Since the
|
||||
Lovelace UI already has authentication, you will be able to start
|
||||
casting right away.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header">Wat does Home Assistant Cast do?</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant Cast is a receiver application for the Chromecast. When
|
||||
loaded, it will make a direct connection to your Home Assistant
|
||||
instance.
|
||||
</p>
|
||||
<p>
|
||||
Home Assistant Cast is able to render any of your Lovelace views on
|
||||
your Chromecast. Things that work in Lovelace in Home Assistant will
|
||||
work in Home Assistant Cast:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Render Lovelace views, including custom cards</li>
|
||||
<li>
|
||||
Real-time data stream will ensure the UI always shows the latest
|
||||
state of your house
|
||||
</li>
|
||||
<li>Navigate between views using navigate actions or weblinks</li>
|
||||
<li>
|
||||
Instant updates of the casted Lovelace UI when you update your
|
||||
Lovelace configuration.
|
||||
</li>
|
||||
</ul>
|
||||
<p>Things that currently do not work:</p>
|
||||
<ul>
|
||||
<li>
|
||||
Live videostreams using the streaming integration
|
||||
</li>
|
||||
<li>Specifying a view with a single card with "panel: true".</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section-header" id="https">
|
||||
How do I change what is shown on my Chromecast?
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant Cast allows you to show your Lovelace view on your
|
||||
Chromecast. So to edit what is shown, you need to edit your Lovelace
|
||||
UI.
|
||||
</p>
|
||||
<p>
|
||||
To edit your Lovelace UI, open Home Assistant, click on the three-dot
|
||||
menu in the top right and click on "Configure UI".
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="section-header" id="browser">
|
||||
What browsers are supported?
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Chromecast is a technology developed by Google, and is available on:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Google Chrome (all platforms except on iOS)</li>
|
||||
<li>
|
||||
Microsoft Edge (all platforms,
|
||||
<a href="https://www.microsoftedgeinsider.com" target="_blank"
|
||||
>dev and canary builds only</a
|
||||
>)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="section-header">Why do some custom cards not work?</div>
|
||||
<div class="card-content">
|
||||
<p>
|
||||
Home Assistant needs to be configured to allow Home Assistant Cast to
|
||||
load custom cards. Starting with Home Assistant 0.97, this is done
|
||||
automatically. If you are on an older version, or have manually
|
||||
configured CORS for the HTTP integration, add the following to your
|
||||
configuration.yaml file:
|
||||
</p>
|
||||
<pre>
|
||||
http:
|
||||
cors_allowed_origins:
|
||||
- https://cast.home-assistant.io</pre
|
||||
>
|
||||
<p>
|
||||
Some custom cards rely on things that are only available in the normal
|
||||
Home Assistant interface. This requires an update by the custom card
|
||||
developer.
|
||||
</p>
|
||||
<p>
|
||||
If you're a custom card developer: the most common mistake is that
|
||||
LitElement is extracted from an element that is not available on the
|
||||
page.
|
||||
</p>
|
||||
</div>
|
||||
</hc-layout>
|
||||
|
||||
<script>
|
||||
var _gaq = [["_setAccount", "UA-57927901-9"], ["_trackPageview"]];
|
||||
(function(d, t) {
|
||||
var g = d.createElement(t),
|
||||
s = d.getElementsByTagName(t)[0];
|
||||
g.src =
|
||||
("https:" == location.protocol ? "//ssl" : "//www") +
|
||||
".google-analytics.com/ga.js";
|
||||
s.parentNode.insertBefore(g, s);
|
||||
})(document, "script");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
54
cast/src/html/launcher.html.template
Normal file
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home Assistant Cast</title>
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<link rel="icon" href="/images/ha-cast-icon.png" type="image/png" />
|
||||
<%= renderTemplate('_style_base') %>
|
||||
<style>
|
||||
body {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
</style>
|
||||
<meta property="fb:app_id" content="338291289691179">
|
||||
<meta property="og:title" content="Home Assistant Cast">
|
||||
<meta property="og:site_name" content="Home Assistant Cast">
|
||||
<meta property="og:url" content="https://cast.home-assistant.io/">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:description" content="Show Home Assistant on your Chromecast or Google Assistant devices with a screen.">
|
||||
<meta property="og:image" content="https://cast.home-assistant.io/images/google-nest-hub.png">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@home_assistant">
|
||||
<meta name="twitter:title" content="Home Assistant Cast">
|
||||
<meta name="twitter:description" content="Show Home Assistant on your Chromecast or Google Assistant devices with a screen.">
|
||||
<meta name="twitter:image" content="https://cast.home-assistant.io/images/google-nest-hub.png">
|
||||
</head>
|
||||
<body>
|
||||
<%= renderTemplate('_js_base') %>
|
||||
|
||||
<hc-connect></hc-connect>
|
||||
|
||||
<script type="module" crossorigin="use-credentials">
|
||||
import "<%= latestLauncherJS %>";
|
||||
</script>
|
||||
|
||||
<script nomodule>
|
||||
(function() {
|
||||
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
|
||||
if (!isS101) {
|
||||
_ls("/static/polyfills/custom-elements-es5-adapter.js");
|
||||
_ls("<%= es5LauncherJS %>");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-57927901-9', 'auto');
|
||||
ga('send', 'pageview', location.pathname.includes("auth_callback") === -1 ? location.pathname : "/");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
18
cast/src/html/receiver.html.template
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
|
||||
<script type="module" src="<%= latestReceiverJS %>"></script>
|
||||
<%= renderTemplate('_style_base') %>
|
||||
<style>
|
||||
body {
|
||||
background-color: white;
|
||||
font-size: initial;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var _gaq=[['_setAccount','UA-57927901-10'],['_trackPageview']];
|
||||
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
|
||||
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
|
||||
s.parentNode.insertBefore(g,s)}(document,'script'));
|
||||
</script>
|
||||
</html>
|
5
cast/src/launcher/entrypoint.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import "../../../src/resources/ha-style";
|
||||
import "../../../src/resources/roboto";
|
||||
import "../../../src/components/ha-iconset-svg";
|
||||
import "../../../src/resources/hass-icons";
|
||||
import "./layout/hc-connect";
|
282
cast/src/launcher/layout/hc-cast.ts
Normal file
@@ -0,0 +1,282 @@
|
||||
import {
|
||||
customElement,
|
||||
LitElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import { Connection, Auth } from "home-assistant-js-websocket";
|
||||
import "@polymer/iron-icon";
|
||||
import "@polymer/paper-listbox/paper-listbox";
|
||||
import "@polymer/paper-item/paper-icon-item";
|
||||
import "../../../../src/components/ha-icon";
|
||||
import {
|
||||
enableWrite,
|
||||
askWrite,
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import {
|
||||
ensureConnectedCastSession,
|
||||
castSendShowLovelaceView,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||
import {
|
||||
LovelaceConfig,
|
||||
getLovelaceCollection,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import "./hc-layout";
|
||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
|
||||
|
||||
@customElement("hc-cast")
|
||||
class HcCast extends LitElement {
|
||||
@property() public auth!: Auth;
|
||||
@property() public connection!: Connection;
|
||||
@property() public castManager!: CastManager;
|
||||
@property() private askWrite = false;
|
||||
@property() private lovelaceConfig?: LovelaceConfig | null;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (this.lovelaceConfig === undefined) {
|
||||
return html`
|
||||
<loading-screen></loading-screen>>
|
||||
`;
|
||||
}
|
||||
|
||||
const error =
|
||||
this.castManager.castState === "NO_DEVICES_AVAILABLE"
|
||||
? html`
|
||||
<p>
|
||||
There were no suitable Chromecast devices to cast to found.
|
||||
</p>
|
||||
`
|
||||
: undefined;
|
||||
|
||||
return html`
|
||||
<hc-layout .auth=${this.auth} .connection=${this.connection}>
|
||||
${this.askWrite
|
||||
? html`
|
||||
<p class="question action-item">
|
||||
Stay logged in?
|
||||
<span>
|
||||
<mwc-button @click=${this._handleSaveTokens}>
|
||||
YES
|
||||
</mwc-button>
|
||||
<mwc-button @click=${this._handleSkipSaveTokens}>
|
||||
NO
|
||||
</mwc-button>
|
||||
</span>
|
||||
</p>
|
||||
`
|
||||
: ""}
|
||||
${error
|
||||
? html`
|
||||
<div class="card-content">${error}</div>
|
||||
`
|
||||
: !this.castManager.status
|
||||
? html`
|
||||
<p class="center-item">
|
||||
<mwc-button raised @click=${this._handleLaunch}>
|
||||
<iron-icon icon="hass:cast"></iron-icon>
|
||||
Start Casting
|
||||
</mwc-button>
|
||||
</p>
|
||||
`
|
||||
: html`
|
||||
<div class="section-header">PICK A VIEW</div>
|
||||
<paper-listbox
|
||||
attr-for-selected="data-path"
|
||||
.selected=${this.castManager.status.lovelacePath || ""}
|
||||
>
|
||||
${(this.lovelaceConfig
|
||||
? this.lovelaceConfig.views
|
||||
: [generateDefaultViewConfig([], [], [], {}, () => "")]
|
||||
).map(
|
||||
(view, idx) => html`
|
||||
<paper-icon-item
|
||||
@click=${this._handlePickView}
|
||||
data-path=${view.path || idx}
|
||||
>
|
||||
${view.icon
|
||||
? html`
|
||||
<ha-icon
|
||||
.icon=${view.icon}
|
||||
slot="item-icon"
|
||||
></ha-icon>
|
||||
`
|
||||
: ""}
|
||||
${view.title || view.path}
|
||||
</paper-icon-item>
|
||||
`
|
||||
)}
|
||||
</paper-listbox>
|
||||
`}
|
||||
<div class="card-actions">
|
||||
${this.castManager.status
|
||||
? html`
|
||||
<mwc-button @click=${this._handleLaunch}>
|
||||
<iron-icon icon="hass:cast-connected"></iron-icon>
|
||||
Manage
|
||||
</mwc-button>
|
||||
`
|
||||
: ""}
|
||||
<div class="spacer"></div>
|
||||
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
||||
</div>
|
||||
</hc-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
const llColl = getLovelaceCollection(this.connection);
|
||||
// We first do a single refresh because we need to check if there is LL
|
||||
// configuration.
|
||||
llColl.refresh().then(
|
||||
() => {
|
||||
llColl.subscribe((config) => {
|
||||
this.lovelaceConfig = config;
|
||||
});
|
||||
},
|
||||
async () => {
|
||||
this.lovelaceConfig = null;
|
||||
}
|
||||
);
|
||||
|
||||
this.askWrite = askWrite();
|
||||
|
||||
this.castManager.addEventListener("state-changed", () => {
|
||||
this.requestUpdate();
|
||||
});
|
||||
this.castManager.addEventListener("connection-changed", () => {
|
||||
this.requestUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
super.updated(changedProps);
|
||||
toggleAttribute(
|
||||
this,
|
||||
"hide-icons",
|
||||
this.lovelaceConfig
|
||||
? !this.lovelaceConfig.views.some((view) => view.icon)
|
||||
: true
|
||||
);
|
||||
}
|
||||
|
||||
private async _handleSkipSaveTokens() {
|
||||
this.askWrite = false;
|
||||
}
|
||||
|
||||
private async _handleSaveTokens() {
|
||||
enableWrite();
|
||||
this.askWrite = false;
|
||||
}
|
||||
|
||||
private _handleLaunch() {
|
||||
this.castManager.requestSession();
|
||||
}
|
||||
|
||||
private async _handlePickView(ev: Event) {
|
||||
const path = (ev.currentTarget as any).getAttribute("data-path");
|
||||
await ensureConnectedCastSession(this.castManager!, this.auth!);
|
||||
castSendShowLovelaceView(this.castManager, path);
|
||||
}
|
||||
|
||||
private async _handleLogout() {
|
||||
try {
|
||||
await this.auth.revoke();
|
||||
saveTokens(null);
|
||||
if (this.castManager.castSession) {
|
||||
this.castManager.castContext.endCurrentSession(true);
|
||||
}
|
||||
this.connection.close();
|
||||
location.reload();
|
||||
} catch (err) {
|
||||
alert("Unable to log out!");
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.center-item {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.question {
|
||||
position: relative;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.question:before {
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
content: "";
|
||||
background-color: var(--primary-color);
|
||||
opacity: 0.12;
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
.connection,
|
||||
.connection a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
mwc-button iron-icon {
|
||||
margin-right: 8px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
paper-listbox {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
paper-listbox ha-icon {
|
||||
padding: 12px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
paper-icon-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
paper-icon-item[disabled] {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
:host([hide-icons]) paper-icon-item {
|
||||
--paper-item-icon-width: 0px;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-content a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-cast": HcCast;
|
||||
}
|
||||
}
|
333
cast/src/launcher/layout/hc-connect.ts
Normal file
@@ -0,0 +1,333 @@
|
||||
import {
|
||||
LitElement,
|
||||
customElement,
|
||||
property,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
} from "lit-element";
|
||||
import {
|
||||
getAuth,
|
||||
createConnection,
|
||||
Auth,
|
||||
getAuthOptions,
|
||||
ERR_HASS_HOST_REQUIRED,
|
||||
ERR_INVALID_HTTPS_TO_HTTP,
|
||||
Connection,
|
||||
ERR_CANNOT_CONNECT,
|
||||
ERR_INVALID_AUTH,
|
||||
} from "home-assistant-js-websocket";
|
||||
import "@polymer/iron-icon";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
import {
|
||||
loadTokens,
|
||||
saveTokens,
|
||||
} from "../../../../src/common/auth/token_storage";
|
||||
import "../../../../src/layouts/loading-screen";
|
||||
import { CastManager, getCastManager } from "../../../../src/cast/cast_manager";
|
||||
import "./hc-layout";
|
||||
import { castSendShowDemo } from "../../../../src/cast/receiver_messages";
|
||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||
|
||||
const seeFAQ = (qid) => html`
|
||||
See <a href="./faq.html${qid ? `#${qid}` : ""}">the FAQ</a> for more
|
||||
information.
|
||||
`;
|
||||
const translateErr = (err) =>
|
||||
err === ERR_CANNOT_CONNECT
|
||||
? "Unable to connect"
|
||||
: err === ERR_HASS_HOST_REQUIRED
|
||||
? "Please enter a Home Assistant URL."
|
||||
: err === ERR_INVALID_HTTPS_TO_HTTP
|
||||
? html`
|
||||
Cannot connect to Home Assistant instances over "http://".
|
||||
${seeFAQ("https")}
|
||||
`
|
||||
: `Unknown error (${err}).`;
|
||||
|
||||
const INTRO = html`
|
||||
<p>
|
||||
Home Assistant Cast allows you to cast your Home Assistant installation to
|
||||
Chromecast video devices and to Google Assistant devices with a screen.
|
||||
</p>
|
||||
<p>
|
||||
For more information, see the
|
||||
<a href="./faq.html">frequently asked questions</a>.
|
||||
</p>
|
||||
`;
|
||||
|
||||
@customElement("hc-connect")
|
||||
export class HcConnect extends LitElement {
|
||||
@property() private loading = false;
|
||||
// If we had stored credentials but we cannot connect,
|
||||
// show a screen asking retry or logout.
|
||||
@property() private cannotConnect = false;
|
||||
@property() private error?: string | TemplateResult;
|
||||
@property() private auth?: Auth;
|
||||
@property() private connection?: Connection;
|
||||
@property() private castManager?: CastManager | null;
|
||||
private openDemo = false;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (this.cannotConnect) {
|
||||
const tokens = loadTokens();
|
||||
return html`
|
||||
<hc-layout>
|
||||
<div class="card-content">
|
||||
Unable to connect to ${tokens!.hassUrl}.
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a href="/">
|
||||
<mwc-button>
|
||||
Retry
|
||||
</mwc-button>
|
||||
</a>
|
||||
<div class="spacer"></div>
|
||||
<mwc-button @click=${this._handleLogout}>Log out</mwc-button>
|
||||
</div>
|
||||
</hc-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
if (this.castManager === undefined || this.loading) {
|
||||
return html`
|
||||
<loading-screen></loading-screen>
|
||||
`;
|
||||
}
|
||||
|
||||
if (this.castManager === null) {
|
||||
return html`
|
||||
<hc-layout>
|
||||
<div class="card-content">
|
||||
${INTRO}
|
||||
<p class="error">
|
||||
The Cast API is not available in your browser.
|
||||
${seeFAQ("browser")}
|
||||
</p>
|
||||
</div>
|
||||
</hc-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
if (!this.auth) {
|
||||
return html`
|
||||
<hc-layout>
|
||||
<div class="card-content">
|
||||
${INTRO}
|
||||
<p>
|
||||
To get started, enter your Home Assistant URL and click authorize.
|
||||
If you want a preview instead, click the show demo button.
|
||||
</p>
|
||||
<p>
|
||||
<paper-input
|
||||
label="Home Assistant URL"
|
||||
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
|
||||
@keydown=${this._handleInputKeyDown}
|
||||
></paper-input>
|
||||
</p>
|
||||
${this.error
|
||||
? html`
|
||||
<p class="error">${this.error}</p>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<mwc-button @click=${this._handleDemo}>
|
||||
Show Demo
|
||||
<iron-icon
|
||||
.icon=${this.castManager.castState === "CONNECTED"
|
||||
? "hass:cast-connected"
|
||||
: "hass:cast"}
|
||||
></iron-icon>
|
||||
</mwc-button>
|
||||
<div class="spacer"></div>
|
||||
<mwc-button @click=${this._handleConnect}>Authorize</mwc-button>
|
||||
</div>
|
||||
</hc-layout>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hc-cast
|
||||
.connection=${this.connection}
|
||||
.auth=${this.auth}
|
||||
.castManager=${this.castManager}
|
||||
></hc-cast>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
import("./hc-cast");
|
||||
|
||||
getCastManager().then(
|
||||
async (mgr) => {
|
||||
this.castManager = mgr;
|
||||
mgr.addEventListener("connection-changed", () => {
|
||||
this.requestUpdate();
|
||||
});
|
||||
mgr.addEventListener("state-changed", () => {
|
||||
if (this.openDemo && mgr.castState === "CONNECTED" && !this.auth) {
|
||||
castSendShowDemo(mgr);
|
||||
}
|
||||
});
|
||||
|
||||
if (location.search.indexOf("auth_callback=1") !== -1) {
|
||||
this._tryConnection("auth-callback");
|
||||
} else if (loadTokens()) {
|
||||
this._tryConnection("saved-tokens");
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.castManager = null;
|
||||
}
|
||||
);
|
||||
registerServiceWorker(false);
|
||||
}
|
||||
|
||||
private async _handleDemo() {
|
||||
this.openDemo = true;
|
||||
if (this.castManager!.status && !this.castManager!.status.showDemo) {
|
||||
castSendShowDemo(this.castManager!);
|
||||
} else {
|
||||
this.castManager!.requestSession();
|
||||
}
|
||||
}
|
||||
|
||||
private _handleInputKeyDown(ev: KeyboardEvent) {
|
||||
// Handle pressing enter.
|
||||
if (ev.keyCode === 13) {
|
||||
this._handleConnect();
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleConnect() {
|
||||
const inputEl = this.shadowRoot!.querySelector("paper-input")!;
|
||||
const value = inputEl.value || "";
|
||||
this.error = undefined;
|
||||
|
||||
if (value === "") {
|
||||
this.error = "Please enter a Home Assistant URL.";
|
||||
return;
|
||||
} else if (value.indexOf("://") === -1) {
|
||||
this.error =
|
||||
"Please enter your full URL, including the protocol part (https://).";
|
||||
return;
|
||||
}
|
||||
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(value);
|
||||
} catch (err) {
|
||||
this.error = "Invalid URL";
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.protocol === "http:" && url.hostname !== "localhost") {
|
||||
this.error = translateErr(ERR_INVALID_HTTPS_TO_HTTP);
|
||||
return;
|
||||
}
|
||||
await this._tryConnection("user-request", `${url.protocol}//${url.host}`);
|
||||
}
|
||||
|
||||
private async _tryConnection(
|
||||
init: "auth-callback" | "user-request" | "saved-tokens",
|
||||
hassUrl?: string
|
||||
) {
|
||||
const options: getAuthOptions = {
|
||||
saveTokens,
|
||||
loadTokens: () => Promise.resolve(loadTokens()),
|
||||
};
|
||||
if (hassUrl) {
|
||||
options.hassUrl = hassUrl;
|
||||
}
|
||||
let auth: Auth;
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
auth = await getAuth(options);
|
||||
} catch (err) {
|
||||
if (init === "saved-tokens" && err === ERR_CANNOT_CONNECT) {
|
||||
this.cannotConnect = true;
|
||||
return;
|
||||
}
|
||||
this.error = translateErr(err);
|
||||
this.loading = false;
|
||||
return;
|
||||
} finally {
|
||||
// Clear url if we have a auth callback in url.
|
||||
if (location.search.includes("auth_callback=1")) {
|
||||
history.replaceState(null, "", location.pathname);
|
||||
}
|
||||
}
|
||||
|
||||
let conn: Connection;
|
||||
|
||||
try {
|
||||
conn = await createConnection({ auth });
|
||||
} catch (err) {
|
||||
// In case of saved tokens, silently solve problems.
|
||||
if (init === "saved-tokens") {
|
||||
if (err === ERR_CANNOT_CONNECT) {
|
||||
this.cannotConnect = true;
|
||||
} else if (err === ERR_INVALID_AUTH) {
|
||||
saveTokens(null);
|
||||
}
|
||||
} else {
|
||||
this.error = translateErr(err);
|
||||
}
|
||||
|
||||
return;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
this.auth = auth;
|
||||
this.connection = conn;
|
||||
this.castManager!.auth = auth;
|
||||
}
|
||||
|
||||
private async _handleLogout() {
|
||||
try {
|
||||
saveTokens(null);
|
||||
location.reload();
|
||||
} catch (err) {
|
||||
alert("Unable to log out!");
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
.card-content a {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.card-actions a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.error a {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
mwc-button iron-icon {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-connect": HcConnect;
|
||||
}
|
||||
}
|
166
cast/src/launcher/layout/hc-layout.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
customElement,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import {
|
||||
Auth,
|
||||
Connection,
|
||||
HassUser,
|
||||
getUser,
|
||||
} from "home-assistant-js-websocket";
|
||||
import "../../../../src/components/ha-card";
|
||||
|
||||
@customElement("hc-layout")
|
||||
class HcLayout extends LitElement {
|
||||
@property() public subtitle?: string | undefined;
|
||||
@property() public auth?: Auth;
|
||||
@property() public connection?: Connection;
|
||||
@property() public user?: HassUser;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="layout">
|
||||
<img class="hero" src="/images/google-nest-hub.png" />
|
||||
<div class="card-header">
|
||||
Home Assistant Cast${this.subtitle ? ` – ${this.subtitle}` : ""}
|
||||
${this.auth
|
||||
? html`
|
||||
<div class="subtitle">
|
||||
<a href=${this.auth.data.hassUrl} target="_blank"
|
||||
>${this.auth.data.hassUrl.substr(
|
||||
this.auth.data.hassUrl.indexOf("//") + 2
|
||||
)}</a
|
||||
>
|
||||
${this.user
|
||||
? html`
|
||||
– ${this.user.name}
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</ha-card>
|
||||
<div class="footer">
|
||||
<a href="./faq.html">Frequently Asked Questions</a> – Found a bug? Let
|
||||
@balloob know
|
||||
<!-- <a
|
||||
href="https://github.com/home-assistant/home-assistant-polymer/issues"
|
||||
target="_blank"
|
||||
>Let us know!</a
|
||||
> -->
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
|
||||
if (this.connection) {
|
||||
getUser(this.connection).then((user) => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
min-height: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ha-card {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.layout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
color: var(--ha-card-header-color, --primary-text-color);
|
||||
font-family: var(--ha-card-header-font-family, inherit);
|
||||
font-size: var(--ha-card-header-font-size, 24px);
|
||||
letter-spacing: -0.012em;
|
||||
line-height: 32px;
|
||||
padding: 24px 16px 16px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 14px;
|
||||
color: var(--secondary-text-color);
|
||||
line-height: initial;
|
||||
}
|
||||
.subtitle a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
:host ::slotted(.card-content:not(:first-child)),
|
||||
slot:not(:first-child)::slotted(.card-content) {
|
||||
padding-top: 0px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
:host ::slotted(.section-header) {
|
||||
font-weight: 500;
|
||||
padding: 4px 16px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
:host ::slotted(.card-content) {
|
||||
padding: 16px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
:host ::slotted(.card-actions) {
|
||||
border-top: 1px solid #e8e8e8;
|
||||
padding: 5px 16px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
padding: 8px 0 24px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.footer a {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
@media all and (max-width: 500px) {
|
||||
:host {
|
||||
justify-content: flex-start;
|
||||
min-height: 90%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-layout": HcLayout;
|
||||
}
|
||||
}
|
1
cast/src/receiver/cast_context.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const castContext = cast.framework.CastReceiverContext.getInstance();
|
141
cast/src/receiver/demo/cast-demo-entities.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
import { Entity, convertEntities } from "../../../../src/fake_data/entity";
|
||||
|
||||
export const castDemoEntities: () => Entity[] = () =>
|
||||
convertEntities({
|
||||
"light.reading_light": {
|
||||
entity_id: "light.reading_light",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Reading Light",
|
||||
},
|
||||
},
|
||||
"light.ceiling": {
|
||||
entity_id: "light.ceiling",
|
||||
state: "on",
|
||||
attributes: {
|
||||
friendly_name: "Ceiling lights",
|
||||
},
|
||||
},
|
||||
"light.standing_lamp": {
|
||||
entity_id: "light.standing_lamp",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Standing Lamp",
|
||||
},
|
||||
},
|
||||
"sensor.temperature_inside": {
|
||||
entity_id: "sensor.temperature_inside",
|
||||
state: "22.7",
|
||||
attributes: {
|
||||
battery_level: 78,
|
||||
unit_of_measurement: "\u00b0C",
|
||||
friendly_name: "Inside",
|
||||
device_class: "temperature",
|
||||
},
|
||||
},
|
||||
"sensor.temperature_outside": {
|
||||
entity_id: "sensor.temperature_outside",
|
||||
state: "31.4",
|
||||
attributes: {
|
||||
battery_level: 53,
|
||||
unit_of_measurement: "\u00b0C",
|
||||
friendly_name: "Outside",
|
||||
device_class: "temperature",
|
||||
},
|
||||
},
|
||||
"person.arsaboo": {
|
||||
entity_id: "person.arsaboo",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
radius: 50,
|
||||
friendly_name: "Arsaboo",
|
||||
latitude: 52.3579946,
|
||||
longitude: 4.8664597,
|
||||
entity_picture: "/images/arsaboo.jpg",
|
||||
},
|
||||
},
|
||||
"person.melody": {
|
||||
entity_id: "person.melody",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
radius: 50,
|
||||
friendly_name: "Melody",
|
||||
latitude: 52.3408927,
|
||||
longitude: 4.8711073,
|
||||
entity_picture: "/images/melody.jpg",
|
||||
},
|
||||
},
|
||||
"zone.home": {
|
||||
entity_id: "zone.home",
|
||||
state: "zoning",
|
||||
attributes: {
|
||||
hidden: true,
|
||||
latitude: 52.3631339,
|
||||
longitude: 4.8903147,
|
||||
radius: 100,
|
||||
friendly_name: "Home",
|
||||
icon: "hass:home",
|
||||
},
|
||||
},
|
||||
"input_number.harmonyvolume": {
|
||||
entity_id: "input_number.harmonyvolume",
|
||||
state: "18.0",
|
||||
attributes: {
|
||||
initial: 30,
|
||||
min: 1,
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
friendly_name: "Volume",
|
||||
icon: "hass:volume-high",
|
||||
},
|
||||
},
|
||||
"climate.upstairs": {
|
||||
entity_id: "climate.upstairs",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
current_temperature: 24,
|
||||
min_temp: 15,
|
||||
max_temp: 30,
|
||||
temperature: null,
|
||||
target_temp_high: 26,
|
||||
target_temp_low: 18,
|
||||
fan_mode: "auto",
|
||||
fan_modes: ["auto", "on"],
|
||||
hvac_modes: ["auto", "cool", "heat", "off"],
|
||||
aux_heat: "off",
|
||||
actual_humidity: 30,
|
||||
fan: "on",
|
||||
operation: "fan",
|
||||
fan_min_on_time: 10,
|
||||
friendly_name: "Upstairs",
|
||||
supported_features: 27,
|
||||
preset_mode: "away",
|
||||
preset_modes: ["home", "away", "eco", "sleep"],
|
||||
},
|
||||
},
|
||||
"climate.downstairs": {
|
||||
entity_id: "climate.downstairs",
|
||||
state: "auto",
|
||||
attributes: {
|
||||
current_temperature: 22,
|
||||
min_temp: 15,
|
||||
max_temp: 30,
|
||||
temperature: null,
|
||||
target_temp_high: 24,
|
||||
target_temp_low: 20,
|
||||
fan_mode: "auto",
|
||||
fan_modes: ["auto", "on"],
|
||||
hvac_modes: ["auto", "cool", "heat", "off"],
|
||||
aux_heat: "off",
|
||||
actual_humidity: 30,
|
||||
fan: "on",
|
||||
operation: "fan",
|
||||
fan_min_on_time: 10,
|
||||
friendly_name: "Downstairs",
|
||||
supported_features: 27,
|
||||
preset_mode: "home",
|
||||
preset_modes: ["home", "away", "eco", "sleep"],
|
||||
},
|
||||
},
|
||||
});
|
93
cast/src/receiver/demo/cast-demo-lovelace.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
LovelaceConfig,
|
||||
LovelaceCardConfig,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import { castContext } from "../cast_context";
|
||||
|
||||
export const castDemoLovelace: () => LovelaceConfig = () => {
|
||||
const touchSupported = castContext.getDeviceCapabilities()
|
||||
.touch_input_supported;
|
||||
return {
|
||||
views: [
|
||||
{
|
||||
path: "overview",
|
||||
cards: [
|
||||
{
|
||||
type: "markdown",
|
||||
title: "Home Assistant Cast",
|
||||
content: `With Home Assistant you can easily create interfaces (just like this one) which can be shown on Chromecast devices connected to TVs or Google Assistant devices with a screen.${
|
||||
touchSupported
|
||||
? "\n\nYou are able to interact with this demo using the touch screen."
|
||||
: "\n\nOn a Google Nest Hub you are able to interact with Home Assistant Cast via the touch screen."
|
||||
}`,
|
||||
},
|
||||
{
|
||||
type: touchSupported ? "entities" : "glance",
|
||||
title: "Living Room",
|
||||
entities: [
|
||||
"light.reading_light",
|
||||
"light.ceiling",
|
||||
"light.standing_lamp",
|
||||
"input_number.harmonyvolume",
|
||||
],
|
||||
},
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_inside",
|
||||
},
|
||||
{
|
||||
graph: "line",
|
||||
type: "sensor",
|
||||
entity: "sensor.temperature_outside",
|
||||
},
|
||||
],
|
||||
type: "horizontal-stack",
|
||||
},
|
||||
{
|
||||
type: "map",
|
||||
entities: ["person.arsaboo", "person.melody", "zone.home"],
|
||||
aspect_ratio: touchSupported ? "16:9.3" : "16:11",
|
||||
},
|
||||
touchSupported && {
|
||||
type: "entities",
|
||||
entities: [
|
||||
{
|
||||
type: "weblink",
|
||||
url: "/lovelace/climate",
|
||||
name: "Climate controls",
|
||||
icon: "hass:arrow-right",
|
||||
},
|
||||
],
|
||||
},
|
||||
].filter(Boolean) as LovelaceCardConfig[],
|
||||
},
|
||||
{
|
||||
path: "climate",
|
||||
cards: [
|
||||
{
|
||||
type: "thermostat",
|
||||
entity: "climate.downstairs",
|
||||
},
|
||||
{
|
||||
type: "entities",
|
||||
entities: [
|
||||
{
|
||||
type: "weblink",
|
||||
url: "/lovelace/overview",
|
||||
name: "Back",
|
||||
icon: "hass:arrow-left",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: "thermostat",
|
||||
entity: "climate.upstairs",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
42
cast/src/receiver/entrypoint.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import "../../../src/resources/custom-card-support";
|
||||
import { castContext } from "./cast_context";
|
||||
import { ReceivedMessage } from "./types";
|
||||
import { HassMessage } from "../../../src/cast/receiver_messages";
|
||||
import { HcMain } from "./layout/hc-main";
|
||||
import { CAST_NS } from "../../../src/cast/const";
|
||||
|
||||
const controller = new HcMain();
|
||||
document.body.append(controller);
|
||||
|
||||
const options = new cast.framework.CastReceiverOptions();
|
||||
options.disableIdleTimeout = true;
|
||||
options.customNamespaces = {
|
||||
// @ts-ignore
|
||||
[CAST_NS]: cast.framework.system.MessageType.JSON,
|
||||
};
|
||||
|
||||
// The docs say we need to set options.touchScreenOptimizeApp = true
|
||||
// https://developers.google.com/cast/docs/caf_receiver/customize_ui#accessing_ui_controls
|
||||
// This doesn't work.
|
||||
// @ts-ignore
|
||||
options.touchScreenOptimizedApp = true;
|
||||
|
||||
// The class reference say we can set a uiConfig in options to set it
|
||||
// https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.CastReceiverOptions#uiConfig
|
||||
// This doesn't work either.
|
||||
// @ts-ignore
|
||||
options.uiConfig = new cast.framework.ui.UiConfig();
|
||||
// @ts-ignore
|
||||
options.uiConfig.touchScreenOptimizedApp = true;
|
||||
|
||||
castContext.addCustomMessageListener(
|
||||
CAST_NS,
|
||||
// @ts-ignore
|
||||
(ev: ReceivedMessage<HassMessage>) => {
|
||||
const msg = ev.data;
|
||||
msg.senderId = ev.senderId;
|
||||
controller.processIncomingMessage(msg);
|
||||
}
|
||||
);
|
||||
|
||||
castContext.start(options);
|
56
cast/src/receiver/layout/hc-demo.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { HassElement } from "../../../../src/state/hass-element";
|
||||
import "./hc-lovelace";
|
||||
import { customElement, TemplateResult, html, property } from "lit-element";
|
||||
import {
|
||||
MockHomeAssistant,
|
||||
provideHass,
|
||||
} from "../../../../src/fake_data/provide_hass";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { castDemoEntities } from "../demo/cast-demo-entities";
|
||||
import { castDemoLovelace } from "../demo/cast-demo-lovelace";
|
||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||
|
||||
@customElement("hc-demo")
|
||||
class HcDemo extends HassElement {
|
||||
@property() public lovelacePath!: string;
|
||||
@property() private _lovelaceConfig?: LovelaceConfig;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (!this._lovelaceConfig) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<hc-lovelace
|
||||
.hass=${this.hass}
|
||||
.lovelaceConfig=${this._lovelaceConfig}
|
||||
.viewPath=${this.lovelacePath}
|
||||
></hc-lovelace>
|
||||
`;
|
||||
}
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._initialize();
|
||||
}
|
||||
|
||||
private async _initialize() {
|
||||
const initial: Partial<MockHomeAssistant> = {
|
||||
// Override updateHass so that the correct hass lifecycle methods are called
|
||||
updateHass: (hassUpdate: Partial<HomeAssistant>) =>
|
||||
this._updateHass(hassUpdate),
|
||||
};
|
||||
|
||||
const hass = (this.hass = provideHass(this, initial));
|
||||
|
||||
mockHistory(hass);
|
||||
|
||||
hass.addEntities(castDemoEntities());
|
||||
this._lovelaceConfig = castDemoLovelace();
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-demo": HcDemo;
|
||||
}
|
||||
}
|
66
cast/src/receiver/layout/hc-launch-screen.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import {
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
customElement,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
|
||||
@customElement("hc-launch-screen")
|
||||
class HcLaunchScreen extends LitElement {
|
||||
@property() public hass?: HomeAssistant;
|
||||
@property() public error?: string;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
return html`
|
||||
<div class="container">
|
||||
<img
|
||||
src="https://www.home-assistant.io/images/blog/2018-09-thinking-big/social.png"
|
||||
/>
|
||||
<div class="status">
|
||||
${this.hass ? "Connected" : "Not Connected"}
|
||||
${this.error
|
||||
? html`
|
||||
<p>Error: ${this.error}</p>
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
display: block;
|
||||
height: 100vh;
|
||||
padding-top: 64px;
|
||||
background-color: white;
|
||||
font-size: 24px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
img {
|
||||
width: 717px;
|
||||
height: 376px;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.status {
|
||||
padding-right: 54px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-launch-screen": HcLaunchScreen;
|
||||
}
|
||||
}
|
119
cast/src/receiver/layout/hc-lovelace.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import {
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
html,
|
||||
customElement,
|
||||
CSSResult,
|
||||
css,
|
||||
property,
|
||||
} from "lit-element";
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import "../../../../src/panels/lovelace/views/hui-view";
|
||||
import "../../../../src/panels/lovelace/views/hui-panel-view";
|
||||
import { HomeAssistant } from "../../../../src/types";
|
||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||
import "./hc-launch-screen";
|
||||
|
||||
@customElement("hc-lovelace")
|
||||
class HcLovelace extends LitElement {
|
||||
@property() public hass!: HomeAssistant;
|
||||
|
||||
@property() public lovelaceConfig!: LovelaceConfig;
|
||||
|
||||
@property() public viewPath?: string | number;
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
const index = this._viewIndex;
|
||||
if (index === undefined) {
|
||||
return html`
|
||||
<hc-launch-screen
|
||||
.hass=${this.hass}
|
||||
.error=${`Unable to find a view with path ${this.viewPath}`}
|
||||
></hc-launch-screen>
|
||||
`;
|
||||
}
|
||||
const lovelace: Lovelace = {
|
||||
config: this.lovelaceConfig,
|
||||
editMode: false,
|
||||
enableFullEditMode: () => undefined,
|
||||
mode: "storage",
|
||||
language: "en",
|
||||
saveConfig: async () => undefined,
|
||||
deleteConfig: async () => undefined,
|
||||
setEditMode: () => undefined,
|
||||
};
|
||||
return this.lovelaceConfig.views[index].panel
|
||||
? html`
|
||||
<hui-panel-view
|
||||
.hass=${this.hass}
|
||||
.config=${this.lovelaceConfig.views[index]}
|
||||
></hui-panel-view>
|
||||
`
|
||||
: html`
|
||||
<hui-view
|
||||
.hass=${this.hass}
|
||||
.lovelace=${lovelace}
|
||||
.index=${index}
|
||||
columns="2"
|
||||
></hui-view>
|
||||
`;
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
super.updated(changedProps);
|
||||
|
||||
if (changedProps.has("viewPath") || changedProps.has("lovelaceConfig")) {
|
||||
const index = this._viewIndex;
|
||||
|
||||
if (index !== undefined) {
|
||||
const configBackground =
|
||||
this.lovelaceConfig.views[index].background ||
|
||||
this.lovelaceConfig.background;
|
||||
|
||||
if (configBackground) {
|
||||
(this.shadowRoot!.querySelector(
|
||||
"hui-view, hui-panel-view"
|
||||
) as HTMLElement)!.style.setProperty(
|
||||
"--lovelace-background",
|
||||
configBackground
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private get _viewIndex() {
|
||||
const selectedView = this.viewPath;
|
||||
const selectedViewInt = parseInt(selectedView as string, 10);
|
||||
for (let i = 0; i < this.lovelaceConfig.views.length; i++) {
|
||||
if (
|
||||
this.lovelaceConfig.views[i].path === selectedView ||
|
||||
i === selectedViewInt
|
||||
) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background: var(--primary-background-color);
|
||||
}
|
||||
:host > * {
|
||||
flex: 1;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-lovelace": HcLovelace;
|
||||
}
|
||||
}
|
250
cast/src/receiver/layout/hc-main.ts
Normal file
@@ -0,0 +1,250 @@
|
||||
import {
|
||||
getAuth,
|
||||
createConnection,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import { customElement, TemplateResult, html, property } from "lit-element";
|
||||
import { HassElement } from "../../../../src/state/hass-element";
|
||||
import {
|
||||
HassMessage,
|
||||
ConnectMessage,
|
||||
ShowLovelaceViewMessage,
|
||||
GetStatusMessage,
|
||||
ShowDemoMessage,
|
||||
} from "../../../../src/cast/receiver_messages";
|
||||
import {
|
||||
LovelaceConfig,
|
||||
getLovelaceCollection,
|
||||
} from "../../../../src/data/lovelace";
|
||||
import "./hc-launch-screen";
|
||||
import { castContext } from "../cast_context";
|
||||
import { CAST_NS } from "../../../../src/cast/const";
|
||||
import { ReceiverStatusMessage } from "../../../../src/cast/sender_messages";
|
||||
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
|
||||
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
||||
|
||||
@customElement("hc-main")
|
||||
export class HcMain extends HassElement {
|
||||
@property() private _showDemo = false;
|
||||
|
||||
@property() private _lovelaceConfig?: LovelaceConfig;
|
||||
|
||||
@property() private _lovelacePath: string | number | null = null;
|
||||
|
||||
@property() private _error?: string;
|
||||
|
||||
private _unsubLovelace?: UnsubscribeFunc;
|
||||
|
||||
public processIncomingMessage(msg: HassMessage) {
|
||||
if (msg.type === "connect") {
|
||||
this._handleConnectMessage(msg);
|
||||
} else if (msg.type === "show_lovelace_view") {
|
||||
this._handleShowLovelaceMessage(msg);
|
||||
} else if (msg.type === "get_status") {
|
||||
this._handleGetStatusMessage(msg);
|
||||
} else if (msg.type === "show_demo") {
|
||||
this._handleShowDemo(msg);
|
||||
} else {
|
||||
// tslint:disable-next-line: no-console
|
||||
console.warn("unknown msg type", msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (this._showDemo) {
|
||||
return html`
|
||||
<hc-demo .lovelacePath=${this._lovelacePath}></hc-demo>
|
||||
`;
|
||||
}
|
||||
|
||||
if (
|
||||
!this._lovelaceConfig ||
|
||||
this._lovelacePath === null ||
|
||||
// Guard against part of HA not being loaded yet.
|
||||
(this.hass &&
|
||||
(!this.hass.states || !this.hass.config || !this.hass.services))
|
||||
) {
|
||||
return html`
|
||||
<hc-launch-screen
|
||||
.hass=${this.hass}
|
||||
.error=${this._error}
|
||||
></hc-launch-screen>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<hc-lovelace
|
||||
.hass=${this.hass}
|
||||
.lovelaceConfig=${this._lovelaceConfig}
|
||||
.viewPath=${this._lovelacePath}
|
||||
></hc-lovelace>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
import("../second-load");
|
||||
window.addEventListener("location-changed", () => {
|
||||
if (location.pathname.startsWith("/lovelace/")) {
|
||||
this._lovelacePath = location.pathname.substr(10);
|
||||
this._sendStatus();
|
||||
}
|
||||
});
|
||||
document.body.addEventListener("click", (ev) => {
|
||||
const href = isNavigationClick(ev);
|
||||
if (href && href.startsWith("/lovelace/")) {
|
||||
this._lovelacePath = href.substr(10);
|
||||
this._sendStatus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _sendStatus(senderId?: string) {
|
||||
const status: ReceiverStatusMessage = {
|
||||
type: "receiver_status",
|
||||
connected: !!this.hass,
|
||||
showDemo: this._showDemo,
|
||||
};
|
||||
|
||||
if (this.hass) {
|
||||
status.hassUrl = this.hass.auth.data.hassUrl;
|
||||
status.lovelacePath = this._lovelacePath!;
|
||||
}
|
||||
|
||||
if (senderId) {
|
||||
this.sendMessage(senderId, status);
|
||||
} else {
|
||||
for (const sender of castContext.getSenders()) {
|
||||
this.sendMessage(sender.id, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _handleGetStatusMessage(msg: GetStatusMessage) {
|
||||
this._sendStatus(msg.senderId!);
|
||||
}
|
||||
|
||||
private async _handleConnectMessage(msg: ConnectMessage) {
|
||||
let auth;
|
||||
try {
|
||||
auth = await getAuth({
|
||||
loadTokens: async () => ({
|
||||
hassUrl: msg.hassUrl,
|
||||
clientId: msg.clientId,
|
||||
refresh_token: msg.refreshToken,
|
||||
access_token: "",
|
||||
expires: 0,
|
||||
expires_in: 0,
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
this._error = this._getErrorMessage(err);
|
||||
return;
|
||||
}
|
||||
let connection;
|
||||
try {
|
||||
connection = await createConnection({ auth });
|
||||
} catch (err) {
|
||||
this._error = this._getErrorMessage(err);
|
||||
return;
|
||||
}
|
||||
if (this.hass) {
|
||||
this.hass.connection.close();
|
||||
}
|
||||
this.initializeHass(auth, connection);
|
||||
this._error = undefined;
|
||||
this._sendStatus();
|
||||
}
|
||||
|
||||
private async _handleShowLovelaceMessage(msg: ShowLovelaceViewMessage) {
|
||||
// We should not get this command before we are connected.
|
||||
// Means a client got out of sync. Let's send status to them.
|
||||
if (!this.hass) {
|
||||
this._sendStatus(msg.senderId!);
|
||||
this._error = "Cannot show Lovelace because we're not connected.";
|
||||
return;
|
||||
}
|
||||
if (!this._unsubLovelace) {
|
||||
const llColl = getLovelaceCollection(this.hass!.connection);
|
||||
// We first do a single refresh because we need to check if there is LL
|
||||
// configuration.
|
||||
try {
|
||||
await llColl.refresh();
|
||||
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
||||
this._handleNewLovelaceConfig(lovelaceConfig)
|
||||
);
|
||||
} catch (err) {
|
||||
// Generate a Lovelace config.
|
||||
this._unsubLovelace = () => undefined;
|
||||
const { generateLovelaceConfigFromHass } = await import(
|
||||
"../../../../src/panels/lovelace/common/generate-lovelace-config"
|
||||
);
|
||||
this._handleNewLovelaceConfig(
|
||||
await generateLovelaceConfigFromHass(this.hass!)
|
||||
);
|
||||
}
|
||||
}
|
||||
this._showDemo = false;
|
||||
this._lovelacePath = msg.viewPath;
|
||||
if (castContext.getDeviceCapabilities().touch_input_supported) {
|
||||
this._breakFree();
|
||||
}
|
||||
this._sendStatus();
|
||||
}
|
||||
|
||||
private _handleNewLovelaceConfig(lovelaceConfig: LovelaceConfig) {
|
||||
castContext.setApplicationState(lovelaceConfig.title!);
|
||||
this._lovelaceConfig = lovelaceConfig;
|
||||
if (lovelaceConfig.resources) {
|
||||
loadLovelaceResources(
|
||||
lovelaceConfig.resources,
|
||||
this.hass!.auth.data.hassUrl
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private _handleShowDemo(_msg: ShowDemoMessage) {
|
||||
import("./hc-demo").then(() => {
|
||||
this._showDemo = true;
|
||||
this._lovelacePath = "overview";
|
||||
this._sendStatus();
|
||||
if (castContext.getDeviceCapabilities().touch_input_supported) {
|
||||
this._breakFree();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _getErrorMessage(error: number): string {
|
||||
switch (error) {
|
||||
case 1:
|
||||
return "Unable to connect to the Home Assistant websocket API.";
|
||||
case 2:
|
||||
return "The supplied authentication is invalid.";
|
||||
case 3:
|
||||
return "The connection to Home Assistant was lost.";
|
||||
case 4:
|
||||
return "Missing hassUrl. This is required.";
|
||||
case 5:
|
||||
return "Home Assistant needs to be served over https:// to use with Home Assistant Cast.";
|
||||
default:
|
||||
return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
private _breakFree() {
|
||||
const controls = document.body.querySelector("touch-controls");
|
||||
if (controls) {
|
||||
controls.remove();
|
||||
}
|
||||
document.body.setAttribute("style", "overflow-y: auto !important");
|
||||
}
|
||||
|
||||
private sendMessage(senderId: string, response: any) {
|
||||
castContext.sendCustomMessage(CAST_NS, senderId, response);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hc-main": HcMain;
|
||||
}
|
||||
}
|
5
cast/src/receiver/second-load.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import "web-animations-js/web-animations-next-lite.min";
|
||||
import "../../../src/resources/hass-icons";
|
||||
import "../../../src/resources/roboto";
|
||||
import "../../../src/components/ha-iconset-svg";
|
||||
import "./layout/hc-lovelace";
|
6
cast/src/receiver/types.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface ReceivedMessage<T> {
|
||||
gj: boolean;
|
||||
data: T;
|
||||
senderId: string;
|
||||
type: "message";
|
||||
}
|
11
cast/webpack.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const { createCastConfig } = require("../build-scripts/webpack.js");
|
||||
const { isProdBuild } = require("../build-scripts/env.js");
|
||||
|
||||
// File just used for stats builds
|
||||
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createCastConfig({
|
||||
isProdBuild,
|
||||
latestBuild,
|
||||
});
|
18
demo/public/_headers
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
Cache-Control: public, max-age: 0, s-maxage=3600, must-revalidate
|
||||
Content-Security-Policy: form-action https:
|
||||
Referrer-Policy: no-referrer-when-downgrade
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 1; mode=block
|
||||
|
||||
/api/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
||||
|
||||
/assets/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
||||
|
||||
/frontend_es5/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
||||
|
||||
/frontend_latest/*
|
||||
Cache-Control: public, max-age: 604800, s-maxage=604800
|
BIN
demo/public/assets/arsaboo/images/arsaboo.jpg
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
demo/public/assets/arsaboo/images/melody.jpg
Normal file
After Width: | Height: | Size: 36 KiB |
@@ -7,22 +7,26 @@
|
||||
{
|
||||
"src": "/static/icons/favicon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/favicon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/favicon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "/static/icons/favicon-1024x1024.png",
|
||||
"sizes": "1024x1024",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
}
|
||||
],
|
||||
"lang": "en-US",
|
||||
|
@@ -0,0 +1,3 @@
|
||||
self.addEventListener("fetch", function(event) {
|
||||
event.respondWith(fetch(event.request));
|
||||
});
|
||||
|
@@ -1,91 +1,75 @@
|
||||
import { Entity, convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||
convertEntities({
|
||||
"zone.home": {
|
||||
entity_id: "zone.home",
|
||||
state: "zoning",
|
||||
attributes: {
|
||||
hidden: true,
|
||||
latitude: 52.3631339,
|
||||
longitude: 4.8903147,
|
||||
radius: 200,
|
||||
friendly_name: "Home",
|
||||
icon: "hademo:home",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.243651+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.243651+00:00",
|
||||
context: { id: "a1b962da6bc54aad9d8e921e47c7ba87", user_id: null },
|
||||
},
|
||||
"zone.buckhead": {
|
||||
"zone.uva": {
|
||||
entity_id: "zone.buckhead",
|
||||
state: "zoning",
|
||||
attributes: {
|
||||
hidden: true,
|
||||
radius: 200,
|
||||
friendly_name: "Buckhead",
|
||||
radius: 400,
|
||||
friendly_name: "UvA",
|
||||
icon: "hademo:school",
|
||||
latitude: 52.3558182,
|
||||
longitude: 4.9535376,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.243765+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.243765+00:00",
|
||||
context: { id: "ed52190b694c458e8dc5bb733fc553ee", user_id: null },
|
||||
},
|
||||
"zone.downtown": {
|
||||
entity_id: "zone.downtown",
|
||||
state: "zoning",
|
||||
"person.arsaboo": {
|
||||
entity_id: "person.arsaboo",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
hidden: true,
|
||||
radius: 200,
|
||||
friendly_name: "Downtown",
|
||||
icon: "hademo:school",
|
||||
radius: 50,
|
||||
friendly_name: "Arsaboo",
|
||||
latitude: 52.3579946,
|
||||
longitude: 4.8664597,
|
||||
entity_picture: "/assets/arsaboo/images/arsaboo.jpg",
|
||||
},
|
||||
},
|
||||
"person.melody": {
|
||||
entity_id: "person.melody",
|
||||
state: "not_home",
|
||||
attributes: {
|
||||
radius: 50,
|
||||
friendly_name: "Melody",
|
||||
latitude: 52.3408927,
|
||||
longitude: 4.8711073,
|
||||
entity_picture: "/assets/arsaboo/images/melody.jpg",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.243873+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.243873+00:00",
|
||||
context: { id: "9114964fdecd424ca96f60cfa8864422", user_id: null },
|
||||
},
|
||||
"sensor.livingroom_temp_rounded": {
|
||||
entity_id: "sensor.livingroom_temp_rounded",
|
||||
state: "66",
|
||||
state: "21",
|
||||
attributes: {
|
||||
friendly_name: "Living room temperature",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T18:23:58.615703+00:00",
|
||||
last_updated: "2019-01-22T18:23:58.615703+00:00",
|
||||
context: { id: "d8720a928ed645838679c2b5edc5e2fd", user_id: null },
|
||||
},
|
||||
"sensor.study_temp_rounded": {
|
||||
entity_id: "sensor.study_temp_rounded",
|
||||
state: "67",
|
||||
state: "23",
|
||||
attributes: {
|
||||
friendly_name: "Study temperature",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T19:17:17.881894+00:00",
|
||||
last_updated: "2019-01-22T19:17:17.881894+00:00",
|
||||
context: { id: "9e25fd2c4032461f83df3ed778fc031e", user_id: null },
|
||||
},
|
||||
"sensor.sonos_audio_in": {
|
||||
entity_id: "sensor.sonos_audio_in",
|
||||
state: "Paused",
|
||||
attributes: {
|
||||
friendly_name: "Sonos Audio-in",
|
||||
icon: "hademo:volume-high",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:14.678332+00:00",
|
||||
last_updated: "2019-01-22T17:00:14.678332+00:00",
|
||||
context: { id: "072d120e6d584e4d88e3222196b27e4d", user_id: null },
|
||||
},
|
||||
"sensor.living_room": {
|
||||
entity_id: "sensor.living_room",
|
||||
state: "PowerOff",
|
||||
state: "YouTube",
|
||||
attributes: {
|
||||
friendly_name: "Harmony Activity",
|
||||
homebridge_hidden: true,
|
||||
friendly_name: "Harmony",
|
||||
entity_picture: "/assets/arsaboo/icons/Harmony.png",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:14.722625+00:00",
|
||||
last_updated: "2019-01-22T17:00:14.722625+00:00",
|
||||
context: { id: "8a3e097e681740cca0f82905dd9f84b6", user_id: null },
|
||||
},
|
||||
"sensor.total_tv_time": {
|
||||
entity_id: "sensor.total_tv_time",
|
||||
@@ -93,13 +77,11 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
value: "25m",
|
||||
unit_of_measurement: "h",
|
||||
friendly_name: "Total TV Time",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.total_tv_time"
|
||||
),
|
||||
icon: "hademo:chart-line",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:14.938049+00:00",
|
||||
last_updated: "2019-01-22T17:00:14.938049+00:00",
|
||||
context: { id: "22b23e84bd7d4acfb97653fbb68ad6ef", user_id: null },
|
||||
},
|
||||
"climate.upstairs": {
|
||||
entity_id: "climate.upstairs",
|
||||
@@ -112,26 +94,20 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
target_temp_high: 24,
|
||||
target_temp_low: 20,
|
||||
fan_mode: "auto",
|
||||
fan_list: ["auto", "on"],
|
||||
operation_mode: "auto",
|
||||
operation_list: ["auto", "auxHeatOnly", "cool", "heat", "off"],
|
||||
hold_mode: null,
|
||||
away_mode: "off",
|
||||
fan_modes: ["auto", "on"],
|
||||
hvac_modes: ["auto", "cool", "heat", "off"],
|
||||
aux_heat: "off",
|
||||
actual_humidity: 30,
|
||||
fan: "on",
|
||||
climate_mode: "Day",
|
||||
operation: "fan",
|
||||
climate_list: ["Away", "Sleep", "Day", "Home"],
|
||||
fan_min_on_time: 10,
|
||||
friendly_name: "Upstairs",
|
||||
supported_features: 3575,
|
||||
homebridge_hidden: true,
|
||||
entity_picture: "/assets/arsaboo/icons/Ecobee.png",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.names.upstairs"
|
||||
),
|
||||
supported_features: 27,
|
||||
preset_mode: "away",
|
||||
preset_modes: ["home", "away", "eco", "sleep"],
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.810867+00:00",
|
||||
last_updated: "2019-01-22T19:33:14.146114+00:00",
|
||||
context: { id: "211635d7bddb468d927d18cee9f795cf", user_id: null },
|
||||
},
|
||||
"input_boolean.abodeupdate": {
|
||||
entity_id: "input_boolean.abodeupdate",
|
||||
@@ -139,16 +115,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Abode Updates",
|
||||
icon: "hademo:security",
|
||||
homebridge_hidden: true,
|
||||
templates: {
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
},
|
||||
emulated_hue_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.881638+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.881638+00:00",
|
||||
context: { id: "7565c5becbca495c91550822d3284249", user_id: null },
|
||||
},
|
||||
"input_boolean.tv": {
|
||||
entity_id: "input_boolean.tv",
|
||||
@@ -156,15 +123,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
friendly_name: "TV",
|
||||
icon: "hademo:television",
|
||||
homebridge_hidden: false,
|
||||
templates: {
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
},
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.882562+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.882562+00:00",
|
||||
context: { id: "0ac79c8674b242be968d08791e6b5932", user_id: null },
|
||||
},
|
||||
"input_boolean.homeautomation": {
|
||||
entity_id: "input_boolean.homeautomation",
|
||||
@@ -172,15 +131,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Home Automation",
|
||||
icon: "hass:home-automation",
|
||||
homebridge_hidden: true,
|
||||
templates: {
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
},
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.883106+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.883106+00:00",
|
||||
context: { id: "c6eb55b9528c49f181f624b38c9e2744", user_id: null },
|
||||
},
|
||||
"input_boolean.tvtime": {
|
||||
entity_id: "input_boolean.tvtime",
|
||||
@@ -188,59 +139,46 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
friendly_name: "TV Time",
|
||||
icon: "hademo:television-guide",
|
||||
homebridge_hidden: true,
|
||||
templates: {
|
||||
icon:
|
||||
"if (state === 'on') return 'hademo:television-classic'; return 'hademo:television-classic-off';\n",
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
},
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.883309+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.883309+00:00",
|
||||
context: { id: "5fdf8af8eb214e65ade4e3aeff3dd34b", user_id: null },
|
||||
},
|
||||
"input_select.livingroomharmony": {
|
||||
entity_id: "input_select.livingroomharmony",
|
||||
state: "PowerOff",
|
||||
state: "YouTube",
|
||||
attributes: {
|
||||
options: [
|
||||
"PowerOff",
|
||||
"Watch Fire TV",
|
||||
"Youtube",
|
||||
"YouTube",
|
||||
"SATV",
|
||||
"Watch Apple TV",
|
||||
],
|
||||
friendly_name: "Harmony Activity",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.activity"
|
||||
),
|
||||
icon: "hademo:remote",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.884366+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.884366+00:00",
|
||||
context: { id: "0f58b582c976468da868054edf770f92", user_id: null },
|
||||
},
|
||||
"input_select.hdmiswitcher": {
|
||||
entity_id: "input_select.hdmiswitcher",
|
||||
state: "Shield",
|
||||
attributes: {
|
||||
options: ["AppleTV", "FireTV", "Shield"],
|
||||
friendly_name: "HDMI Switcher",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.hdmi_switcher"
|
||||
),
|
||||
icon: "hademo:remote",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.884597+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.884597+00:00",
|
||||
context: { id: "20071b60a5a84a10b48a218f1cad67e7", user_id: null },
|
||||
},
|
||||
"input_select.hdmiinput": {
|
||||
entity_id: "input_select.hdmiinput",
|
||||
state: "InputHdmi4",
|
||||
attributes: {
|
||||
options: ["InputHdmi1", "InputHdmi2", "InputHDMI3", "InputHdmi4"],
|
||||
friendly_name: "HDMI Input",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.hdmi_input"
|
||||
),
|
||||
icon: "hademo:remote",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:56.884850+00:00",
|
||||
last_updated: "2019-01-22T16:59:56.884850+00:00",
|
||||
context: { id: "d807dee60854436f81ef374ab8267bd1", user_id: null },
|
||||
},
|
||||
"input_number.harmonyvolume": {
|
||||
entity_id: "input_number.harmonyvolume",
|
||||
@@ -251,23 +189,21 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
max: 100,
|
||||
step: 1,
|
||||
mode: "slider",
|
||||
friendly_name: "Volume",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.volume"
|
||||
),
|
||||
icon: "hademo:volume-high",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:16.104666+00:00",
|
||||
last_updated: "2019-01-22T17:00:16.104666+00:00",
|
||||
context: { id: "46df627202ed4c3981ad140e06bcc578", user_id: null },
|
||||
},
|
||||
"script.tv_off": {
|
||||
entity_id: "script.tv_off",
|
||||
state: "off",
|
||||
attributes: {
|
||||
last_triggered: null,
|
||||
friendly_name: "Turn Television off",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.turn_tv_off"
|
||||
),
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.074073+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.074073+00:00",
|
||||
context: { id: "618e16fb9dba4dde9c40feda1f10bcc9", user_id: null },
|
||||
},
|
||||
"sensor.usdinr": {
|
||||
entity_id: "sensor.usdinr",
|
||||
@@ -279,11 +215,19 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
unit_of_measurement: "INR",
|
||||
friendly_name: "USDINR",
|
||||
icon: "hademo:currency-usd",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T18:25:11.582558+00:00",
|
||||
last_updated: "2019-01-22T18:25:11.582558+00:00",
|
||||
context: { id: "7737cf1420d241d8afb3f016179c133c", user_id: null },
|
||||
},
|
||||
"sensor.study_temp": {
|
||||
entity_id: "sensor.study_temp",
|
||||
state: "20.9",
|
||||
attributes: {
|
||||
unit_of_measurement: "°C",
|
||||
device_class: "temperature",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.names.temperature_study"
|
||||
),
|
||||
icon: "hademo:thermometer",
|
||||
},
|
||||
},
|
||||
"cover.garagedoor": {
|
||||
entity_id: "cover.garagedoor",
|
||||
@@ -292,27 +236,10 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
friendly_name: "Garage Door",
|
||||
icon: "hademo:garage",
|
||||
supported_features: 11,
|
||||
homebridge_hidden: false,
|
||||
homebridge_cover_type: "garage_door",
|
||||
},
|
||||
last_changed: "2019-01-22T19:31:05.399638+00:00",
|
||||
last_updated: "2019-01-22T19:31:05.399638+00:00",
|
||||
context: { id: "6ce1bded3a1c4601a4bc8e8c3823cc9f", user_id: null },
|
||||
},
|
||||
"light.master_lights": {
|
||||
entity_id: "light.master_lights",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
friendly_name: "Master Lights",
|
||||
supported_features: 63,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.423884+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.423884+00:00",
|
||||
context: { id: "b2f91c5772a346b7a24cb28386276cca", user_id: null },
|
||||
},
|
||||
|
||||
"light.living_room_lights": {
|
||||
entity_id: "light.living_room_lights",
|
||||
state: "off",
|
||||
@@ -321,22 +248,14 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
max_mireds: 400,
|
||||
friendly_name: "Living Room Lights",
|
||||
supported_features: 55,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:05.573457+00:00",
|
||||
last_updated: "2019-01-22T17:00:05.573457+00:00",
|
||||
context: { id: "bbcc2a67b73a42a280f905c5de1d120d", user_id: null },
|
||||
},
|
||||
"switch.security_armed": {
|
||||
entity_id: "switch.security_armed",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Home Security Arm",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T19:29:19.871240+00:00",
|
||||
last_updated: "2019-01-22T19:29:19.871240+00:00",
|
||||
context: { id: "2d370c236dc84c6ba4510fa9b537d926", user_id: null },
|
||||
},
|
||||
"light.kitchen_lights": {
|
||||
entity_id: "light.kitchen_lights",
|
||||
@@ -344,67 +263,16 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
attributes: {
|
||||
friendly_name: "Kitchen lights",
|
||||
supported_features: 1,
|
||||
homebridge_hidden: false,
|
||||
emulated_hue_hidden: false,
|
||||
emulated_hue_name: "Kitchen lights",
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.294651+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.294651+00:00",
|
||||
context: { id: "84a69e03a3b14de29e6753fb10889da7", user_id: null },
|
||||
},
|
||||
"light.hue_color_lamp_1": {
|
||||
entity_id: "light.hue_color_lamp_1",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
friendly_name: "Master 1",
|
||||
supported_features: 63,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.421788+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.421788+00:00",
|
||||
context: { id: "573a69eccae942d5a4b9870c3585429f", user_id: null },
|
||||
},
|
||||
"light.hue_color_lamp_2": {
|
||||
entity_id: "light.hue_color_lamp_2",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
friendly_name: "Master 2",
|
||||
supported_features: 63,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.422442+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.422442+00:00",
|
||||
context: { id: "19ae7cae5143419991ae92a7a3bda423", user_id: null },
|
||||
},
|
||||
"light.hue_color_lamp_3": {
|
||||
entity_id: "light.hue_color_lamp_3",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 153,
|
||||
max_mireds: 500,
|
||||
friendly_name: "Master 3",
|
||||
supported_features: 63,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T16:59:57.423068+00:00",
|
||||
last_updated: "2019-01-22T16:59:57.423068+00:00",
|
||||
context: { id: "75d3c44287804191bdd86b967125d7a9", user_id: null },
|
||||
},
|
||||
|
||||
"sensor.plexspy": {
|
||||
entity_id: "sensor.plexspy",
|
||||
state: "0",
|
||||
attributes: {
|
||||
unit_of_measurement: "Watching",
|
||||
friendly_name: "PlexSpy",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:00.185247+00:00",
|
||||
last_updated: "2019-01-22T17:00:00.185247+00:00",
|
||||
context: { id: "07a3c87af6c54b35914c529acf4e60bb", user_id: null },
|
||||
},
|
||||
"binary_sensor.ring_front_door_ding": {
|
||||
entity_id: "binary_sensor.ring_front_door_ding",
|
||||
@@ -416,11 +284,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
timezone: "America/New_York",
|
||||
friendly_name: "Front Door Ding",
|
||||
device_class: "occupancy",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.255653+00:00",
|
||||
last_updated: "2019-01-22T18:24:03.677589+00:00",
|
||||
context: { id: "d7508c32f2c346d5950e725b422d6695", user_id: null },
|
||||
},
|
||||
"sensor.ring_front_door_last_motion": {
|
||||
entity_id: "sensor.ring_front_door_last_motion",
|
||||
@@ -439,11 +303,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
category: "motion",
|
||||
friendly_name: "Front Door Last Motion",
|
||||
icon: "hademo:history",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T18:22:33.829681+00:00",
|
||||
last_updated: "2019-01-22T18:23:04.162733+00:00",
|
||||
context: { id: "2ca6046f7da2486988032576da8dc475", user_id: null },
|
||||
},
|
||||
"camera.patio": {
|
||||
entity_id: "camera.patio",
|
||||
@@ -457,9 +317,6 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
"/api/camera_proxy/camera.patio?token=cbd8dfac9efb441f19168e271cb8629b0372d0c1f721353394b23ed0202013b0",
|
||||
supported_features: 0,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.259908+00:00",
|
||||
last_updated: "2019-01-22T19:35:30.063163+00:00",
|
||||
context: { id: "dc4051275fa84f9ba9a6db3190d07992", user_id: null },
|
||||
},
|
||||
"camera.porch": {
|
||||
entity_id: "camera.porch",
|
||||
@@ -473,9 +330,6 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
"/api/camera_proxy/camera.porch?token=479b332e0a7cad4c58e0fb98a1ecb7942e3b225190adb93a1341edfa7daf45b0",
|
||||
supported_features: 0,
|
||||
},
|
||||
last_changed: "2019-01-22T19:32:38.491230+00:00",
|
||||
last_updated: "2019-01-22T19:35:30.064062+00:00",
|
||||
context: { id: "4f09dc684f6d4a87990c8b821cf0f49a", user_id: null },
|
||||
},
|
||||
"camera.backyard": {
|
||||
entity_id: "camera.backyard",
|
||||
@@ -489,9 +343,6 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
"/api/camera_proxy/camera.backyard?token=9381b2e4edd1bb21e868e2193f5d132a5fae153ce4f458451d979a02712b4642",
|
||||
supported_features: 0,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.261698+00:00",
|
||||
last_updated: "2019-01-22T19:35:30.064857+00:00",
|
||||
context: { id: "010e1d23a42b4218a90c43c20cffa71f", user_id: null },
|
||||
},
|
||||
"camera.driveway": {
|
||||
entity_id: "camera.driveway",
|
||||
@@ -505,22 +356,6 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
"/api/camera_proxy/camera.driveway?token=ac38bf88c2c5896eed66ae15739a3e726677f92d79e0d57f83f726ac28bda746",
|
||||
supported_features: 0,
|
||||
},
|
||||
last_changed: "2019-01-22T19:32:38.618521+00:00",
|
||||
last_updated: "2019-01-22T19:35:30.065677+00:00",
|
||||
context: { id: "ed8e123e97994bf1b3798bb7c8d7bb85", user_id: null },
|
||||
},
|
||||
"light.gateway_light_34ce00813670": {
|
||||
entity_id: "light.gateway_light_34ce00813670",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Gateway light",
|
||||
supported_features: 17,
|
||||
homebridge_hidden: true,
|
||||
emulated_hue_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.343398+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.343398+00:00",
|
||||
context: { id: "395a958263074e9eaebb582be34e46db", user_id: null },
|
||||
},
|
||||
"alarm_control_panel.abode_alarm": {
|
||||
entity_id: "alarm_control_panel.abode_alarm",
|
||||
@@ -534,12 +369,8 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
cellular_backup: false,
|
||||
friendly_name: "Abode Alarm",
|
||||
icon: "hademo:security",
|
||||
homebridge_hidden: false,
|
||||
entity_picture: "/assets/arsaboo/icons/Abode.jpg",
|
||||
},
|
||||
last_changed: "2019-01-22T19:29:19.864324+00:00",
|
||||
last_updated: "2019-01-22T19:29:19.864324+00:00",
|
||||
context: { id: "562080ae942046f0a9f0a9959bd493e8", user_id: null },
|
||||
},
|
||||
"binary_sensor.ring_front_door_motion": {
|
||||
entity_id: "binary_sensor.ring_front_door_motion",
|
||||
@@ -551,11 +382,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
timezone: "America/New_York",
|
||||
friendly_name: "Front Door Motion",
|
||||
device_class: "motion",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T18:24:14.683620+00:00",
|
||||
last_updated: "2019-01-22T18:24:14.683620+00:00",
|
||||
context: { id: "99bd1f8a0ef848b39293c846d3cf9ff4", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d00016daecc": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d00016daecc",
|
||||
@@ -565,11 +392,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
battery_level: 43,
|
||||
friendly_name: "Living Room Occupancy",
|
||||
device_class: "motion",
|
||||
homebridge_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T19:36:42.441431+00:00",
|
||||
last_updated: "2019-01-22T19:36:42.441431+00:00",
|
||||
context: { id: "95e6019573da458dac144f521517ce9f", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001bf26df": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001bf26df",
|
||||
@@ -579,11 +402,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
battery_level: 45,
|
||||
friendly_name: "Garage Entry Door",
|
||||
device_class: "door",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T19:31:03.412180+00:00",
|
||||
last_updated: "2019-01-22T19:31:03.412180+00:00",
|
||||
context: { id: "9cc9a481b6be439c93856b347402e4ac", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0001a1f2ab": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0001a1f2ab",
|
||||
@@ -593,53 +412,9 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
battery_level: 49,
|
||||
friendly_name: "Guest Room Occupancy",
|
||||
device_class: "motion",
|
||||
homebridge_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.630369+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.630369+00:00",
|
||||
context: { id: "2acd91071ed2421a81cdb862af6b03db", user_id: null },
|
||||
},
|
||||
"binary_sensor.water_leak_sensor_158d0001d77800": {
|
||||
entity_id: "binary_sensor.water_leak_sensor_158d0001d77800",
|
||||
state: "off",
|
||||
attributes: {
|
||||
battery_level: 41,
|
||||
friendly_name: "Laundry Water Leak",
|
||||
device_class: "moisture",
|
||||
homebridge_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.632708+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.632708+00:00",
|
||||
context: { id: "252f80524c284844a9e47013c0f94ada", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d00016c53bf": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d00016c53bf",
|
||||
state: "off",
|
||||
attributes: {
|
||||
"No motion since": 0,
|
||||
battery_level: 43,
|
||||
friendly_name: "Master Occupancy",
|
||||
device_class: "motion",
|
||||
homebridge_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.635223+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.635223+00:00",
|
||||
context: { id: "5c112c0a7a91492ba1d7eac30ed4ecf5", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d00016612af": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d00016612af",
|
||||
state: "off",
|
||||
attributes: {
|
||||
"No motion since": 0,
|
||||
battery_level: 41,
|
||||
friendly_name: "Upstairs Occupancy",
|
||||
device_class: "motion",
|
||||
homebridge_hidden: false,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.636514+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.636514+00:00",
|
||||
context: { id: "fe418536af56428e9e8ab3724580e631", user_id: null },
|
||||
},
|
||||
|
||||
"binary_sensor.front_door": {
|
||||
entity_id: "binary_sensor.front_door",
|
||||
state: "off",
|
||||
@@ -651,11 +426,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
device_type: "Door Contact",
|
||||
friendly_name: "Front Door",
|
||||
device_class: "door",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T19:31:27.023892+00:00",
|
||||
last_updated: "2019-01-22T19:31:27.023892+00:00",
|
||||
context: { id: "6e10573f7d7b470ea0a74f2d00475800", user_id: null },
|
||||
},
|
||||
"binary_sensor.back_door": {
|
||||
entity_id: "binary_sensor.back_door",
|
||||
@@ -668,11 +439,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
device_type: "Door Contact",
|
||||
friendly_name: "Back Door",
|
||||
device_class: "door",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:03.642051+00:00",
|
||||
last_updated: "2019-01-22T17:00:03.642051+00:00",
|
||||
context: { id: "a2e7acd74b8646d2b32e40d7a1db4cf1", user_id: null },
|
||||
},
|
||||
"media_player.family_room_2": {
|
||||
entity_id: "media_player.family_room_2",
|
||||
@@ -681,12 +448,15 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
volume_level: 0.18,
|
||||
is_volume_muted: false,
|
||||
media_content_type: "music",
|
||||
media_duration: 155,
|
||||
media_duration: 300,
|
||||
media_position: 0,
|
||||
media_position_updated_at: "2019-05-09T16:21:57.112Z",
|
||||
media_title: "Ek Ladki Ko Dekha Toh Aisa Laga - Title Track",
|
||||
media_artist: "Rochak Kohli",
|
||||
media_album_name: "Ek Ladki Ko Dekha Toh Aisa Laga",
|
||||
media_position_updated_at: new Date(
|
||||
// 23 seconds in
|
||||
new Date().getTime() - 23000
|
||||
).toISOString(),
|
||||
media_title: "I Wasn't Born To Follow",
|
||||
media_artist: "The Byrds",
|
||||
media_album_name: "The Notorious Byrd Brothers",
|
||||
source_list: [
|
||||
"Bollywood Hindi Hits",
|
||||
"Bollywood Radio and Beyond",
|
||||
@@ -704,15 +474,13 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
sonos_group: ["media_player.family_room_2"],
|
||||
night_sound: false,
|
||||
speech_enhance: false,
|
||||
friendly_name: "Family Room",
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.names.family_room"
|
||||
),
|
||||
entity_picture:
|
||||
"/api/media_player_proxy/media_player.family_room_2?token=be41a86e2a360761d67c36a010b09654b730deec092016ee92aafef79b1978ff&cache=e03d22fb103202e7",
|
||||
supported_features: 64063,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:04.802095+00:00",
|
||||
last_updated: "2019-01-22T17:00:04.802095+00:00",
|
||||
context: { id: "a4dfb3301f2149758368952e080d3247", user_id: null },
|
||||
},
|
||||
"sensor.ring_front_door_last_ding": {
|
||||
entity_id: "sensor.ring_front_door_last_ding",
|
||||
@@ -731,25 +499,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
category: "ding",
|
||||
friendly_name: "Front Door Last Ding",
|
||||
icon: "hademo:history",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:04.444969+00:00",
|
||||
last_updated: "2019-01-22T17:00:04.444969+00:00",
|
||||
context: { id: "8ae2198d1fd446f48ebdbcbb10c9bcde", user_id: null },
|
||||
},
|
||||
"light.lifxnrkitchen": {
|
||||
entity_id: "light.lifxnrkitchen",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
friendly_name: "LifxnrKitchen",
|
||||
supported_features: 55,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:05.570989+00:00",
|
||||
last_updated: "2019-01-22T17:00:05.570989+00:00",
|
||||
context: { id: "67f4c61e3a354ea99097bd5f43a88490", user_id: null },
|
||||
},
|
||||
"light.lifx5": {
|
||||
entity_id: "light.lifx5",
|
||||
@@ -759,56 +509,7 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
max_mireds: 400,
|
||||
friendly_name: "Garage lights",
|
||||
supported_features: 55,
|
||||
homebridge_hidden: false,
|
||||
emulated_hue_hidden: false,
|
||||
emulated_hue_name: "Garage Lights",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:05.580826+00:00",
|
||||
last_updated: "2019-01-22T17:00:05.580826+00:00",
|
||||
context: { id: "86f413dff85b44a491305279fa7f8939", user_id: null },
|
||||
},
|
||||
"light.lifxnrguest": {
|
||||
entity_id: "light.lifxnrguest",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
friendly_name: "LifxnrGuest",
|
||||
supported_features: 55,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:05.587119+00:00",
|
||||
last_updated: "2019-01-22T17:00:05.587119+00:00",
|
||||
context: { id: "8ee6c032fd784171a509a93c7a33197e", user_id: null },
|
||||
},
|
||||
"light.lifx3": {
|
||||
entity_id: "light.lifx3",
|
||||
state: "off",
|
||||
attributes: {
|
||||
min_mireds: 111,
|
||||
max_mireds: 400,
|
||||
friendly_name: "Lifx3",
|
||||
supported_features: 55,
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:05.587973+00:00",
|
||||
last_updated: "2019-01-22T17:00:05.587973+00:00",
|
||||
context: { id: "8ad5cc04e437477fa495ecf7de36a7b8", user_id: null },
|
||||
},
|
||||
"sensor.illumination_158d00016c53bf": {
|
||||
entity_id: "sensor.illumination_158d00016c53bf",
|
||||
state: "10",
|
||||
attributes: {
|
||||
battery_level: 43,
|
||||
unit_of_measurement: "lx",
|
||||
friendly_name: "Master Brightness",
|
||||
device_class: "illuminance",
|
||||
homebridge_hidden: true,
|
||||
icon: "hademo:brightness-7",
|
||||
},
|
||||
last_changed: "2019-01-22T19:34:01.373772+00:00",
|
||||
last_updated: "2019-01-22T19:34:01.373772+00:00",
|
||||
context: { id: "2582b7ad576746b1b3ade68adb64c878", user_id: null },
|
||||
},
|
||||
"sensor.alok_to_home": {
|
||||
entity_id: "sensor.alok_to_home",
|
||||
@@ -823,13 +524,11 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
duration: "44 mins",
|
||||
distance: "34.3 mi",
|
||||
unit_of_measurement: "min",
|
||||
friendly_name: "Commute to Home",
|
||||
homebridge_hidden: true,
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.commute_home"
|
||||
),
|
||||
icon: "hademo:car",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:15.963892+00:00",
|
||||
last_updated: "2019-01-22T17:00:15.963892+00:00",
|
||||
context: { id: "16e423e342274086b26b15de787cea3c", user_id: null },
|
||||
},
|
||||
"sensor.morning_commute": {
|
||||
entity_id: "sensor.morning_commute",
|
||||
@@ -844,74 +543,24 @@ export const demoEntitiesArsaboo: () => Entity[] = () =>
|
||||
duration: "37 mins",
|
||||
distance: "30.2 mi",
|
||||
unit_of_measurement: "min",
|
||||
friendly_name: "Morning Commute",
|
||||
homebridge_hidden: true,
|
||||
friendly_name: localize(
|
||||
"ui.panel.page-demo.config.arsaboo.labels.morning_commute"
|
||||
),
|
||||
icon: "hademo:car",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:16.142799+00:00",
|
||||
last_updated: "2019-01-22T17:00:16.142799+00:00",
|
||||
context: { id: "fc0ee1d25cc941ce9ead8a8cefdf3df9", user_id: null },
|
||||
},
|
||||
"switch.wemoswitch": {
|
||||
entity_id: "switch.wemoswitch",
|
||||
state: "on",
|
||||
attributes: { friendly_name: "WeMoSwitch", homebridge_hidden: true },
|
||||
last_changed: "2019-01-22T17:00:22.455617+00:00",
|
||||
last_updated: "2019-01-22T17:00:22.455617+00:00",
|
||||
context: { id: "d5ddc6e4c88f436ab372934934c8675e", user_id: null },
|
||||
},
|
||||
"switch.wemoinsight": {
|
||||
entity_id: "switch.wemoinsight",
|
||||
state: "off",
|
||||
attributes: {
|
||||
state_detail: "off",
|
||||
on_latest_time: "00d 00h 00m 17s",
|
||||
on_today_time: "00d 00h 00m 00s",
|
||||
on_total_time: "00d 21h 49m 35s",
|
||||
power_threshold_w: 2,
|
||||
friendly_name: "WeMoInsight",
|
||||
homebridge_hidden: true,
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:22.397783+00:00",
|
||||
last_updated: "2019-01-22T17:00:22.492778+00:00",
|
||||
context: { id: "1ff8d42d21084350acbdb6002551fc61", user_id: null },
|
||||
},
|
||||
"switch.driveway": {
|
||||
entity_id: "switch.driveway",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Driveway Light",
|
||||
homebridge_hidden: false,
|
||||
templates: {
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
icon:
|
||||
"if (state === 'on') return 'hademo:lightbulb-on'; return 'hademo:lightbulb';\n",
|
||||
},
|
||||
emulated_hue_hidden: false,
|
||||
emulated_hue_name: "Driveway Light",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:22.398939+00:00",
|
||||
last_updated: "2019-01-22T17:00:22.398939+00:00",
|
||||
context: { id: "422aaa88552048fba49ad02c698d878e", user_id: null },
|
||||
},
|
||||
"switch.wemoporch": {
|
||||
entity_id: "switch.wemoporch",
|
||||
state: "off",
|
||||
attributes: {
|
||||
friendly_name: "Porch Lights",
|
||||
homebridge_hidden: false,
|
||||
templates: {
|
||||
icon_color:
|
||||
"if (state === 'on') return 'rgb(251, 210, 41)'; return 'rgb(54, 95, 140)';\n",
|
||||
icon:
|
||||
"if (state === 'on') return 'hademo:lightbulb-on'; return 'hademo:lightbulb';\n",
|
||||
},
|
||||
emulated_hue_hidden: false,
|
||||
emulated_hue_name: "Porch Lights",
|
||||
},
|
||||
last_changed: "2019-01-22T17:00:22.435345+00:00",
|
||||
last_updated: "2019-01-22T17:00:22.435345+00:00",
|
||||
context: { id: "fdbe1a67cfc64adc8bfafeb84bcd12ad", user_id: null },
|
||||
},
|
||||
});
|
||||
|
@@ -3,10 +3,22 @@ import { Lovelace } from "../../../src/panels/lovelace/types";
|
||||
import { DemoConfig } from "./types";
|
||||
|
||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
||||
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||
() => import("./jimpower").then((mod) => mod.demoJimpower),
|
||||
() =>
|
||||
import(/* webpackChunkName: "arsaboo" */ "./arsaboo").then(
|
||||
(mod) => mod.demoArsaboo
|
||||
),
|
||||
() =>
|
||||
import(/* webpackChunkName: "teachingbirds" */ "./teachingbirds").then(
|
||||
(mod) => mod.demoTeachingbirds
|
||||
),
|
||||
() =>
|
||||
import(/* webpackChunkName: "kernehed" */ "./kernehed").then(
|
||||
(mod) => mod.demoKernehed
|
||||
),
|
||||
() =>
|
||||
import(/* webpackChunkName: "jimpower" */ "./jimpower").then(
|
||||
(mod) => mod.demoJimpower
|
||||
),
|
||||
];
|
||||
|
||||
export let selectedDemoConfigIndex: number = 0;
|
||||
@@ -25,7 +37,7 @@ export const setDemoConfig = async (
|
||||
selectedDemoConfigIndex = index;
|
||||
selectedDemoConfig = confProm;
|
||||
|
||||
hass.addEntities(config.entities(), true);
|
||||
lovelace.saveConfig(config.lovelace());
|
||||
hass.addEntities(config.entities(hass.localize), true);
|
||||
lovelace.saveConfig(config.lovelace(hass.localize));
|
||||
hass.mockTheme(config.theme());
|
||||
};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Entity, convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
export const demoEntitiesJimpower: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
"zone.powertec": {
|
||||
entity_id: "zone.powertec",
|
||||
@@ -11,9 +12,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Powertec",
|
||||
icon: "mdi:briefcase",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.430813+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.430813+00:00",
|
||||
context: { id: "c1120d64a06142dab9d7c34fd7d937e6", user_id: null },
|
||||
},
|
||||
"zone.kindy": {
|
||||
entity_id: "zone.kindy",
|
||||
@@ -24,9 +22,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Kindy",
|
||||
icon: "mdi:school",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.430969+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.430969+00:00",
|
||||
context: { id: "a4218f348e5f4a7cbdfdd25874d10570", user_id: null },
|
||||
},
|
||||
"zone.stocklands": {
|
||||
entity_id: "zone.stocklands",
|
||||
@@ -37,9 +32,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Stocklands",
|
||||
icon: "mdi:cart",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431095+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431095+00:00",
|
||||
context: { id: "689e63e51bd44de5bd93087c82cfa984", user_id: null },
|
||||
},
|
||||
"zone.parlour": {
|
||||
entity_id: "zone.parlour",
|
||||
@@ -50,9 +42,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Parlour",
|
||||
icon: "mdi:coffee",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431219+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431219+00:00",
|
||||
context: { id: "fd7e2e644cc54f368bc4d7105fc504a4", user_id: null },
|
||||
},
|
||||
"zone.work_home_beacon_25mins": {
|
||||
entity_id: "zone.work_home_beacon_25mins",
|
||||
@@ -63,9 +52,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Work Home Beacon 25mins",
|
||||
icon: "mdi:car",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431340+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431340+00:00",
|
||||
context: { id: "3dd3290258974c57a20d847905ac4035", user_id: null },
|
||||
},
|
||||
"zone.work_home_beacon_15mins": {
|
||||
entity_id: "zone.work_home_beacon_15mins",
|
||||
@@ -76,9 +62,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Work Home Beacon 15mins",
|
||||
icon: "mdi:car",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431463+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431463+00:00",
|
||||
context: { id: "a46b76ccc3ed4e19b32ed0ae1487e0c3", user_id: null },
|
||||
},
|
||||
"zone.work_home_beacon_5mins": {
|
||||
entity_id: "zone.work_home_beacon_5mins",
|
||||
@@ -89,9 +72,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Work Home Beacon 5mins",
|
||||
icon: "mdi:car",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431585+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431585+00:00",
|
||||
context: { id: "4059a802ae224f4e83d7f22f5946f6fb", user_id: null },
|
||||
},
|
||||
"zone.darwin": {
|
||||
entity_id: "zone.darwin",
|
||||
@@ -102,9 +82,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Darwin",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431704+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431704+00:00",
|
||||
context: { id: "d1b9cc62453e48d78fac4de7eceac848", user_id: null },
|
||||
},
|
||||
"zone.brisbane": {
|
||||
entity_id: "zone.brisbane",
|
||||
@@ -115,9 +92,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Brisbane",
|
||||
icon: "mdi:car",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.431821+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.431821+00:00",
|
||||
context: { id: "db90c5f4e13240dfb028265f2a0c6ab2", user_id: null },
|
||||
},
|
||||
"zone.sydney": {
|
||||
entity_id: "zone.sydney",
|
||||
@@ -128,9 +102,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Sydney",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.432543+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.432543+00:00",
|
||||
context: { id: "b558af0f406241f2b5e0338eec3e34a8", user_id: null },
|
||||
},
|
||||
"zone.melbourne": {
|
||||
entity_id: "zone.melbourne",
|
||||
@@ -141,9 +112,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Melbourne",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.432673+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.432673+00:00",
|
||||
context: { id: "b864ec85733e46949bc9b20bb1d4fa46", user_id: null },
|
||||
},
|
||||
"zone.perth": {
|
||||
entity_id: "zone.perth",
|
||||
@@ -154,9 +122,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Perth",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.432794+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.432794+00:00",
|
||||
context: { id: "d450738483f74e2194c7d52dc540cc70", user_id: null },
|
||||
},
|
||||
"zone.adelaide": {
|
||||
entity_id: "zone.adelaide",
|
||||
@@ -167,9 +132,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Adelaide",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.432912+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.432912+00:00",
|
||||
context: { id: "9964d216d1e841c88f7c847d21cdaeac", user_id: null },
|
||||
},
|
||||
"zone.tasmania": {
|
||||
entity_id: "zone.tasmania",
|
||||
@@ -180,9 +142,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Tasmania",
|
||||
icon: "mdi:airplane",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433033+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433033+00:00",
|
||||
context: { id: "097127a6a4c1420dbb7f714cdb47769b", user_id: null },
|
||||
},
|
||||
"zone.uk": {
|
||||
entity_id: "zone.uk",
|
||||
@@ -193,9 +152,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "UK",
|
||||
icon: "mdi:earth",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433150+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433150+00:00",
|
||||
context: { id: "dff58ae59b9048ecbdded5dbdfc8edc8", user_id: null },
|
||||
},
|
||||
"zone.france": {
|
||||
entity_id: "zone.france",
|
||||
@@ -206,9 +162,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "France",
|
||||
icon: "mdi:earth",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433279+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433279+00:00",
|
||||
context: { id: "f0dbc9fe806a452481080de7df6e8b06", user_id: null },
|
||||
},
|
||||
"zone.netherlands": {
|
||||
entity_id: "zone.netherlands",
|
||||
@@ -219,9 +172,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Netherlands",
|
||||
icon: "mdi:earth",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433395+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433395+00:00",
|
||||
context: { id: "4d59ecf66b434bb48fa116e9e263617f", user_id: null },
|
||||
},
|
||||
"zone.switzerland": {
|
||||
entity_id: "zone.switzerland",
|
||||
@@ -232,9 +182,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Switzerland",
|
||||
icon: "mdi:earth",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433511+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433511+00:00",
|
||||
context: { id: "eaf56c63c2fa4b64bc2d9f57c299fd4e", user_id: null },
|
||||
},
|
||||
"zone.italy": {
|
||||
entity_id: "zone.italy",
|
||||
@@ -245,9 +192,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Italy",
|
||||
icon: "mdi:earth",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433628+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433628+00:00",
|
||||
context: { id: "8d2af1ca5e064a9a859261375357420f", user_id: null },
|
||||
},
|
||||
"zone.home": {
|
||||
entity_id: "zone.home",
|
||||
@@ -258,9 +202,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Kingia Castle",
|
||||
icon: "mdi:home",
|
||||
},
|
||||
last_changed: "2019-01-14T08:56:59.433746+00:00",
|
||||
last_updated: "2019-01-14T08:56:59.433746+00:00",
|
||||
context: { id: "87c9fa771f9943bd9b91957e2fd2bb17", user_id: null },
|
||||
},
|
||||
"sensor.lower_temperature": {
|
||||
entity_id: "sensor.lower_temperature",
|
||||
@@ -275,9 +216,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Downstairs Temperature",
|
||||
icon: "mdi:sofa",
|
||||
},
|
||||
last_changed: "2019-01-18T19:27:15.224071+00:00",
|
||||
last_updated: "2019-01-18T19:27:15.224071+00:00",
|
||||
context: { id: "d2efd90df9214a55b2fb52d3d547af54", user_id: null },
|
||||
},
|
||||
"sensor.upstairs_temperature": {
|
||||
entity_id: "sensor.upstairs_temperature",
|
||||
@@ -292,9 +230,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Upstairs Temperature",
|
||||
icon: "mdi:hotel",
|
||||
},
|
||||
last_changed: "2019-01-18T19:23:10.307890+00:00",
|
||||
last_updated: "2019-01-18T19:23:10.307890+00:00",
|
||||
context: { id: "aeead40329e14918a5f4024f57a4b8ba", user_id: null },
|
||||
},
|
||||
"sensor.next_bus": {
|
||||
entity_id: "sensor.next_bus",
|
||||
@@ -304,9 +239,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Time to Next Bus",
|
||||
icon: "mdi:bus-clock",
|
||||
},
|
||||
last_changed: "2019-01-18T19:28:01.035644+00:00",
|
||||
last_updated: "2019-01-18T19:28:01.035644+00:00",
|
||||
context: { id: "4aa5848850ae44e48c1159bc1ba48e9c", user_id: null },
|
||||
},
|
||||
"sensor.battery_tina": {
|
||||
entity_id: "sensor.battery_tina",
|
||||
@@ -317,9 +249,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:battery-charging",
|
||||
device_class: "battery",
|
||||
},
|
||||
last_changed: "2019-01-18T19:26:45.464947+00:00",
|
||||
last_updated: "2019-01-18T19:26:45.464947+00:00",
|
||||
context: { id: "1d657ffd7bb344b8bf06ff22836bdba6", user_id: null },
|
||||
},
|
||||
"sensor.battery_james": {
|
||||
entity_id: "sensor.battery_james",
|
||||
@@ -330,9 +259,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "",
|
||||
device_class: "battery",
|
||||
},
|
||||
last_changed: "2019-01-18T12:17:52.040153+00:00",
|
||||
last_updated: "2019-01-18T18:58:35.848089+00:00",
|
||||
context: { id: "81f5a90f05e24d3795e2e99c80b4ce15", user_id: null },
|
||||
},
|
||||
"sensor.james": {
|
||||
entity_id: "sensor.james",
|
||||
@@ -342,9 +268,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:walk",
|
||||
entity_picture: "/local/james.jpg",
|
||||
},
|
||||
last_changed: "2019-01-18T06:31:24.315507+00:00",
|
||||
last_updated: "2019-01-18T06:31:24.315507+00:00",
|
||||
context: { id: "e24c5331fdca4055829f5905f9006377", user_id: null },
|
||||
},
|
||||
"sensor.tina": {
|
||||
entity_id: "sensor.tina",
|
||||
@@ -354,17 +277,11 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:walk",
|
||||
entity_picture: "/local/tina.jpg",
|
||||
},
|
||||
last_changed: "2019-01-18T03:12:11.415222+00:00",
|
||||
last_updated: "2019-01-18T03:12:11.415222+00:00",
|
||||
context: { id: "97c677519d2c41258e09754742b1a661", user_id: null },
|
||||
},
|
||||
"sensor.aqi": {
|
||||
entity_id: "sensor.aqi",
|
||||
state: "20",
|
||||
attributes: { friendly_name: "Air Quality Index" },
|
||||
last_changed: "2019-01-18T18:57:27.696759+00:00",
|
||||
last_updated: "2019-01-18T18:57:27.696759+00:00",
|
||||
context: { id: "96a025a4d52849efbe53b4790ab0584d", user_id: null },
|
||||
},
|
||||
"sensor.bom_temp": {
|
||||
entity_id: "sensor.bom_temp",
|
||||
@@ -374,97 +291,61 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Gold Coast Temperature",
|
||||
device_class: "temperature",
|
||||
},
|
||||
last_changed: "2019-01-18T19:05:22.110622+00:00",
|
||||
last_updated: "2019-01-18T19:05:22.110622+00:00",
|
||||
context: { id: "a793308a4653496fa5676fe42725d7b7", user_id: null },
|
||||
},
|
||||
"sensor.forks": {
|
||||
entity_id: "sensor.forks",
|
||||
state: "32",
|
||||
attributes: { friendly_name: "forks" },
|
||||
last_changed: "2019-01-17T01:58:06.790553+00:00",
|
||||
last_updated: "2019-01-17T01:58:06.790553+00:00",
|
||||
context: { id: "06af241838484b9596881681be5a4012", user_id: null },
|
||||
},
|
||||
"sensor.stars_last_week": {
|
||||
entity_id: "sensor.stars_last_week",
|
||||
state: "0",
|
||||
attributes: { friendly_name: "Last Week" },
|
||||
last_changed: "2019-01-14T08:58:04.014555+00:00",
|
||||
last_updated: "2019-01-14T08:58:04.014555+00:00",
|
||||
context: { id: "4aa610a907e849efa8b32a78e807fce3", user_id: null },
|
||||
},
|
||||
"sensor.issues": {
|
||||
entity_id: "sensor.issues",
|
||||
state: "26",
|
||||
attributes: { friendly_name: "issues" },
|
||||
last_changed: "2019-01-16T07:57:51.055084+00:00",
|
||||
last_updated: "2019-01-16T07:57:51.055084+00:00",
|
||||
context: { id: "8cb53830772549eface4d8737b3f766f", user_id: null },
|
||||
},
|
||||
"sensor.stars": {
|
||||
entity_id: "sensor.stars",
|
||||
state: "282",
|
||||
attributes: { friendly_name: "stars" },
|
||||
last_changed: "2019-01-16T21:58:01.522658+00:00",
|
||||
last_updated: "2019-01-16T21:58:01.522658+00:00",
|
||||
context: { id: "6943e39111ea49629262802740195c3d", user_id: null },
|
||||
},
|
||||
"sensor.stars_this_month": {
|
||||
entity_id: "sensor.stars_this_month",
|
||||
state: "12",
|
||||
attributes: { friendly_name: "This Month" },
|
||||
last_changed: "2019-01-16T21:58:01.559398+00:00",
|
||||
last_updated: "2019-01-16T21:58:01.559398+00:00",
|
||||
context: { id: "e6ddf5e4348842c2966bac17d82930fd", user_id: null },
|
||||
},
|
||||
"sensor.stars_last_month": {
|
||||
entity_id: "sensor.stars_last_month",
|
||||
state: "0",
|
||||
attributes: { friendly_name: "Last Month" },
|
||||
last_changed: "2019-01-14T08:58:04.022654+00:00",
|
||||
last_updated: "2019-01-14T08:58:04.022654+00:00",
|
||||
context: { id: "0cf396f4f5b34243824b3c8221017ddf", user_id: null },
|
||||
},
|
||||
"sensor.git_stars_next_dif": {
|
||||
entity_id: "sensor.git_stars_next_dif",
|
||||
state: "45",
|
||||
attributes: { friendly_name: "Next Target" },
|
||||
last_changed: "2019-01-18T08:58:36.490901+00:00",
|
||||
last_updated: "2019-01-18T08:58:36.490901+00:00",
|
||||
context: { id: "78c815150be545ab9d515988ac537f06", user_id: null },
|
||||
},
|
||||
"sensor.git_stars_last_dif": {
|
||||
entity_id: "sensor.git_stars_last_dif",
|
||||
state: "31",
|
||||
attributes: { friendly_name: "Next Target" },
|
||||
last_changed: "2019-01-17T21:58:23.379460+00:00",
|
||||
last_updated: "2019-01-17T21:58:23.379460+00:00",
|
||||
context: { id: "6dd2104a5e86400ebc9c448fe8557574", user_id: null },
|
||||
},
|
||||
"sensor.subscribers": {
|
||||
entity_id: "sensor.subscribers",
|
||||
state: "32",
|
||||
attributes: { friendly_name: "subscribers" },
|
||||
last_changed: "2019-01-15T12:57:30.802676+00:00",
|
||||
last_updated: "2019-01-15T12:57:30.802676+00:00",
|
||||
context: { id: "17585750a5cb4a4db64bcae7d52d8899", user_id: null },
|
||||
},
|
||||
"sensor.stars_this_week": {
|
||||
entity_id: "sensor.stars_this_week",
|
||||
state: "12",
|
||||
attributes: { friendly_name: "This Week" },
|
||||
last_changed: "2019-01-16T21:58:01.556195+00:00",
|
||||
last_updated: "2019-01-16T21:58:01.556195+00:00",
|
||||
context: { id: "aa97170544654051860768b744d7b748", user_id: null },
|
||||
},
|
||||
"sensor.git_stars_trend_dif": {
|
||||
entity_id: "sensor.git_stars_trend_dif",
|
||||
state: "1486",
|
||||
attributes: { friendly_name: "Trending Target" },
|
||||
last_changed: "2019-01-17T17:58:22.314538+00:00",
|
||||
last_updated: "2019-01-17T17:58:22.314538+00:00",
|
||||
context: { id: "35d95c7dc5c543dab6e9c808f62b711c", user_id: null },
|
||||
},
|
||||
"binary_sensor.james_bag_status": {
|
||||
entity_id: "binary_sensor.james_bag_status",
|
||||
@@ -474,9 +355,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:briefcase",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T21:12:17.037576+00:00",
|
||||
last_updated: "2019-01-14T21:12:17.037576+00:00",
|
||||
context: { id: "f5c6084b5e9c4d6e9e0734a4a6dbd85e", user_id: null },
|
||||
},
|
||||
"binary_sensor.tina_gps_status": {
|
||||
entity_id: "binary_sensor.tina_gps_status",
|
||||
@@ -486,9 +364,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:crosshairs-gps",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-18T03:12:11.391690+00:00",
|
||||
last_updated: "2019-01-18T03:12:11.391690+00:00",
|
||||
context: { id: "4940a85adbb24fbd8472f4b647a4372f", user_id: null },
|
||||
},
|
||||
"binary_sensor.tina_ble_status": {
|
||||
entity_id: "binary_sensor.tina_ble_status",
|
||||
@@ -498,9 +373,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:bluetooth-audio",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T08:58:04.037535+00:00",
|
||||
last_updated: "2019-01-14T08:58:04.037535+00:00",
|
||||
context: { id: "5c4a4e92e0ab4d1898783feeb895e12a", user_id: null },
|
||||
},
|
||||
"binary_sensor.james_car_status": {
|
||||
entity_id: "binary_sensor.james_car_status",
|
||||
@@ -510,9 +382,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:car-side",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T21:11:24.613784+00:00",
|
||||
last_updated: "2019-01-14T21:11:24.613784+00:00",
|
||||
context: { id: "e808b25e595346fcb06a365ee1fd49ff", user_id: null },
|
||||
},
|
||||
"binary_sensor.james_ble_status": {
|
||||
entity_id: "binary_sensor.james_ble_status",
|
||||
@@ -522,9 +391,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:bluetooth-audio",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T20:45:44.607734+00:00",
|
||||
last_updated: "2019-01-14T20:45:44.607734+00:00",
|
||||
context: { id: "9663630a8bd24ee3a269bb6e7d4ab024", user_id: null },
|
||||
},
|
||||
"binary_sensor.tina_keys_status": {
|
||||
entity_id: "binary_sensor.tina_keys_status",
|
||||
@@ -534,9 +400,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:key",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T08:58:04.041286+00:00",
|
||||
last_updated: "2019-01-14T08:58:04.041286+00:00",
|
||||
context: { id: "48d44191df8841f5bc2f4d148db269c1", user_id: null },
|
||||
},
|
||||
"binary_sensor.james_keys_status": {
|
||||
entity_id: "binary_sensor.james_keys_status",
|
||||
@@ -546,9 +409,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:key",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-14T21:11:07.377711+00:00",
|
||||
last_updated: "2019-01-14T21:11:07.377711+00:00",
|
||||
context: { id: "a965c2cf10b54e328a75db3de2833a02", user_id: null },
|
||||
},
|
||||
"binary_sensor.james_gps_status": {
|
||||
entity_id: "binary_sensor.james_gps_status",
|
||||
@@ -558,9 +418,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:crosshairs-gps",
|
||||
device_class: "connectivity",
|
||||
},
|
||||
last_changed: "2019-01-18T06:31:24.293839+00:00",
|
||||
last_updated: "2019-01-18T06:31:24.293839+00:00",
|
||||
context: { id: "800d6eef0ce141448c9f576ee43c0672", user_id: null },
|
||||
},
|
||||
"binary_sensor.garage": {
|
||||
entity_id: "binary_sensor.garage",
|
||||
@@ -570,33 +427,21 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:garage",
|
||||
device_class: "door",
|
||||
},
|
||||
last_changed: "2019-01-18T05:32:29.053625+00:00",
|
||||
last_updated: "2019-01-18T05:32:29.053625+00:00",
|
||||
context: { id: "bf35d862a2214198a0f7a945eabf36d2", user_id: null },
|
||||
},
|
||||
"binary_sensor.recycle": {
|
||||
entity_id: "binary_sensor.recycle",
|
||||
state: "off",
|
||||
attributes: { friendly_name: "Recycle", icon: "mdi:recycle" },
|
||||
last_changed: "2019-01-14T08:57:00.348349+00:00",
|
||||
last_updated: "2019-01-14T08:58:04.463267+00:00",
|
||||
context: { id: "76ef24942b0b4822bde851fc9e5e1b37", user_id: null },
|
||||
},
|
||||
"binary_sensor.trash": {
|
||||
entity_id: "binary_sensor.trash",
|
||||
state: "off",
|
||||
attributes: { friendly_name: "Trash", icon: "mdi:delete" },
|
||||
last_changed: "2019-01-15T14:00:01.040666+00:00",
|
||||
last_updated: "2019-01-15T14:00:01.040666+00:00",
|
||||
context: { id: "7bb9aaeb1b6b41e3be746e200a452318", user_id: null },
|
||||
},
|
||||
"binary_sensor.alarm": {
|
||||
entity_id: "binary_sensor.alarm",
|
||||
state: "off",
|
||||
attributes: { friendly_name: "Alarm", icon: "mdi:security-home" },
|
||||
last_changed: "2019-01-14T08:57:00.349685+00:00",
|
||||
last_updated: "2019-01-18T11:17:13.014318+00:00",
|
||||
context: { id: "16fd03ae798d4abc8d3ca6189b9a9e19", user_id: null },
|
||||
},
|
||||
"binary_sensor.windows": {
|
||||
entity_id: "binary_sensor.windows",
|
||||
@@ -606,9 +451,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:window-open",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-18T09:04:17.995330+00:00",
|
||||
last_updated: "2019-01-18T09:04:17.995330+00:00",
|
||||
context: { id: "38e6c51af4a643a1aaffacc473459d66", user_id: null },
|
||||
},
|
||||
"binary_sensor.doors": {
|
||||
entity_id: "binary_sensor.doors",
|
||||
@@ -618,9 +460,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:door-closed",
|
||||
device_class: "door",
|
||||
},
|
||||
last_changed: "2019-01-18T19:17:16.499271+00:00",
|
||||
last_updated: "2019-01-18T19:17:16.499271+00:00",
|
||||
context: { id: "debe9843a732402bb62f8ee16e47fe26", user_id: null },
|
||||
},
|
||||
"binary_sensor.lights": {
|
||||
entity_id: "binary_sensor.lights",
|
||||
@@ -630,9 +469,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
icon: "mdi:lightbulb",
|
||||
device_class: "light",
|
||||
},
|
||||
last_changed: "2019-01-18T18:59:16.225881+00:00",
|
||||
last_updated: "2019-01-18T18:59:16.225881+00:00",
|
||||
context: { id: "d4895a1468b34208b62a33c403ee049e", user_id: null },
|
||||
},
|
||||
"alarm_control_panel.ha_alarm": {
|
||||
entity_id: "alarm_control_panel.ha_alarm",
|
||||
@@ -643,12 +479,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "HA Alarm",
|
||||
icon: "mdi:security-home",
|
||||
},
|
||||
last_changed: "2019-01-18T18:59:16.103038+00:00",
|
||||
last_updated: "2019-01-18T18:59:16.103038+00:00",
|
||||
context: {
|
||||
id: "c4e3fa0f7f29431087bcef1a6f55fc3b",
|
||||
user_id: "c6d308d516b841e68b14427624fd13e0",
|
||||
},
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001e73c09": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001e73c09",
|
||||
@@ -659,9 +489,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Back Door Sensor",
|
||||
device_class: "door",
|
||||
},
|
||||
last_changed: "2019-01-18T19:17:16.489053+00:00",
|
||||
last_updated: "2019-01-18T19:17:16.489053+00:00",
|
||||
context: { id: "8ddde2fbee0f4dacaed736752d30da79", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001e73af4": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001e73af4",
|
||||
@@ -672,9 +499,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Kitchen Window",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-14T08:57:08.943587+00:00",
|
||||
last_updated: "2019-01-18T04:42:35.215550+00:00",
|
||||
context: { id: "6013ffc2e9c446319d1fca6795138a20", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d00022c2f21": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d00022c2f21",
|
||||
@@ -685,9 +509,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Staircase Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:28:25.428449+00:00",
|
||||
last_updated: "2019-01-18T19:28:25.428449+00:00",
|
||||
context: { id: "c1236d8e2b3c4e5eb1c08f8b68996f3e", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001e73a73": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001e73a73",
|
||||
@@ -698,9 +519,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Jackson Window",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-17T10:24:42.962509+00:00",
|
||||
last_updated: "2019-01-17T10:24:42.962509+00:00",
|
||||
context: { id: "19262eecf0d746c89c992350ea3187bf", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d000201351c": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d000201351c",
|
||||
@@ -711,9 +529,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Jackson Room Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:26:18.055694+00:00",
|
||||
last_updated: "2019-01-18T19:28:11.133616+00:00",
|
||||
context: { id: "aed85caae799477ab769c878d2fc3aa0", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001e73aad": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001e73aad",
|
||||
@@ -724,9 +539,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Hudson Window",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-18T05:29:44.504900+00:00",
|
||||
last_updated: "2019-01-18T05:29:44.504900+00:00",
|
||||
context: { id: "72facb8dbed94e978cfcd6ad60da21e7", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0002006d46": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0002006d46",
|
||||
@@ -737,9 +549,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Hudson Room Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:27:20.044976+00:00",
|
||||
last_updated: "2019-01-18T19:28:01.700029+00:00",
|
||||
context: { id: "121952f287dc41868870891690b7ab18", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001e74875": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001e74875",
|
||||
@@ -750,9 +559,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Bathroom Window",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-18T09:04:17.963573+00:00",
|
||||
last_updated: "2019-01-18T16:07:38.652287+00:00",
|
||||
context: { id: "83ce1b87de414a23a1223d3721712b15", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d000200e4ab": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d000200e4ab",
|
||||
@@ -763,9 +569,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Bathroom Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T17:04:51.065363+00:00",
|
||||
last_updated: "2019-01-18T17:33:37.358909+00:00",
|
||||
context: { id: "bb4d6ec2c1634194a843b93cc64474a2", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0001e5d118": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0001e5d118",
|
||||
@@ -776,9 +579,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Living Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:28:32.639483+00:00",
|
||||
last_updated: "2019-01-18T19:28:32.639483+00:00",
|
||||
context: { id: "19858190bb284f9280cc521ee5ea7a08", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0001e63803": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0001e63803",
|
||||
@@ -789,9 +589,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Bedroom Motion Densor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:27:20.031506+00:00",
|
||||
last_updated: "2019-01-18T19:28:05.990986+00:00",
|
||||
context: { id: "3907daecb7fe49638b3d4dcbf716050a", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d0001f36741": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d0001f36741",
|
||||
@@ -802,9 +599,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Bedroom Window",
|
||||
device_class: "window",
|
||||
},
|
||||
last_changed: "2019-01-18T09:36:45.480842+00:00",
|
||||
last_updated: "2019-01-18T09:41:44.724656+00:00",
|
||||
context: { id: "52bfda25d7fe4945a07c1b667909afde", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d000200ea5b": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d000200ea5b",
|
||||
@@ -815,9 +609,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Patio Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:02:44.124615+00:00",
|
||||
last_updated: "2019-01-18T19:20:41.377013+00:00",
|
||||
context: { id: "bd79ecfe99884ecfaff483569412332a", user_id: null },
|
||||
},
|
||||
"binary_sensor.water_leak_sensor_158d00026e26dc": {
|
||||
entity_id: "binary_sensor.water_leak_sensor_158d00026e26dc",
|
||||
@@ -827,9 +618,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Kitchen Leak Sensor",
|
||||
device_class: "moisture",
|
||||
},
|
||||
last_changed: "2019-01-14T08:57:08.966446+00:00",
|
||||
last_updated: "2019-01-15T21:46:47.375891+00:00",
|
||||
context: { id: "f4bfeb155fed4da5a84911c8e4f382b9", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d000225432d": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d000225432d",
|
||||
@@ -840,9 +628,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Patio Door Sensor",
|
||||
device_class: "door",
|
||||
},
|
||||
last_changed: "2019-01-18T11:08:54.826953+00:00",
|
||||
last_updated: "2019-01-18T11:08:54.826953+00:00",
|
||||
context: { id: "3be61e6b08df4539bb5be17c46c57eb2", user_id: null },
|
||||
},
|
||||
"binary_sensor.door_window_sensor_158d00022016b2": {
|
||||
entity_id: "binary_sensor.door_window_sensor_158d00022016b2",
|
||||
@@ -853,9 +638,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Front Door Sensor",
|
||||
device_class: "door",
|
||||
},
|
||||
last_changed: "2019-01-18T11:15:37.170616+00:00",
|
||||
last_updated: "2019-01-18T11:15:37.170616+00:00",
|
||||
context: { id: "18dee29b96d9475587974e9fe23b041b", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0001e5d147": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0001e5d147",
|
||||
@@ -866,9 +648,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Entrance Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T11:17:30.719455+00:00",
|
||||
last_updated: "2019-01-18T11:45:26.680090+00:00",
|
||||
context: { id: "de0b26c1d7494de8a5af973e6f098d7c", user_id: null },
|
||||
},
|
||||
"binary_sensor.smoke_sensor_158d0001b8ddc7": {
|
||||
entity_id: "binary_sensor.smoke_sensor_158d0001b8ddc7",
|
||||
@@ -879,9 +658,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Downstairs Smoke Detector",
|
||||
device_class: "smoke",
|
||||
},
|
||||
last_changed: "2019-01-14T08:57:08.972973+00:00",
|
||||
last_updated: "2019-01-14T08:57:08.972973+00:00",
|
||||
context: { id: "55a958822b534c8ea67f2def2380c0c2", user_id: null },
|
||||
},
|
||||
"binary_sensor.smoke_sensor_158d0001b8deba": {
|
||||
entity_id: "binary_sensor.smoke_sensor_158d0001b8deba",
|
||||
@@ -892,9 +668,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Upstairs Smoke Detector",
|
||||
device_class: "smoke",
|
||||
},
|
||||
last_changed: "2019-01-14T08:57:08.973800+00:00",
|
||||
last_updated: "2019-01-14T08:57:08.973800+00:00",
|
||||
context: { id: "a4df1a6a2fcd431f9fc374562317f43a", user_id: null },
|
||||
},
|
||||
"binary_sensor.motion_sensor_158d0001e5cf11": {
|
||||
entity_id: "binary_sensor.motion_sensor_158d0001e5cf11",
|
||||
@@ -905,9 +678,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Playroom Motion Sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T19:21:57.159579+00:00",
|
||||
last_updated: "2019-01-18T19:24:56.764707+00:00",
|
||||
context: { id: "c811022df9274ebf84fd14b005b58d55", user_id: null },
|
||||
},
|
||||
"binary_sensor.water_leak_sensor_158d0002338651": {
|
||||
entity_id: "binary_sensor.water_leak_sensor_158d0002338651",
|
||||
@@ -917,9 +687,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "Bathroom Leak Sensor",
|
||||
device_class: "moisture",
|
||||
},
|
||||
last_changed: "2019-01-14T08:57:08.975457+00:00",
|
||||
last_updated: "2019-01-14T08:57:08.975457+00:00",
|
||||
context: { id: "402512d782014da9ac2fd57e2c984f40", user_id: null },
|
||||
},
|
||||
"sensor.us_air_pollution_level_2": {
|
||||
entity_id: "sensor.us_air_pollution_level_2",
|
||||
@@ -931,9 +698,6 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "U.S. Air Pollution Level",
|
||||
icon: "mdi:emoticon-excited",
|
||||
},
|
||||
last_changed: "2019-01-15T04:59:09.009635+00:00",
|
||||
last_updated: "2019-01-15T04:59:09.009635+00:00",
|
||||
context: { id: "5ba0cfab9733498eb1ccf06d8c88cb67", user_id: null },
|
||||
},
|
||||
"sensor.us_main_pollutant_2": {
|
||||
entity_id: "sensor.us_main_pollutant_2",
|
||||
@@ -947,8 +711,5 @@ export const demoEntitiesJimpower: () => Entity[] = () =>
|
||||
friendly_name: "U.S. Main Pollutant",
|
||||
icon: "mdi:chemical-weapon",
|
||||
},
|
||||
last_changed: "2019-01-15T04:49:08.675430+00:00",
|
||||
last_updated: "2019-01-15T04:49:08.675430+00:00",
|
||||
context: { id: "15f2b232efd94c5fbeef00a51bb4dd41", user_id: null },
|
||||
},
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import "../../custom-cards/card-modder";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoLovelaceJimpower: () => LovelaceConfig = () => ({
|
||||
export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
||||
name: "Kingia Castle",
|
||||
resources: [
|
||||
// {
|
||||
|
@@ -23,27 +23,24 @@ export const demoThemeJimpower = () => ({
|
||||
"paper-listbox-background-color": "#2E333A",
|
||||
"table-row-background-color": "#353840",
|
||||
"paper-grey-50": "var(--primary-text-color)",
|
||||
"paper-toggle-button-checked-button-color": "var(--accent-color)",
|
||||
"switch-checked-color": "var(--accent-color)",
|
||||
"paper-dialog-background-color": "#434954",
|
||||
"secondary-text-color": "#5294E2",
|
||||
"google-red-500": "#E45E65",
|
||||
"divider-color": "rgba(0, 0, 0, .12)",
|
||||
"paper-toggle-button-unchecked-ink-color": "var(--disabled-text-color)",
|
||||
"google-green-500": "#39E949",
|
||||
"paper-toggle-button-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"label-badge-border-color": "green",
|
||||
"paper-listbox-color": "var(--primary-color)",
|
||||
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
|
||||
"paper-toggle-button-checked-ink-color": "var(--accent-color)",
|
||||
"paper-card-background-color": "#434954",
|
||||
"label-badge-text-color": "var(--primary-text-color)",
|
||||
"paper-slider-knob-start-color": "var(--accent-color)",
|
||||
"paper-toggle-button-unchecked-bar-color": "var(--disabled-text-color)",
|
||||
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
||||
"dark-primary-color": "var(--accent-color)",
|
||||
"paper-slider-secondary-color": "var(--secondary-background-color)",
|
||||
"paper-slider-pin-color": "var(--accent-color)",
|
||||
"paper-item-icon-active-color": "#F9C536",
|
||||
"accent-color": "#E45E65",
|
||||
"paper-toggle-button-checked-bar-color": "var(--accent-color)",
|
||||
"table-row-alternative-background-color": "#3E424B",
|
||||
});
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { Entity, convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
||||
convertEntities({
|
||||
"zone.anna": {
|
||||
entity_id: "zone.anna",
|
||||
@@ -11,9 +12,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Anna",
|
||||
icon: "mdi:home-variant",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.731926+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.731926+00:00",
|
||||
context: { id: "77f8305e96e24d8ebbac1d52a394f725", user_id: null },
|
||||
},
|
||||
"zone.peak_hq": {
|
||||
entity_id: "zone.peak_hq",
|
||||
@@ -24,9 +22,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "PEAK HQ",
|
||||
icon: "mdi:briefcase",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.732676+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.732676+00:00",
|
||||
context: { id: "10a51d25775144ca84d19aa1fec3f473", user_id: null },
|
||||
},
|
||||
"zone.bellas_jobb": {
|
||||
entity_id: "zone.bellas_jobb",
|
||||
@@ -37,9 +32,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Bellas jobb",
|
||||
icon: "mdi:briefcase",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.733288+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.733288+00:00",
|
||||
context: { id: "c8001f0ab45f43a2b66af3dc849aca36", user_id: null },
|
||||
},
|
||||
"zone.geab": {
|
||||
entity_id: "zone.geab",
|
||||
@@ -50,9 +42,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "GEAB",
|
||||
icon: "mdi:briefcase",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.733871+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.733871+00:00",
|
||||
context: { id: "57ba8b28976649ae90ff3d0652daa551", user_id: null },
|
||||
},
|
||||
"zone.mamma": {
|
||||
entity_id: "zone.mamma",
|
||||
@@ -63,9 +52,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Mamma",
|
||||
icon: "mdi:home-variant",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.735150+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.735150+00:00",
|
||||
context: { id: "ebeb9fa7177746ddb5edd43d076b5209", user_id: null },
|
||||
},
|
||||
"zone.skolan": {
|
||||
entity_id: "zone.skolan",
|
||||
@@ -76,9 +62,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Skolan",
|
||||
icon: "mdi:school",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.735883+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.735883+00:00",
|
||||
context: { id: "70c93139b05e465e9d7f3645f473061c", user_id: null },
|
||||
},
|
||||
"zone.ica_fjallbacken": {
|
||||
entity_id: "zone.ica_fjallbacken",
|
||||
@@ -89,9 +72,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "ICA Fj\u00e4llbacken",
|
||||
icon: "mdi:cart",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.736498+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.736498+00:00",
|
||||
context: { id: "d17736ee569d4b9ab92c608bad43c14d", user_id: null },
|
||||
},
|
||||
"zone.tempo": {
|
||||
entity_id: "zone.tempo",
|
||||
@@ -102,9 +82,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Tempo",
|
||||
icon: "mdi:cart",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.737081+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.737081+00:00",
|
||||
context: { id: "e3917e5da14443ea8da81abcb9e3f0d1", user_id: null },
|
||||
},
|
||||
"zone.home": {
|
||||
entity_id: "zone.home",
|
||||
@@ -115,25 +92,16 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Hem",
|
||||
icon: "mdi:home",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:22.737655+00:00",
|
||||
last_updated: "2019-01-18T15:51:22.737655+00:00",
|
||||
context: { id: "d04a42c532614232bfebbbe6c27395eb", user_id: null },
|
||||
},
|
||||
"sensor.total_clients_wireless": {
|
||||
entity_id: "sensor.total_clients_wireless",
|
||||
state: "18",
|
||||
attributes: { friendly_name: "Total clients", icon: "mdi:account-group" },
|
||||
last_changed: "2019-01-18T16:00:34.285208+00:00",
|
||||
last_updated: "2019-01-18T16:00:34.285208+00:00",
|
||||
context: { id: "6e6fe5b3265948289e7817ca7dc74bea", user_id: null },
|
||||
},
|
||||
"sensor.zwave_battery_front_door": {
|
||||
entity_id: "sensor.zwave_battery_front_door",
|
||||
state: "63",
|
||||
attributes: { friendly_name: "Battery", icon: "mdi:battery-60" },
|
||||
last_changed: "2019-01-18T15:55:28.392149+00:00",
|
||||
last_updated: "2019-01-18T15:55:28.392149+00:00",
|
||||
context: { id: "eb2f5a4c8d534e83b2bcc7f87e8a9851", user_id: null },
|
||||
},
|
||||
"sensor.oskar_devices": {
|
||||
entity_id: "sensor.oskar_devices",
|
||||
@@ -142,9 +110,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Oskar",
|
||||
entity_picture: "/assets/kernehed/oscar.jpg",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:16.145962+00:00",
|
||||
last_updated: "2019-01-18T15:53:16.145962+00:00",
|
||||
context: { id: "0e20cf8e4fef40839e4c06921d95b139", user_id: null },
|
||||
},
|
||||
"sensor.bella_devices": {
|
||||
entity_id: "sensor.bella_devices",
|
||||
@@ -153,9 +118,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Bella",
|
||||
entity_picture: "/assets/kernehed/bella.jpg",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:16.152450+00:00",
|
||||
last_updated: "2019-01-18T15:53:16.152450+00:00",
|
||||
context: { id: "43b2512b239f46efbdcc4241c3140b06", user_id: null },
|
||||
},
|
||||
"sensor.oskar_bluetooth": {
|
||||
entity_id: "sensor.oskar_bluetooth",
|
||||
@@ -164,9 +126,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Oskar",
|
||||
entity_picture: "/assets/kernehed/oscar.jpg",
|
||||
},
|
||||
last_changed: "2019-01-18T16:04:26.642398+00:00",
|
||||
last_updated: "2019-01-18T16:04:26.642398+00:00",
|
||||
context: { id: "7d3de12e4c424bdf9242fa3128fc0a7f", user_id: null },
|
||||
},
|
||||
"sensor.battery_oskar": {
|
||||
entity_id: "sensor.battery_oskar",
|
||||
@@ -176,9 +135,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "oskar batteri",
|
||||
device_class: "battery",
|
||||
},
|
||||
last_changed: "2019-01-18T15:54:50.511369+00:00",
|
||||
last_updated: "2019-01-18T15:54:50.511369+00:00",
|
||||
context: { id: "566a01d2fbf8482c9d295405aea3ef18", user_id: null },
|
||||
},
|
||||
"sensor.battery_bella": {
|
||||
entity_id: "sensor.battery_bella",
|
||||
@@ -188,9 +144,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "bella batteri",
|
||||
device_class: "battery",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:16.248139+00:00",
|
||||
last_updated: "2019-01-18T15:53:16.248139+00:00",
|
||||
context: { id: "0daeaca38b584becb17ddeaff6c0821e", user_id: null },
|
||||
},
|
||||
"binary_sensor.unifi_camera": {
|
||||
entity_id: "binary_sensor.unifi_camera",
|
||||
@@ -199,9 +152,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "R\u00f6relsesensor kamera",
|
||||
icon: "mdi:walk",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:25.599307+00:00",
|
||||
last_updated: "2019-01-18T15:51:25.599307+00:00",
|
||||
context: { id: "6c34816433ac4e4a8fb1d66586ff8312", user_id: null },
|
||||
},
|
||||
"sensor.db_size": {
|
||||
entity_id: "sensor.db_size",
|
||||
@@ -211,9 +161,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "DB size",
|
||||
icon: "mdi:database",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:26.081784+00:00",
|
||||
last_updated: "2019-01-18T16:02:26.081784+00:00",
|
||||
context: { id: "185f9f7391a7470e95f591c3278012f7", user_id: null },
|
||||
},
|
||||
"input_select.christmas_pattern": {
|
||||
entity_id: "input_select.christmas_pattern",
|
||||
@@ -236,9 +183,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Choose pattern:",
|
||||
icon: "mdi:snowflake",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:27.137496+00:00",
|
||||
last_updated: "2019-01-18T15:51:27.137496+00:00",
|
||||
context: { id: "17f2d1bc9ec345589b135d3c5d45f485", user_id: null },
|
||||
},
|
||||
"input_select.christmas_palette": {
|
||||
entity_id: "input_select.christmas_palette",
|
||||
@@ -258,9 +202,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Choose palette:",
|
||||
icon: "mdi:vanish",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:27.138686+00:00",
|
||||
last_updated: "2019-01-18T15:51:27.138686+00:00",
|
||||
context: { id: "4eecf1f28d744100aef459c9262ebff8", user_id: null },
|
||||
},
|
||||
"binary_sensor.harmony_hub": {
|
||||
entity_id: "binary_sensor.harmony_hub",
|
||||
@@ -274,17 +215,11 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:remote",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:29.431080+00:00",
|
||||
last_updated: "2019-01-18T16:01:40.417721+00:00",
|
||||
context: { id: "28f6ae7c0f834c41858bb6c08d4baabf", user_id: null },
|
||||
},
|
||||
"switch.rest_julbelysning": {
|
||||
entity_id: "switch.rest_julbelysning",
|
||||
state: "on",
|
||||
attributes: { friendly_name: "Julbelysning" },
|
||||
last_changed: "2019-01-18T15:53:16.345017+00:00",
|
||||
last_updated: "2019-01-18T15:53:16.345017+00:00",
|
||||
context: { id: "0252d0bce23c4329a2beb62094d3cfe7", user_id: null },
|
||||
},
|
||||
"binary_sensor.ubiquiti_nvr": {
|
||||
entity_id: "binary_sensor.ubiquiti_nvr",
|
||||
@@ -298,9 +233,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:38.352047+00:00",
|
||||
last_updated: "2019-01-18T16:01:49.078087+00:00",
|
||||
context: { id: "02c4f1b1cc3447748cf7956311b27e6f", user_id: null },
|
||||
},
|
||||
"binary_sensor.server_1": {
|
||||
entity_id: "binary_sensor.server_1",
|
||||
@@ -314,9 +246,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:46.562111+00:00",
|
||||
last_updated: "2019-01-18T16:01:44.857908+00:00",
|
||||
context: { id: "8b3645c1acbb418f8594b30bffd8df04", user_id: null },
|
||||
},
|
||||
"binary_sensor.windows_server": {
|
||||
entity_id: "binary_sensor.windows_server",
|
||||
@@ -330,9 +259,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:51:51.945544+00:00",
|
||||
last_updated: "2019-01-18T16:02:00.100310+00:00",
|
||||
context: { id: "84fc4435143243a398235928f4d46c1c", user_id: null },
|
||||
},
|
||||
"binary_sensor.ubiquiti_controller": {
|
||||
entity_id: "binary_sensor.ubiquiti_controller",
|
||||
@@ -346,9 +272,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:00.042894+00:00",
|
||||
last_updated: "2019-01-18T16:02:04.175934+00:00",
|
||||
context: { id: "92d789cb452147d5b0d433f7495e1b21", user_id: null },
|
||||
},
|
||||
"binary_sensor.server_2": {
|
||||
entity_id: "binary_sensor.server_2",
|
||||
@@ -362,9 +285,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:08.637459+00:00",
|
||||
last_updated: "2019-01-18T16:02:33.942666+00:00",
|
||||
context: { id: "6215707ffd1d42ad9f72a40317cb2472", user_id: null },
|
||||
},
|
||||
"alarm_control_panel.kernehed_manison": {
|
||||
entity_id: "alarm_control_panel.kernehed_manison",
|
||||
@@ -531,9 +451,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
},
|
||||
friendly_name: "Our Manison",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:08.647500+00:00",
|
||||
last_updated: "2019-01-18T15:52:08.647500+00:00",
|
||||
context: { id: "d7d20117f8dc430699f85ebe49d00345", user_id: null },
|
||||
},
|
||||
"sensor.qbittorrent_down_speed": {
|
||||
entity_id: "sensor.qbittorrent_down_speed",
|
||||
@@ -543,17 +460,11 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Nedladdning",
|
||||
icon: "mdi:file-download",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:08.782929+00:00",
|
||||
last_updated: "2019-01-18T15:52:08.782929+00:00",
|
||||
context: { id: "a680b2cbf5d64b98b0a37595a1939197", user_id: null },
|
||||
},
|
||||
"sensor.qbittorrent_status": {
|
||||
entity_id: "sensor.qbittorrent_status",
|
||||
state: "idle",
|
||||
attributes: { friendly_name: "Status", icon: "mdi:resistor" },
|
||||
last_changed: "2019-01-18T15:56:54.148361+00:00",
|
||||
last_updated: "2019-01-18T15:56:54.148361+00:00",
|
||||
context: { id: "e7675363c274496eaa23346ff3383772", user_id: null },
|
||||
},
|
||||
"sensor.qbittorrent_up_speed": {
|
||||
entity_id: "sensor.qbittorrent_up_speed",
|
||||
@@ -563,9 +474,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Uppladdning",
|
||||
icon: "mdi:file-upload",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:08.872888+00:00",
|
||||
last_updated: "2019-01-18T15:52:08.872888+00:00",
|
||||
context: { id: "cfb7424d3c54429baab49ef3dda53a33", user_id: null },
|
||||
},
|
||||
"sensor.pi_hole_ads_blocked_today": {
|
||||
entity_id: "sensor.pi_hole_ads_blocked_today",
|
||||
@@ -576,9 +484,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Pi-Hole Ads Blocked Today",
|
||||
icon: "mdi:close-octagon-outline",
|
||||
},
|
||||
last_changed: "2019-01-18T16:03:05.284888+00:00",
|
||||
last_updated: "2019-01-18T16:03:05.284888+00:00",
|
||||
context: { id: "d9191530bc94401ca88a2a1aff07387d", user_id: null },
|
||||
},
|
||||
"sensor.pi_hole_dns_unique_clients": {
|
||||
entity_id: "sensor.pi_hole_dns_unique_clients",
|
||||
@@ -589,9 +494,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Pi-Hole DNS Unique Clients",
|
||||
icon: "mdi:account-outline",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:09.605689+00:00",
|
||||
last_updated: "2019-01-18T15:52:09.605689+00:00",
|
||||
context: { id: "e9f0c3578ff4454fb53121d99c606e74", user_id: null },
|
||||
},
|
||||
"sensor.pi_hole_dns_queries_today": {
|
||||
entity_id: "sensor.pi_hole_dns_queries_today",
|
||||
@@ -602,9 +504,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Pi-Hole DNS Queries Today",
|
||||
icon: "mdi:comment-question-outline",
|
||||
},
|
||||
last_changed: "2019-01-18T16:03:05.274660+00:00",
|
||||
last_updated: "2019-01-18T16:03:05.274660+00:00",
|
||||
context: { id: "dab495be096549438bca2bb5078e41c1", user_id: null },
|
||||
},
|
||||
"sensor.memory_free": {
|
||||
entity_id: "sensor.memory_free",
|
||||
@@ -614,9 +513,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Memory free",
|
||||
icon: "mdi:memory",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:09.553687+00:00",
|
||||
last_updated: "2019-01-18T16:05:09.553687+00:00",
|
||||
context: { id: "8a208015f2c74ed39bada502922d0d0d", user_id: null },
|
||||
},
|
||||
"sensor.processor_use": {
|
||||
entity_id: "sensor.processor_use",
|
||||
@@ -626,9 +522,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Processor use",
|
||||
icon: "mdi:memory",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:09.793229+00:00",
|
||||
last_updated: "2019-01-18T16:05:09.793229+00:00",
|
||||
context: { id: "c5f93e10c82a431a95f85587a5e8ce95", user_id: null },
|
||||
},
|
||||
"binary_sensor.gaming_pc": {
|
||||
entity_id: "binary_sensor.gaming_pc",
|
||||
@@ -642,9 +535,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:laptop",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:19.270243+00:00",
|
||||
last_updated: "2019-01-18T16:02:25.800945+00:00",
|
||||
context: { id: "46211ef0d63e4d75b521cf9ffe121b06", user_id: null },
|
||||
},
|
||||
"sensor.speedtest_download": {
|
||||
entity_id: "sensor.speedtest_download",
|
||||
@@ -661,9 +551,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Speedtest Download",
|
||||
icon: "mdi:speedometer",
|
||||
},
|
||||
last_changed: "2019-01-18T16:01:02.379273+00:00",
|
||||
last_updated: "2019-01-18T16:01:02.379273+00:00",
|
||||
context: { id: "820da4cd237c49eb83dd1f2ad109882a", user_id: null },
|
||||
},
|
||||
"sensor.speedtest_upload": {
|
||||
entity_id: "sensor.speedtest_upload",
|
||||
@@ -680,9 +567,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Speedtest Upload",
|
||||
icon: "mdi:speedometer",
|
||||
},
|
||||
last_changed: "2019-01-18T16:01:02.722583+00:00",
|
||||
last_updated: "2019-01-18T16:01:02.722583+00:00",
|
||||
context: { id: "f390680ee9b44e6aa1ae44ece757f329", user_id: null },
|
||||
},
|
||||
"sensor.speedtest_ping": {
|
||||
entity_id: "sensor.speedtest_ping",
|
||||
@@ -699,9 +583,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Speedtest Ping",
|
||||
icon: "mdi:speedometer",
|
||||
},
|
||||
last_changed: "2019-01-18T16:01:02.809026+00:00",
|
||||
last_updated: "2019-01-18T16:01:02.809026+00:00",
|
||||
context: { id: "a81bd7b4f4f748b290b2156e4b43b919", user_id: null },
|
||||
},
|
||||
"sensor.last_boot": {
|
||||
entity_id: "sensor.last_boot",
|
||||
@@ -712,9 +593,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
icon: "mdi:clock",
|
||||
device_class: "timestamp",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:24.128311+00:00",
|
||||
last_updated: "2019-01-18T15:52:24.128311+00:00",
|
||||
context: { id: "5d0f7cdb75074973aa06d08e3680ebbf", user_id: null },
|
||||
},
|
||||
"sensor.plex": {
|
||||
entity_id: "sensor.plex",
|
||||
@@ -724,9 +602,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Plex",
|
||||
icon: "mdi:plex",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:24.140024+00:00",
|
||||
last_updated: "2019-01-18T15:52:24.140024+00:00",
|
||||
context: { id: "2f992b87ce544a489bbf2d8929b0e4a2", user_id: null },
|
||||
},
|
||||
"binary_sensor.teamspeak": {
|
||||
entity_id: "binary_sensor.teamspeak",
|
||||
@@ -740,9 +615,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:server-network",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:28.615587+00:00",
|
||||
last_updated: "2019-01-18T16:02:21.732951+00:00",
|
||||
context: { id: "73ca74db48e74164b2aeaadc6cce5d34", user_id: null },
|
||||
},
|
||||
"sensor.disk_free_home": {
|
||||
entity_id: "sensor.disk_free_home",
|
||||
@@ -752,9 +624,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Disk free /home",
|
||||
icon: "mdi:harddisk",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:03.575620+00:00",
|
||||
last_updated: "2019-01-18T16:02:03.575620+00:00",
|
||||
context: { id: "02f4dad30931408081c02e89bafa1171", user_id: null },
|
||||
},
|
||||
"weather.smhi_vader": {
|
||||
entity_id: "weather.smhi_vader",
|
||||
@@ -835,9 +704,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
cloudiness: 25,
|
||||
friendly_name: "V\u00e4der",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:33.173548+00:00",
|
||||
last_updated: "2019-01-18T15:52:33.173548+00:00",
|
||||
context: { id: "1c85566e7912415eb124dd9834a4f906", user_id: null },
|
||||
},
|
||||
"binary_sensor.ubiquiti_switch": {
|
||||
entity_id: "binary_sensor.ubiquiti_switch",
|
||||
@@ -851,9 +717,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:nas",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:35.266657+00:00",
|
||||
last_updated: "2019-01-18T16:02:29.854283+00:00",
|
||||
context: { id: "dc9ba8c7aa194d2bbe84331506d8320f", user_id: null },
|
||||
},
|
||||
"binary_sensor.entre_kamera": {
|
||||
entity_id: "binary_sensor.entre_kamera",
|
||||
@@ -867,9 +730,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "connectivity",
|
||||
icon: "mdi:cctv",
|
||||
},
|
||||
last_changed: "2019-01-18T15:52:45.321631+00:00",
|
||||
last_updated: "2019-01-18T16:01:55.993590+00:00",
|
||||
context: { id: "511076d91fb94bafaae7d5ebe08bfee7", user_id: null },
|
||||
},
|
||||
"sensor.bella_tid_till_hem": {
|
||||
entity_id: "sensor.bella_tid_till_hem",
|
||||
@@ -886,9 +746,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Antal minuter hem",
|
||||
icon: "mdi:timer",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:19.161560+00:00",
|
||||
last_updated: "2019-01-18T15:53:19.161560+00:00",
|
||||
context: { id: "3da5acfb211d47afb9c744a6ba135344", user_id: null },
|
||||
},
|
||||
"sensor.oskar_tid_till_hem": {
|
||||
entity_id: "sensor.oskar_tid_till_hem",
|
||||
@@ -906,9 +763,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "Antal minuter hem",
|
||||
icon: "mdi:timer",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:19.197183+00:00",
|
||||
last_updated: "2019-01-18T15:53:19.197183+00:00",
|
||||
context: { id: "cade22f8710648868dd55a9d562ebe76", user_id: null },
|
||||
},
|
||||
"lock.polycontrol_danalock_v3_btze_locked": {
|
||||
entity_id: "lock.polycontrol_danalock_v3_btze_locked",
|
||||
@@ -920,9 +774,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
value_id: "72057594513489920",
|
||||
friendly_name: "Frontdoor",
|
||||
},
|
||||
last_changed: "2019-01-18T15:53:36.058341+00:00",
|
||||
last_updated: "2019-01-18T15:53:36.058341+00:00",
|
||||
context: { id: "e12f4a5ee7864b95bde4d5da1c8753b9", user_id: null },
|
||||
},
|
||||
"binary_sensor.front_door_sensor": {
|
||||
entity_id: "binary_sensor.front_door_sensor",
|
||||
@@ -934,9 +785,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "opening",
|
||||
icon: "mdi:door",
|
||||
},
|
||||
last_changed: "2019-01-18T16:03:19.907644+00:00",
|
||||
last_updated: "2019-01-18T16:03:19.907644+00:00",
|
||||
context: { id: "5c9724de70d249218710cd48d662383a", user_id: null },
|
||||
},
|
||||
"binary_sensor.altan_motion_sensor": {
|
||||
entity_id: "binary_sensor.altan_motion_sensor",
|
||||
@@ -947,9 +795,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "altan_motion_sensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:09.208632+00:00",
|
||||
last_updated: "2019-01-18T16:02:09.208632+00:00",
|
||||
context: { id: "fa3835c018ab4f2caa5fc7a629765ce1", user_id: null },
|
||||
},
|
||||
"binary_sensor.back_door_sensor": {
|
||||
entity_id: "binary_sensor.back_door_sensor",
|
||||
@@ -961,9 +806,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "opening",
|
||||
icon: "mdi:door",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:09.221573+00:00",
|
||||
last_updated: "2019-01-18T16:02:09.221573+00:00",
|
||||
context: { id: "79b24786327f402d98039fc7f64a5cac", user_id: null },
|
||||
},
|
||||
"binary_sensor.badrumssensor": {
|
||||
entity_id: "binary_sensor.badrumssensor",
|
||||
@@ -974,9 +816,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "badrumssensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:09.230201+00:00",
|
||||
last_updated: "2019-01-18T16:02:09.230201+00:00",
|
||||
context: { id: "d717171f27ac4788baf5a01aa76103cb", user_id: null },
|
||||
},
|
||||
"binary_sensor.trapp_motion_sensor": {
|
||||
entity_id: "binary_sensor.trapp_motion_sensor",
|
||||
@@ -989,9 +828,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "motion",
|
||||
icon: "mdi:walk",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:22.880965+00:00",
|
||||
last_updated: "2019-01-18T16:05:22.880965+00:00",
|
||||
context: { id: "930f8a9f68044b9e9081d446bac41dec", user_id: null },
|
||||
},
|
||||
"binary_sensor.tvattstugan_motion_sensor": {
|
||||
entity_id: "binary_sensor.tvattstugan_motion_sensor",
|
||||
@@ -1004,9 +840,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "motion",
|
||||
icon: "mdi:walk",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:18.681492+00:00",
|
||||
last_updated: "2019-01-18T16:05:18.681492+00:00",
|
||||
context: { id: "5203da025f024e6fa3f23d51e49a6792", user_id: null },
|
||||
},
|
||||
"binary_sensor.dorrklockan": {
|
||||
entity_id: "binary_sensor.dorrklockan",
|
||||
@@ -1018,9 +851,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "opening",
|
||||
icon: "mdi:bell",
|
||||
},
|
||||
last_changed: "2019-01-18T16:03:12.046042+00:00",
|
||||
last_updated: "2019-01-18T16:03:12.046042+00:00",
|
||||
context: { id: "fdfdad57b15c456687f610a65e3ef4cb", user_id: null },
|
||||
},
|
||||
"binary_sensor.skafferiet_motion_sensor": {
|
||||
entity_id: "binary_sensor.skafferiet_motion_sensor",
|
||||
@@ -1032,9 +862,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "motion",
|
||||
icon: "mdi:walk",
|
||||
},
|
||||
last_changed: "2019-01-18T16:02:09.287461+00:00",
|
||||
last_updated: "2019-01-18T16:02:09.287461+00:00",
|
||||
context: { id: "51facd375f354ae5aef8c343d6e76290", user_id: null },
|
||||
},
|
||||
"binary_sensor.kallaren_motion_sensor": {
|
||||
entity_id: "binary_sensor.kallaren_motion_sensor",
|
||||
@@ -1047,9 +874,6 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
device_class: "motion",
|
||||
icon: "mdi:walk",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:17.181070+00:00",
|
||||
last_updated: "2019-01-18T16:05:17.181070+00:00",
|
||||
context: { id: "56df28bb79234daba64d61ae7daf0f54", user_id: null },
|
||||
},
|
||||
"binary_sensor.banksensor": {
|
||||
entity_id: "binary_sensor.banksensor",
|
||||
@@ -1061,8 +885,5 @@ export const demoEntitiesKernehed: () => Entity[] = () =>
|
||||
friendly_name: "B\u00e4nksensor",
|
||||
device_class: "motion",
|
||||
},
|
||||
last_changed: "2019-01-18T16:05:03.828041+00:00",
|
||||
last_updated: "2019-01-18T16:05:03.828041+00:00",
|
||||
context: { id: "a270883993b04d90bee5c27180c43cb8", user_id: null },
|
||||
},
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoLovelaceKernehed: () => LovelaceConfig = () => ({
|
||||
export const demoLovelaceKernehed: DemoConfig["lovelace"] = () => ({
|
||||
name: "Hem",
|
||||
resources: [
|
||||
// {
|
||||
|
@@ -24,27 +24,24 @@ export const demoThemeKernehed = () => ({
|
||||
"paper-listbox-background-color": "#141414",
|
||||
"table-row-background-color": "#292929",
|
||||
"paper-grey-50": "var(--primary-text-color)",
|
||||
"paper-toggle-button-checked-button-color": "var(--accent-color)",
|
||||
"switch-checked-color": "var(--accent-color)",
|
||||
"paper-dialog-background-color": "#292929",
|
||||
"secondary-text-color": "#b58e31",
|
||||
"google-red-500": "#b58e31",
|
||||
"divider-color": "rgba(0, 0, 0, .12)",
|
||||
"paper-toggle-button-unchecked-ink-color": "var(--disabled-text-color)",
|
||||
"google-green-500": "#2980b9",
|
||||
"paper-toggle-button-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||
"label-badge-border-color": "green",
|
||||
"paper-listbox-color": "#777777",
|
||||
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
|
||||
"paper-toggle-button-checked-ink-color": "var(--accent-color)",
|
||||
"paper-card-background-color": "#292929",
|
||||
"label-badge-text-color": "var(--primary-text-color)",
|
||||
"paper-slider-knob-start-color": "var(--accent-color)",
|
||||
"paper-toggle-button-unchecked-bar-color": "var(--disabled-text-color)",
|
||||
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
||||
"dark-primary-color": "var(--accent-color)",
|
||||
"paper-slider-secondary-color": "var(--secondary-background-color)",
|
||||
"paper-slider-pin-color": "var(--accent-color)",
|
||||
"paper-item-icon-active-color": "#b58e31",
|
||||
"accent-color": "#2980b9",
|
||||
"paper-toggle-button-checked-bar-color": "var(--accent-color)",
|
||||
"table-row-alternative-background-color": "#292929",
|
||||
});
|
||||
|
@@ -1,29 +1,7 @@
|
||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
||||
import { DemoConfig } from "../types";
|
||||
|
||||
export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({
|
||||
export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
||||
title: "Home",
|
||||
resources: [
|
||||
// {
|
||||
// url: "/local/lovelace/mini-media-player.js?v=0.6",
|
||||
// type: "module",
|
||||
// },
|
||||
// {
|
||||
// url: "/local/lovelace/slider-entity-row.js?v=d6da75",
|
||||
// type: "js",
|
||||
// },
|
||||
// {
|
||||
// url: "/local/lovelace/monster-card.js?v=0.2.3",
|
||||
// type: "js",
|
||||
// },
|
||||
// {
|
||||
// url: "/local/lovelace/tracker-card.js?v=0.1.5",
|
||||
// type: "js",
|
||||
// },
|
||||
// {
|
||||
// url: "/local/lovelace/home-setter.js?v=0.0.1",
|
||||
// type: "js",
|
||||
// },
|
||||
],
|
||||
views: [
|
||||
{
|
||||
cards: [
|
||||
@@ -1201,484 +1179,5 @@ export const demoLovelaceTeachingbirds: () => LovelaceConfig = () => ({
|
||||
title: "Info",
|
||||
icon: "mdi:lan",
|
||||
},
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entities: [
|
||||
// "switch.dafang_night_mode",
|
||||
// "light.isa_ceiling_light",
|
||||
// "switch.dafang_h264_rtsp_server",
|
||||
// ],
|
||||
// camera_image: "camera.upstairs",
|
||||
// type: "picture-glance",
|
||||
// title: "Upstairs",
|
||||
// },
|
||||
// {
|
||||
// entities: [
|
||||
// {
|
||||
// tap_action: {
|
||||
// action: "call-service",
|
||||
// service: "script.dafang_down",
|
||||
// },
|
||||
// entity: "script.dafang_down",
|
||||
// },
|
||||
// {
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// entity: "script.dafang_up",
|
||||
// },
|
||||
// {
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// entity: "script.dafang_left",
|
||||
// },
|
||||
// {
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// entity: "script.dafang_right",
|
||||
// },
|
||||
// {
|
||||
// entity: "script.dafang_calibrate",
|
||||
// hold_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// tap_action: {
|
||||
// action: "none",
|
||||
// },
|
||||
// icon: "mdi:reload",
|
||||
// },
|
||||
// ],
|
||||
// show_name: false,
|
||||
// type: "glance",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// type: "picture-entity",
|
||||
// entity: "camera.motion_dafang",
|
||||
// },
|
||||
// ],
|
||||
// type: "vertical-stack",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entities: [
|
||||
// "light.living_room_ceiling_light_level",
|
||||
// "light.living_room_spotlights_level",
|
||||
// ],
|
||||
// camera_image: "camera.back_door",
|
||||
// type: "picture-glance",
|
||||
// title: "Back door",
|
||||
// },
|
||||
// {
|
||||
// entities: [
|
||||
// {
|
||||
// entity: "script.sannce_down",
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// icon: "mdi:chevron-down",
|
||||
// },
|
||||
// {
|
||||
// entity: "script.sannce_up",
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// icon: "mdi:chevron-up",
|
||||
// },
|
||||
// {
|
||||
// entity: "script.sannce_left",
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// icon: "mdi:chevron-left",
|
||||
// },
|
||||
// {
|
||||
// entity: "script.sannce_right",
|
||||
// tap_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// icon: "mdi:chevron-right",
|
||||
// },
|
||||
// {
|
||||
// entity: "script.sannce_calibrate",
|
||||
// hold_action: {
|
||||
// action: "toggle",
|
||||
// },
|
||||
// tap_action: {
|
||||
// action: "none",
|
||||
// },
|
||||
// icon: "mdi:reload",
|
||||
// },
|
||||
// ],
|
||||
// show_name: false,
|
||||
// type: "glance",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// type: "picture-entity",
|
||||
// entity: "camera.motion_sannce",
|
||||
// },
|
||||
// ],
|
||||
// type: "vertical-stack",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entities: ["sensor.ring_front_door_battery"],
|
||||
// camera_image: "camera.front_door",
|
||||
// title: "Latest Motion Front Door",
|
||||
// show_state: false,
|
||||
// type: "picture-glance",
|
||||
// entity: "camera.front_door",
|
||||
// },
|
||||
// ],
|
||||
// type: "vertical-stack",
|
||||
// },
|
||||
// ],
|
||||
// path: "cameras",
|
||||
// title: "Cameras",
|
||||
// icon: "mdi:cctv",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entities: [
|
||||
// {
|
||||
// name: "Road temp",
|
||||
// entity: "sensor.trafikverket_alta_road_temperature",
|
||||
// },
|
||||
// {
|
||||
// entity: "sensor.homesolna_travel_time",
|
||||
// name: "Solna",
|
||||
// icon: "mdi:car",
|
||||
// },
|
||||
// {
|
||||
// entity: "sensor.homec9_travel_time",
|
||||
// name: "C9",
|
||||
// icon: "mdi:car",
|
||||
// },
|
||||
// ],
|
||||
// type: "glance",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entity: "camera.tpl_skvaltan",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// entity: "camera.tpl_nacka",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// ],
|
||||
// type: "horizontal-stack",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entity: "camera.vikdalen",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// entity: "camera.tpl_kvarnholmen",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// ],
|
||||
// type: "horizontal-stack",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entity: "camera.marinstaden",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// entity: "camera.svindersvik",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// ],
|
||||
// type: "horizontal-stack",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// entity: "camera.sicklatunneln",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// {
|
||||
// entity: "camera.tpl_grondal",
|
||||
// type: "picture-entity",
|
||||
// show_state: false,
|
||||
// },
|
||||
// ],
|
||||
// type: "horizontal-stack",
|
||||
// },
|
||||
// ],
|
||||
// type: "vertical-stack",
|
||||
// },
|
||||
// ],
|
||||
// path: "traffic",
|
||||
// title: "Traffic info",
|
||||
// icon: "mdi:car",
|
||||
// },
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "input_boolean.ad_*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Appdaemon Apps",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.cats*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Cats",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.house*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "House",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.lights*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Lights",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.presence*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Presence",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.security*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Security",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.system*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "System",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.temperature*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Temperature",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "automation.tts*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "TTS",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// {
|
||||
// filter: {
|
||||
// include: [
|
||||
// {
|
||||
// entity_id: "alert.*",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// type: "custom:monster-card",
|
||||
// card: {
|
||||
// show_header_toggle: false,
|
||||
// type: "entities",
|
||||
// title: "Alerts",
|
||||
// },
|
||||
// show_empty: false,
|
||||
// },
|
||||
// ],
|
||||
// path: "automations",
|
||||
// title: "Automations",
|
||||
// icon: "mdi:flash-auto",
|
||||
// },
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
cards: [
|
||||
{
|
||||
entities: [
|
||||
{
|
||||
url: "https://www.home-assistant.io/",
|
||||
type: "weblink",
|
||||
name: "Home Assistant",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
{
|
||||
url: "https://rc--home-assistant-docs.netlify.com/",
|
||||
type: "weblink",
|
||||
name: "Home Assistant Beta",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
{
|
||||
url:
|
||||
"https://github.com/home-assistant/home-assistant-polymer/releases",
|
||||
type: "weblink",
|
||||
name: "Lovelace release notes",
|
||||
icon: "mdi:home-heart",
|
||||
},
|
||||
{
|
||||
url: "https://s3.amazonaws.com/hassio-version/stable.json",
|
||||
type: "weblink",
|
||||
name: "Hassio build",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
{
|
||||
url:
|
||||
"https://github.com/dresden-elektronik/deconz-rest-plugin/releases",
|
||||
type: "weblink",
|
||||
name: "Deconz release notes",
|
||||
icon: "mdi:home-assistant",
|
||||
},
|
||||
],
|
||||
show_header_toggle: false,
|
||||
type: "entities",
|
||||
title: "Links",
|
||||
},
|
||||
],
|
||||
type: "vertical-stack",
|
||||
},
|
||||
// {
|
||||
// cards: [
|
||||
// {
|
||||
// type: "custom:home-setter",
|
||||
// pages: [
|
||||
// {
|
||||
// path: "lovelace/home",
|
||||
// name: "Default",
|
||||
// },
|
||||
// {
|
||||
// path: "lovelace/dashboard",
|
||||
// name: "Dashboard",
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
// {
|
||||
// title: null,
|
||||
// type: "custom:tracker-card",
|
||||
// trackers: [
|
||||
// "sensor.custom_card_tracker",
|
||||
// "sensor.custom_component_tracker",
|
||||
// ],
|
||||
// },
|
||||
// ],
|
||||
// type: "vertical-stack",
|
||||
// },
|
||||
],
|
||||
path: "settings",
|
||||
title: "Settings",
|
||||
icon: "mdi:cogs",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
@@ -12,8 +12,7 @@ export const demoThemeTeachingbirds = () => ({
|
||||
"paper-slider-knob-color": "var(--primary-color)",
|
||||
"paper-listbox-color": "#FFFFFF",
|
||||
"paper-toggle-button-checked-bar-color": "var(--light-primary-color)",
|
||||
"paper-toggle-button-checked-ink-color": "var(--dark-primary-color)",
|
||||
"paper-toggle-button-unchecked-bar-color": "var(--primary-text-color)",
|
||||
"switch-unchecked-track-color": "var(--primary-text-color)",
|
||||
"paper-card-background-color": "#4e4e4e",
|
||||
"label-badge-text-color": "var(--text-primary-color)",
|
||||
"primary-background-color": "#303030",
|
||||
@@ -22,7 +21,7 @@ export const demoThemeTeachingbirds = () => ({
|
||||
"secondary-background-color": "#2b2b2b",
|
||||
"paper-slider-knob-start-color": "var(--primary-color)",
|
||||
"paper-item-icon-active-color": "#d8bf50",
|
||||
"paper-toggle-button-checked-button-color": "var(--primary-color)",
|
||||
"switch-checked-color": "var(--primary-color)",
|
||||
"secondary-text-color": "#389638",
|
||||
"disabled-text-color": "#545454",
|
||||
"paper-item-icon_-_color": "var(--primary-text-color)",
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import { LovelaceConfig } from "../../../src/data/lovelace";
|
||||
import { Entity } from "../../../src/fake_data/entity";
|
||||
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||
|
||||
export interface DemoConfig {
|
||||
index?: number;
|
||||
name: string;
|
||||
authorName: string;
|
||||
authorUrl: string;
|
||||
lovelace: () => LovelaceConfig;
|
||||
entities: () => Entity[];
|
||||
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
||||
entities: (localize: LocalizeFunc) => Entity[];
|
||||
theme: () => { [key: string]: string } | null;
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ class CardModder extends LitElement {
|
||||
for (var k in this._config.style) {
|
||||
if (window.cardTools.hasTemplate(this._config.style[k]))
|
||||
this.templated.push(k);
|
||||
this.card.style.setProperty(k, '');
|
||||
this.card.style.setProperty(k, "");
|
||||
target.style.setProperty(
|
||||
k,
|
||||
window.cardTools.parseTemplate(this._config.style[k])
|
||||
|
@@ -161,8 +161,8 @@ if (!window.cardTools) {
|
||||
};
|
||||
|
||||
cardTools.longpress = (element) => {
|
||||
customElements.whenDefined("long-press").then(() => {
|
||||
const longpress = document.body.querySelector("long-press");
|
||||
customElements.whenDefined("action-handler").then(() => {
|
||||
const longpress = document.body.querySelector("action-handler");
|
||||
longpress.bind(element);
|
||||
});
|
||||
return element;
|
||||
|
113
demo/src/custom-cards/cast-demo-row.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import {
|
||||
html,
|
||||
LitElement,
|
||||
TemplateResult,
|
||||
customElement,
|
||||
property,
|
||||
css,
|
||||
CSSResult,
|
||||
} from "lit-element";
|
||||
|
||||
import "../../../src/components/ha-icon";
|
||||
import {
|
||||
EntityRow,
|
||||
CastConfig,
|
||||
} from "../../../src/panels/lovelace/entity-rows/types";
|
||||
import { HomeAssistant } from "../../../src/types";
|
||||
import { CastManager } from "../../../src/cast/cast_manager";
|
||||
import { castSendShowDemo } from "../../../src/cast/receiver_messages";
|
||||
|
||||
@customElement("cast-demo-row")
|
||||
class CastDemoRow extends LitElement implements EntityRow {
|
||||
public hass!: HomeAssistant;
|
||||
|
||||
@property() private _castManager?: CastManager | null;
|
||||
|
||||
public setConfig(_config: CastConfig): void {
|
||||
// No config possible.
|
||||
}
|
||||
|
||||
protected render(): TemplateResult | void {
|
||||
if (
|
||||
!this._castManager ||
|
||||
this._castManager.castState === "NO_DEVICES_AVAILABLE"
|
||||
) {
|
||||
return html``;
|
||||
}
|
||||
return html`
|
||||
<ha-icon icon="hademo:television"></ha-icon>
|
||||
<div class="flex">
|
||||
<div class="name">Show Chromecast interface</div>
|
||||
<google-cast-launcher></google-cast-launcher>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
import("../../../src/cast/cast_manager").then(({ getCastManager }) =>
|
||||
getCastManager().then((mgr) => {
|
||||
this._castManager = mgr;
|
||||
mgr.addEventListener("state-changed", () => {
|
||||
this.requestUpdate();
|
||||
});
|
||||
mgr.castContext.addEventListener(
|
||||
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
||||
(ev) => {
|
||||
// On Android, opening a new session always results in SESSION_RESUMED.
|
||||
// So treat both as the same.
|
||||
if (
|
||||
ev.sessionState === "SESSION_STARTED" ||
|
||||
ev.sessionState === "SESSION_RESUMED"
|
||||
) {
|
||||
castSendShowDemo(mgr);
|
||||
}
|
||||
}
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
protected updated(changedProps) {
|
||||
super.updated(changedProps);
|
||||
this.style.display = this._castManager ? "" : "none";
|
||||
}
|
||||
|
||||
static get styles(): CSSResult {
|
||||
return css`
|
||||
:host {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
ha-icon {
|
||||
padding: 8px;
|
||||
color: var(--paper-item-icon-color);
|
||||
}
|
||||
.flex {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
margin-left: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.name {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
google-cast-launcher {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"cast-demo-row": CastDemoRow;
|
||||
}
|
||||
}
|
@@ -1,17 +1,8 @@
|
||||
import {
|
||||
LitElement,
|
||||
html,
|
||||
CSSResult,
|
||||
css,
|
||||
PropertyDeclarations,
|
||||
} from "lit-element";
|
||||
import { LitElement, html, CSSResult, css, property } from "lit-element";
|
||||
import { until } from "lit-html/directives/until";
|
||||
import "@polymer/paper-icon-button";
|
||||
import "@material/mwc-button";
|
||||
import "@polymer/paper-spinner/paper-spinner-lite";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-paper-icon-button-next";
|
||||
import "../../../src/components/ha-paper-icon-button-prev";
|
||||
import { LovelaceCard, Lovelace } from "../../../src/panels/lovelace/types";
|
||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
@@ -23,20 +14,13 @@ import {
|
||||
} from "../configs/demo-configs";
|
||||
|
||||
export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
public lovelace?: Lovelace;
|
||||
public hass?: MockHomeAssistant;
|
||||
private _switching?: boolean;
|
||||
|
||||
static get properties(): PropertyDeclarations {
|
||||
return {
|
||||
lovelace: {},
|
||||
hass: {},
|
||||
_switching: {},
|
||||
};
|
||||
}
|
||||
@property() public lovelace?: Lovelace;
|
||||
@property() public hass!: MockHomeAssistant;
|
||||
@property() private _switching?: boolean;
|
||||
private _hidden = localStorage.hide_demo_card;
|
||||
|
||||
public getCardSize() {
|
||||
return 2;
|
||||
return this._hidden ? 0 : 2;
|
||||
}
|
||||
|
||||
public setConfig(
|
||||
@@ -46,14 +30,13 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
) {}
|
||||
|
||||
protected render() {
|
||||
if (this._hidden) {
|
||||
return;
|
||||
}
|
||||
return html`
|
||||
<ha-card>
|
||||
<div class="picker">
|
||||
<ha-paper-icon-button-prev
|
||||
@click=${this._prevConfig}
|
||||
.disabled=${this._switching}
|
||||
></ha-paper-icon-button-prev>
|
||||
<div>
|
||||
<div class="label">
|
||||
${this._switching
|
||||
? html`
|
||||
<paper-spinner-lite active></paper-spinner-lite>
|
||||
@@ -63,9 +46,12 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
(conf) => html`
|
||||
${conf.name}
|
||||
<small>
|
||||
by
|
||||
<a target="_blank" href="${conf.authorUrl}">
|
||||
${conf.authorName}
|
||||
${this.hass.localize(
|
||||
"ui.panel.page-demo.cards.demo.demo_by",
|
||||
"name",
|
||||
conf.authorName
|
||||
)}
|
||||
</a>
|
||||
</small>
|
||||
`
|
||||
@@ -73,30 +59,29 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
""
|
||||
)}
|
||||
</div>
|
||||
<ha-paper-icon-button-next
|
||||
@click=${this._nextConfig}
|
||||
.disabled=${this._switching}
|
||||
></ha-paper-icon-button-next>
|
||||
<mwc-button @click=${this._nextConfig} .disabled=${this._switching}>
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")}
|
||||
</mwc-button>
|
||||
</div>
|
||||
<div class="content">
|
||||
Welcome home! You've reached the Home Assistant demo where we showcase
|
||||
the best UIs created by our community.
|
||||
<div class="content small-hidden">
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="actions small-hidden">
|
||||
<a href="https://www.home-assistant.io" target="_blank">
|
||||
<mwc-button>Learn more about Home Assistant</mwc-button>
|
||||
<mwc-button>
|
||||
${this.hass.localize("ui.panel.page-demo.cards.demo.learn_more")}
|
||||
</mwc-button>
|
||||
</a>
|
||||
</div>
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
private _prevConfig() {
|
||||
this._updateConfig(
|
||||
selectedDemoConfigIndex > 0
|
||||
? selectedDemoConfigIndex - 1
|
||||
: demoConfigs.length - 1
|
||||
);
|
||||
protected firstUpdated(changedProps) {
|
||||
super.firstUpdated(changedProps);
|
||||
if (this._hidden) {
|
||||
this.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
private _nextConfig() {
|
||||
@@ -110,7 +95,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
private async _updateConfig(index: number) {
|
||||
this._switching = true;
|
||||
try {
|
||||
await setDemoConfig(this.hass!, this.lovelace!, index);
|
||||
await setDemoConfig(this.hass, this.lovelace!, index);
|
||||
} catch (err) {
|
||||
alert("Failed to switch config :-(");
|
||||
} finally {
|
||||
@@ -125,6 +110,10 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.actions a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
@@ -136,17 +125,27 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.picker div {
|
||||
text-align: center;
|
||||
.picker mwc-button {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.picker small {
|
||||
.label {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.label small {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.actions {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 500px) {
|
||||
.small-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@@ -12,5 +12,7 @@ import "./resources/hademo-icons";
|
||||
|
||||
/* polyfill for paper-dropdown */
|
||||
setTimeout(() => {
|
||||
import(/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min");
|
||||
import(
|
||||
/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min"
|
||||
);
|
||||
}, 1000);
|
||||
|
@@ -16,6 +16,8 @@ import { mockEvents } from "./stubs/events";
|
||||
import { mockMediaPlayer } from "./stubs/media_player";
|
||||
import { HomeAssistant } from "../../src/types";
|
||||
import { mockFrontend } from "./stubs/frontend";
|
||||
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
||||
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
||||
|
||||
class HaDemo extends HomeAssistantAppEl {
|
||||
protected async _initialize() {
|
||||
@@ -27,7 +29,13 @@ class HaDemo extends HomeAssistantAppEl {
|
||||
};
|
||||
|
||||
const hass = (this.hass = provideHass(this, initial));
|
||||
mockLovelace(hass);
|
||||
const localizePromise =
|
||||
// @ts-ignore
|
||||
this._loadFragmentTranslations(hass.language, "page-demo").then(
|
||||
() => this.hass!.localize
|
||||
);
|
||||
|
||||
mockLovelace(hass, localizePromise);
|
||||
mockAuth(hass);
|
||||
mockTranslations(hass);
|
||||
mockHistory(hass);
|
||||
@@ -37,60 +45,30 @@ class HaDemo extends HomeAssistantAppEl {
|
||||
mockEvents(hass);
|
||||
mockMediaPlayer(hass);
|
||||
mockFrontend(hass);
|
||||
selectedDemoConfig.then((conf) => {
|
||||
hass.addEntities(conf.entities());
|
||||
if (conf.theme) {
|
||||
hass.mockTheme(conf.theme());
|
||||
mockPersistentNotification(hass);
|
||||
|
||||
// Once config is loaded AND localize, set entities and apply theme.
|
||||
Promise.all([selectedDemoConfig, localizePromise]).then(
|
||||
([conf, localize]) => {
|
||||
hass.addEntities(conf.entities(localize));
|
||||
if (conf.theme) {
|
||||
hass.mockTheme(conf.theme());
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// 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 href = isNavigationClick(e);
|
||||
|
||||
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 === "#") {
|
||||
if (!href) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
navigate(this as any, href);
|
||||
navigate(this, href);
|
||||
},
|
||||
{ capture: true }
|
||||
);
|
||||
|
@@ -7,13 +7,13 @@
|
||||
<link rel="mask-icon" href="/static/icons/mask-icon.svg" color="#03a9f4" />
|
||||
<link
|
||||
rel="preload"
|
||||
href="/static/fonts/roboto/Roboto-Regular.ttf"
|
||||
href="/static/fonts/roboto/Roboto-Regular.woff2"
|
||||
as="font"
|
||||
crossorigin
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="/static/fonts/roboto/Roboto-Medium.ttf"
|
||||
href="/static/fonts/roboto/Roboto-Medium.woff2"
|
||||
as="font"
|
||||
crossorigin
|
||||
/>
|
||||
@@ -87,7 +87,7 @@
|
||||
#ha-init-skeleton::before {
|
||||
display: block;
|
||||
content: "";
|
||||
height: 112px;
|
||||
height: 64px;
|
||||
background-color: #03a9f4;
|
||||
}
|
||||
</style>
|
||||
|
@@ -65,74 +65,79 @@ const generateHistory = (state, deltas) => {
|
||||
const incrementalUnits = ["clients", "queries", "ads"];
|
||||
|
||||
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
||||
mockHass.mockAPI(new RegExp("history/period/.+"), (
|
||||
hass,
|
||||
// @ts-ignore
|
||||
method,
|
||||
path,
|
||||
// @ts-ignore
|
||||
parameters
|
||||
) => {
|
||||
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
||||
const entities = params.filter_entity_id.split(",");
|
||||
mockHass.mockAPI(
|
||||
new RegExp("history/period/.+"),
|
||||
(
|
||||
hass,
|
||||
// @ts-ignore
|
||||
method,
|
||||
path,
|
||||
// @ts-ignore
|
||||
parameters
|
||||
) => {
|
||||
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
||||
const entities = params.filter_entity_id.split(",");
|
||||
|
||||
const results: HassEntity[][] = [];
|
||||
const results: HassEntity[][] = [];
|
||||
|
||||
for (const entityId of entities) {
|
||||
const state = hass.states[entityId];
|
||||
for (const entityId of entities) {
|
||||
const state = hass.states[entityId];
|
||||
|
||||
if (!state) {
|
||||
continue;
|
||||
}
|
||||
if (!state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!state.attributes.unit_of_measurement) {
|
||||
results.push(generateHistory(state, [state.state]));
|
||||
continue;
|
||||
}
|
||||
if (!state.attributes.unit_of_measurement) {
|
||||
results.push(generateHistory(state, [state.state]));
|
||||
continue;
|
||||
}
|
||||
|
||||
const numberState = Number(state.state);
|
||||
const numberState = Number(state.state);
|
||||
|
||||
if (isNaN(numberState)) {
|
||||
// tslint:disable-next-line
|
||||
console.log(
|
||||
"Ignoring state with unparsable state but with a unit",
|
||||
entityId,
|
||||
state
|
||||
if (isNaN(numberState)) {
|
||||
// tslint:disable-next-line
|
||||
console.log(
|
||||
"Ignoring state with unparsable state but with a unit",
|
||||
entityId,
|
||||
state
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const statesToGenerate = 15;
|
||||
let genFunc;
|
||||
|
||||
if (incrementalUnits.includes(state.attributes.unit_of_measurement)) {
|
||||
let initial = Math.floor(
|
||||
numberState * 0.4 + numberState * Math.random() * 0.2
|
||||
);
|
||||
const diff = Math.max(
|
||||
1,
|
||||
Math.floor((numberState - initial) / statesToGenerate)
|
||||
);
|
||||
genFunc = () => {
|
||||
initial += diff;
|
||||
return Math.min(numberState, initial);
|
||||
};
|
||||
} else {
|
||||
const diff = Math.floor(
|
||||
numberState * (numberState > 80 ? 0.05 : 0.5)
|
||||
);
|
||||
genFunc = () =>
|
||||
numberState - diff + Math.floor(Math.random() * 2 * diff);
|
||||
}
|
||||
|
||||
results.push(
|
||||
generateHistory(
|
||||
{
|
||||
entity_id: state.entity_id,
|
||||
attributes: state.attributes,
|
||||
},
|
||||
Array.from({ length: statesToGenerate }, genFunc)
|
||||
)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const statesToGenerate = 15;
|
||||
let genFunc;
|
||||
|
||||
if (incrementalUnits.includes(state.attributes.unit_of_measurement)) {
|
||||
let initial = Math.floor(
|
||||
numberState * 0.4 + numberState * Math.random() * 0.2
|
||||
);
|
||||
const diff = Math.max(
|
||||
1,
|
||||
Math.floor((numberState - initial) / statesToGenerate)
|
||||
);
|
||||
genFunc = () => {
|
||||
initial += diff;
|
||||
return Math.min(numberState, initial);
|
||||
};
|
||||
} else {
|
||||
const diff = Math.floor(numberState * (numberState > 80 ? 0.05 : 0.5));
|
||||
genFunc = () =>
|
||||
numberState - diff + Math.floor(Math.random() * 2 * diff);
|
||||
}
|
||||
|
||||
results.push(
|
||||
generateHistory(
|
||||
{
|
||||
entity_id: state.entity_id,
|
||||
attributes: state.attributes,
|
||||
},
|
||||
Array.from({ length: statesToGenerate }, genFunc)
|
||||
)
|
||||
);
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
});
|
||||
);
|
||||
};
|
||||
|
@@ -1,15 +1,21 @@
|
||||
import "../custom-cards/ha-demo-card";
|
||||
import "../custom-cards/cast-demo-row";
|
||||
// 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 { selectedDemoConfig } from "../configs/demo-configs";
|
||||
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||
|
||||
export const mockLovelace = (hass: MockHomeAssistant) => {
|
||||
selectedDemoConfig.then((config) => hass.addEntities(config.entities()));
|
||||
|
||||
export const mockLovelace = (
|
||||
hass: MockHomeAssistant,
|
||||
localizePromise: Promise<LocalizeFunc>
|
||||
) => {
|
||||
hass.mockWS("lovelace/config", () =>
|
||||
selectedDemoConfig.then((config) => config.lovelace())
|
||||
Promise.all([
|
||||
selectedDemoConfig,
|
||||
localizePromise,
|
||||
]).then(([config, localize]) => config.lovelace(localize))
|
||||
);
|
||||
|
||||
hass.mockWS("lovelace/config/save", () => Promise.resolve());
|
||||
|
16
demo/src/stubs/persistent_notification.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||
import { PersistentNotification } from "../../../src/data/persistent_notification";
|
||||
|
||||
export const mockPersistentNotification = (hass: MockHomeAssistant) => {
|
||||
hass.mockWS("persistent_notification/get", () =>
|
||||
Promise.resolve([
|
||||
{
|
||||
created_at: new Date().toISOString(),
|
||||
message: "There was motion detected in the backyard.",
|
||||
notification_id: "demo-1",
|
||||
title: "Motion Detected!",
|
||||
status: "unread",
|
||||
},
|
||||
] as PersistentNotification[])
|
||||
);
|
||||
};
|
@@ -97,7 +97,7 @@ export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||
"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/).",
|
||||
"You need to configure Nest before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/integrations/nest/).",
|
||||
"component.nest.config.error.internal_error":
|
||||
"Internal error validating code",
|
||||
"component.nest.config.error.invalid_code": "Invalid code",
|
||||
@@ -199,7 +199,7 @@ export const mockTranslations = (hass: MockHomeAssistant) => {
|
||||
"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/).",
|
||||
"You need to configure Point before being able to authenticate with it. [Please read the instructions](https://www.home-assistant.io/integrations/point/).",
|
||||
"component.point.config.create_entry.default":
|
||||
"Successfully authenticated with Minut for your Point device(s)",
|
||||
"component.point.config.error.follow_link":
|
||||
|
@@ -1,10 +1,9 @@
|
||||
const { createDemoConfig } = require("../build-scripts/webpack.js");
|
||||
const { isProdBuild, isStatsBuild } = require("../build-scripts/env.js");
|
||||
|
||||
// This file exists because we haven't migrated the stats script yet
|
||||
// File just used for stats builds
|
||||
|
||||
const isProdBuild = process.env.NODE_ENV === "production";
|
||||
const isStatsBuild = process.env.STATS === "1";
|
||||
const latestBuild = false;
|
||||
const latestBuild = true;
|
||||
|
||||
module.exports = createDemoConfig({
|
||||
isProdBuild,
|
||||
|
@@ -1,18 +0,0 @@
|
||||
<!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>HAGallery</title>
|
||||
<script src='./main.js' async></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Roboto, Noto, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@@ -4,14 +4,6 @@
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
OUTPUT_DIR=dist
|
||||
|
||||
rm -rf $OUTPUT_DIR
|
||||
|
||||
cd ..
|
||||
./node_modules/.bin/gulp build-translations gen-icons
|
||||
cd gallery
|
||||
|
||||
NODE_ENV=production ../node_modules/.bin/webpack -p --config webpack.config.js
|
||||
./node_modules/.bin/gulp build-gallery
|
||||
|
@@ -4,10 +4,6 @@
|
||||
# Stop on errors
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
cd "$(dirname "$0")/../.."
|
||||
|
||||
cd ..
|
||||
./node_modules/.bin/gulp build-translations gen-icons
|
||||
cd gallery
|
||||
|
||||
../node_modules/.bin/webpack-dev-server
|
||||
./node_modules/.bin/gulp develop-gallery
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import JsYaml from "js-yaml";
|
||||
import { safeLoad } from "js-yaml";
|
||||
|
||||
import { createCardElement } from "../../../src/panels/lovelace/common/create-card-element";
|
||||
|
||||
@@ -62,7 +62,7 @@ class DemoCard extends PolymerElement {
|
||||
card.removeChild(card.lastChild);
|
||||
}
|
||||
|
||||
const el = createCardElement(JsYaml.safeLoad(config.config)[0]);
|
||||
const el = createCardElement(safeLoad(config.config)[0]);
|
||||
el.hass = this.hass;
|
||||
card.appendChild(el);
|
||||
}
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "./demo-card";
|
||||
import "../../../src/components/ha-switch";
|
||||
|
||||
class DemoCards extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -26,9 +26,9 @@ class DemoCards extends PolymerElement {
|
||||
</style>
|
||||
<app-toolbar>
|
||||
<div class="filters">
|
||||
<paper-toggle-button checked="{{_showConfig}}"
|
||||
>Show config</paper-toggle-button
|
||||
>
|
||||
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
|
||||
Show config
|
||||
</ha-switch>
|
||||
</div>
|
||||
</app-toolbar>
|
||||
<div class="cards">
|
||||
@@ -53,6 +53,10 @@ class DemoCards extends PolymerElement {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_showConfigToggled(ev) {
|
||||
this._showConfig = ev.target.checked;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("demo-cards", DemoCards);
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||
import "@polymer/paper-toggle-button/paper-toggle-button";
|
||||
|
||||
import "./demo-more-info";
|
||||
import "../../../src/components/ha-switch";
|
||||
|
||||
class DemoMoreInfos extends PolymerElement {
|
||||
static get template() {
|
||||
@@ -26,9 +26,7 @@ class DemoMoreInfos extends PolymerElement {
|
||||
</style>
|
||||
<app-toolbar>
|
||||
<div class="filters">
|
||||
<paper-toggle-button checked="{{_showConfig}}"
|
||||
>Show entity</paper-toggle-button
|
||||
>
|
||||
<ha-switch checked="{{_showConfig}}">Show entity</ha-switch>
|
||||
</div>
|
||||
</app-toolbar>
|
||||
<div class="cards">
|
||||
|
@@ -36,7 +36,7 @@ export default {
|
||||
attributes: {
|
||||
title: "Welcome Home!",
|
||||
message:
|
||||
"Here are some resources to get started:\n\n - [Configuring Home Assistant](https://home-assistant.io/getting-started/configuration/)\n - [Available components](https://home-assistant.io/components/)\n - [Troubleshooting your configuration](https://home-assistant.io/docs/configuration/troubleshooting/)\n - [Getting help](https://home-assistant.io/help/)\n\nTo not see this card popup in the future, edit your config in\n`configuration.yaml` and disable the `introduction` component.",
|
||||
"Here are some resources to get started:\n\n - [Configuring Home Assistant](https://home-assistant.io/getting-started/configuration/)\n - [Available integrations](https://home-assistant.io/integrations/)\n - [Troubleshooting your configuration](https://home-assistant.io/docs/configuration/troubleshooting/)\n - [Getting help](https://home-assistant.io/help/)\n\nTo not see this card popup in the future, edit your config in\n`configuration.yaml` and disable the `introduction` integration.",
|
||||
},
|
||||
last_changed: "2018-07-19T10:44:45.922241+00:00",
|
||||
last_updated: "2018-07-19T10:44:45.922241+00:00",
|
||||
|
@@ -14,14 +14,14 @@ const ENTITIES = [
|
||||
target_temp_high: 75,
|
||||
target_temp_low: 70,
|
||||
fan_mode: "Auto Low",
|
||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
operation_mode: "auto",
|
||||
operation_list: ["heat", "cool", "auto", "off"],
|
||||
hold_mode: "home",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Ecobee",
|
||||
supported_features: 1014,
|
||||
supported_features: 59,
|
||||
preset_mode: "eco",
|
||||
preset_modes: ["away", "eco"],
|
||||
}),
|
||||
getEntity("climate", "nest", "heat", {
|
||||
current_temperature: 17,
|
||||
@@ -29,14 +29,12 @@ const ENTITIES = [
|
||||
max_temp: 25,
|
||||
temperature: 19,
|
||||
fan_mode: "Auto Low",
|
||||
fan_list: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
operation_mode: "heat",
|
||||
operation_list: ["heat", "cool", "auto", "off"],
|
||||
hold_mode: "home",
|
||||
fan_modes: ["On Low", "On High", "Auto Low", "Auto High", "Off"],
|
||||
hvac_modes: ["heat", "cool", "auto", "off"],
|
||||
swing_mode: "Auto",
|
||||
swing_list: ["Auto", "1", "2", "3", "Off"],
|
||||
swing_modes: ["Auto", "1", "2", "3", "Off"],
|
||||
friendly_name: "Nest",
|
||||
supported_features: 1014,
|
||||
supported_features: 43,
|
||||
}),
|
||||
];
|
||||
|
||||
|
@@ -2,7 +2,8 @@ import { html, LitElement, TemplateResult } from "lit-element";
|
||||
import "@material/mwc-button";
|
||||
|
||||
import "../../../src/components/ha-card";
|
||||
import { longPress } from "../../../src/panels/lovelace/common/directives/long-press-directive";
|
||||
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
|
||||
import { ActionHandlerEvent } from "../../../src/data/lovelace";
|
||||
|
||||
export class DemoUtilLongPress extends LitElement {
|
||||
protected render(): TemplateResult | void {
|
||||
@@ -12,9 +13,8 @@ export class DemoUtilLongPress extends LitElement {
|
||||
() => html`
|
||||
<ha-card>
|
||||
<mwc-button
|
||||
@ha-click="${this._handleTap}"
|
||||
@ha-hold="${this._handleHold}"
|
||||
.longPress="${longPress()}"
|
||||
@action=${this._handleAction}
|
||||
.actionHandler=${actionHandler({})}
|
||||
>
|
||||
(long) press me!
|
||||
</mwc-button>
|
||||
@@ -28,12 +28,8 @@ export class DemoUtilLongPress extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleTap(ev: Event) {
|
||||
this._addValue(ev, "tap");
|
||||
}
|
||||
|
||||
private _handleHold(ev: Event) {
|
||||
this._addValue(ev, "hold");
|
||||
private _handleAction(ev: ActionHandlerEvent) {
|
||||
this._addValue(ev, ev.detail.action!);
|
||||
}
|
||||
|
||||
private _addValue(ev: Event, value: string) {
|
||||
|
@@ -56,7 +56,7 @@ class HaGallery extends PolymerElement {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
a paper-item {
|
||||
a {
|
||||
color: var(--primary-text-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
@@ -138,12 +138,22 @@ class HaGallery extends PolymerElement {
|
||||
</template>
|
||||
</div>
|
||||
</app-header-layout>
|
||||
<notification-manager id='notifications'></notification-manager>
|
||||
<notification-manager hass=[[_fakeHass]] id='notifications'></notification-manager>
|
||||
`;
|
||||
}
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
_fakeHass: {
|
||||
type: Object,
|
||||
// Just enough for computeRTL
|
||||
value: {
|
||||
language: "en",
|
||||
translationMetadata: {
|
||||
translations: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
_demo: {
|
||||
type: String,
|
||||
value: document.location.hash.substr(1),
|
||||
|
22
gallery/src/html/index.html.template
Normal file
@@ -0,0 +1,22 @@
|
||||
<!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>HAGallery</title>
|
||||
|
||||
<script type="module" src="<%= latestGalleryJS %>"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: Roboto, Noto, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@@ -1,7 +1,7 @@
|
||||
const path = require("path");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const { createGalleryConfig } = require("../build-scripts/webpack.js");
|
||||
const { babelLoaderConfig } = require("../build-scripts/babel.js");
|
||||
const webpackBase = require("../build-scripts/webpack.js");
|
||||
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const chunkFilename = isProd ? "chunk.[chunkhash].js" : "[name].chunk.js";
|
||||
@@ -9,58 +9,64 @@ const buildPath = path.resolve(__dirname, "dist");
|
||||
const publicPath = isProd ? "./" : "http://localhost:8080/";
|
||||
const latestBuild = true;
|
||||
|
||||
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: "./src/entrypoint.js",
|
||||
module: {
|
||||
rules: [
|
||||
babelLoaderConfig({ latestBuild }),
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: "raw-loader",
|
||||
},
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
module.exports = createGalleryConfig({
|
||||
latestBuild: true,
|
||||
});
|
||||
|
||||
const bla = () => {
|
||||
const oldExports = {
|
||||
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: "./src/entrypoint.js",
|
||||
module: {
|
||||
rules: [
|
||||
babelLoaderConfig({ latestBuild }),
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: "raw-loader",
|
||||
},
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
options: {
|
||||
exportAsEs6Default: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: webpackBase.optimization(latestBuild),
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
"public",
|
||||
{ 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/",
|
||||
},
|
||||
]),
|
||||
].filter(Boolean),
|
||||
resolve: webpackBase.resolve,
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
chunkFilename: chunkFilename,
|
||||
path: buildPath,
|
||||
publicPath,
|
||||
},
|
||||
devServer: {
|
||||
contentBase: "./public",
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: webpackBase.optimization(latestBuild),
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
"public",
|
||||
{ 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/roboto-fontface/fonts/roboto/*.woff2",
|
||||
to: "static/fonts/roboto/",
|
||||
},
|
||||
{
|
||||
from: "../node_modules/leaflet/dist/images",
|
||||
to: "static/images/leaflet/",
|
||||
},
|
||||
]),
|
||||
].filter(Boolean),
|
||||
resolve: webpackBase.resolve,
|
||||
output: {
|
||||
filename: "[name].js",
|
||||
chunkFilename: chunkFilename,
|
||||
path: buildPath,
|
||||
publicPath,
|
||||
},
|
||||
devServer: {
|
||||
contentBase: "./public",
|
||||
},
|
||||
};
|
||||
};
|
||||
|