Initial HADashboard bring up
This commit is contained in:
parent
28ee44b55b
commit
3354c6fed4
|
@ -0,0 +1,14 @@
|
||||||
|
log:
|
||||||
|
logfile: STDOUT
|
||||||
|
errorfile: STDERR
|
||||||
|
appdaemon:
|
||||||
|
threads: 10
|
||||||
|
plugins:
|
||||||
|
HASS:
|
||||||
|
type: hass
|
||||||
|
# Running this on the same user defined docker network so we use the other containers hostname and port directly to avoid data leaks and simplify config
|
||||||
|
ha_url: http://home-assistant:8123
|
||||||
|
token: !secret ha_token
|
||||||
|
hadashboard:
|
||||||
|
# Using docker + reverse proxy means we want this exposed EVERYWHERE, no matter what
|
||||||
|
dash_url: http://0.0.0.0:5050
|
|
@ -0,0 +1,4 @@
|
||||||
|
hello_world:
|
||||||
|
module: hello
|
||||||
|
class: HelloWorld
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
hello_world:
|
||||||
|
module: hello
|
||||||
|
class: HelloWorld
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
#
|
||||||
|
# Hellow World App
|
||||||
|
#
|
||||||
|
# Args:
|
||||||
|
#
|
||||||
|
|
||||||
|
class HelloWorld(hass.Hass):
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self.log("Hello from AppDaemon")
|
||||||
|
self.log("You are now ready to run Apps!")
|
|
@ -0,0 +1,241 @@
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: #222;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #fff;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1;
|
||||||
|
font-family: 'Helvetica Neue', 'Helvetica', 'Open Sans', 'Arial'
|
||||||
|
}
|
||||||
|
|
||||||
|
b, strong {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
img, object {
|
||||||
|
max-width: 100%;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
border-radius: 5px;}
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, ol {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, p {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 300%;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 125%;
|
||||||
|
font-weight: 300;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
background-color: #444;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard_main {
|
||||||
|
margin: 0px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gridster {
|
||||||
|
margin: 0px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-background {
|
||||||
|
pointer-events: none;
|
||||||
|
width: 100%!important;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
opacity: 0.1;
|
||||||
|
font-size: 1375%;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-nostyle {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gridster ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gs-w {
|
||||||
|
width: 100%;
|
||||||
|
display: table;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.iframe {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
border-radius: 5px;}
|
||||||
|
|
||||||
|
.widget {
|
||||||
|
padding: 0px 0px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #444444;
|
||||||
|
-webkit-border-radius: 5px;
|
||||||
|
-moz-border-radius: 5px;
|
||||||
|
border-radius: 5px;}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-inactive {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-active {
|
||||||
|
color: #aaff00;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#container {
|
||||||
|
padding-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialog {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background: rgba(0,0,0,0.8);
|
||||||
|
z-index: 9999;
|
||||||
|
opacity:0;
|
||||||
|
-webkit-transition: opacity 400ms ease-in;
|
||||||
|
-moz-transition: opacity 400ms ease-in;
|
||||||
|
transition: opacity 400ms ease-in;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialogOpen {
|
||||||
|
opacity:0.95;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialogClose {
|
||||||
|
opacity:0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialog > div {
|
||||||
|
width: 275px;
|
||||||
|
position: relative;
|
||||||
|
margin: 3% auto;
|
||||||
|
padding: 5px 20px 13px 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialogCloseButton {
|
||||||
|
line-height: 50px;
|
||||||
|
position: absolute;
|
||||||
|
right: -25px;
|
||||||
|
text-align: center;
|
||||||
|
top: -20px;
|
||||||
|
width: 50px;
|
||||||
|
text-decoration: none;
|
||||||
|
font-weight: bold;
|
||||||
|
-webkit-border-radius: 25px;
|
||||||
|
-moz-border-radius: 25px;
|
||||||
|
border-radius: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modalDialogCloseButton:hover { background: #444; }
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .unit {
|
||||||
|
font-size: 225%;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .value {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .valueunit {
|
||||||
|
width: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .title {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .title2 {
|
||||||
|
position: absolute;
|
||||||
|
top: 23px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-basedisplay-default-label .state_text {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<! body tags ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<! body tags go here ->
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<! head tags ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<! head tags go here ->
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,101 @@
|
||||||
|
$(function(){ //DOM Ready
|
||||||
|
|
||||||
|
function navigate(url)
|
||||||
|
{
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).attr("title", "Hello Panel");
|
||||||
|
content_width = (120 + 5) * 8 + 5
|
||||||
|
$('.gridster').width(content_width)
|
||||||
|
$(".gridster ul").gridster({
|
||||||
|
widget_margins: [5, 5],
|
||||||
|
widget_base_dimensions: [120, 120],
|
||||||
|
avoid_overlapped_widgets: true,
|
||||||
|
max_rows: 15,
|
||||||
|
max_size_x: 8,
|
||||||
|
shift_widgets_up: false
|
||||||
|
}).data('gridster').disable();
|
||||||
|
|
||||||
|
// Add Widgets
|
||||||
|
|
||||||
|
var gridster = $(".gridster ul").gridster().data('gridster');
|
||||||
|
|
||||||
|
gridster.add_widget('<li><div data-bind="attr: {style: widget_style}" class="widget widget-basedisplay-default-label" id="default-label"><h1 class="title" data-bind="text: title, attr:{ style: title_style}"></h1><h1 class="title2" data-bind="text: title2, attr:{ style: title2_style}"></h1><div class="valueunit" data-bind="attr:{ style: container_style}"><h2 class="value" data-bind="html: value, attr:{ style: value_style}"></h2><p class="unit" data-bind="html: unit, attr:{ style: unit_style}"></p></div><h1 class="state_text" data-bind="text: state_text, attr: {style: state_text_style}"></h1></div></li>', 2, 2, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var widgets = {}
|
||||||
|
// Initialize Widgets
|
||||||
|
|
||||||
|
widgets["default-label"] = new basedisplay("default-label", "", "default", {'widget_type': 'basedisplay', 'fields': {'title': '', 'title2': '', 'value': 'Hello World', 'unit': '', 'state_text': ''}, 'static_css': {'title_style': 'color: #fff;', 'title2_style': 'color: #fff;', 'unit_style': '', 'value_style': 'color: #fff;', 'state_text_style': 'color: #fff;', 'widget_style': 'background-color: #444;', 'container_style': ''}, 'css': {}, 'icons': [], 'static_icons': [], 'namespace': 'default'})
|
||||||
|
|
||||||
|
|
||||||
|
// Setup click handler to cancel timeout navigations
|
||||||
|
|
||||||
|
$( ".gridster" ).click(function(){
|
||||||
|
clearTimeout(myTimeout);
|
||||||
|
if (myTimeoutSticky) {
|
||||||
|
myTimeout = setTimeout(function() { navigate(myTimeoutUrl); }, myTimeoutDelay);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set up timeout
|
||||||
|
|
||||||
|
var myTimeout;
|
||||||
|
var myTimeoutUrl;
|
||||||
|
var myTimeoutDelay;
|
||||||
|
var myTimeoutSticky = 0;
|
||||||
|
|
||||||
|
if (location.search != "")
|
||||||
|
{
|
||||||
|
var query = location.search.substr(1);
|
||||||
|
var result = {};
|
||||||
|
query.split("&").forEach(function(part) {
|
||||||
|
var item = part.split("=");
|
||||||
|
result[item[0]] = decodeURIComponent(item[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ("timeout" in result && "return" in result)
|
||||||
|
{
|
||||||
|
url = result.return
|
||||||
|
argcount = 0
|
||||||
|
for (arg in result)
|
||||||
|
{
|
||||||
|
if (arg != "timeout" && arg != "return" && arg != "sticky")
|
||||||
|
{
|
||||||
|
if (argcount == 0)
|
||||||
|
{
|
||||||
|
url += "?";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
url += "?";
|
||||||
|
}
|
||||||
|
argcount ++;
|
||||||
|
url += arg + "=" + result[arg]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("sticky" in result)
|
||||||
|
{
|
||||||
|
myTimeoutSticky = (result.sticky == "1");
|
||||||
|
}
|
||||||
|
myTimeoutUrl = url;
|
||||||
|
myTimeoutDelay = result.timeout * 1000;
|
||||||
|
myTimeout = setTimeout(function() { navigate(url); }, result.timeout * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start listening for HA Events
|
||||||
|
if (location.protocol == 'https:')
|
||||||
|
{
|
||||||
|
wsprot = "wss:"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wsprot = "ws:"
|
||||||
|
}
|
||||||
|
var stream_url = wsprot + '//' + location.host + '/stream'
|
||||||
|
ha_status(stream_url, "Hello Panel", widgets);
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
#
|
||||||
|
# Main arguments, all optional
|
||||||
|
#
|
||||||
|
title: Hello Panel
|
||||||
|
widget_dimensions: [120, 120]
|
||||||
|
widget_margins: [5, 5]
|
||||||
|
columns: 8
|
||||||
|
|
||||||
|
label:
|
||||||
|
widget_type: label
|
||||||
|
text: Hello World
|
||||||
|
|
||||||
|
layout:
|
||||||
|
- label(2x2)
|
|
@ -0,0 +1,2 @@
|
||||||
|
# General Config
|
||||||
|
ha_token: "A very big string here"
|
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# First run
|
||||||
|
#mkdir /opt/appdaemon && cd /opt/appdaemon
|
||||||
|
#git clone https://github.com/home-assistant/appdaemon.git .
|
||||||
|
|
||||||
|
# All subsequent runs: update to latest app daemon, build, run
|
||||||
|
cd /opt/appdaemon
|
||||||
|
git checkout master
|
||||||
|
git pull
|
||||||
|
LATEST=`git tag | sort -r | grep -v b | head -n1`
|
||||||
|
git checkout ${LATEST}
|
||||||
|
docker build -t appdaemon:latest -t appdaemon:${LATEST} .
|
||||||
|
|
||||||
|
docker container stop home-assistant-dashboard
|
||||||
|
docker container rm home-assistant-dashboard
|
||||||
|
|
||||||
|
docker run -it --name home-assistant-dashboard \
|
||||||
|
--restart unless-stopped \
|
||||||
|
--network docker-private \
|
||||||
|
-e DEBUG=1 \
|
||||||
|
-e HA_URL="http://home-assistant:8123" \
|
||||||
|
-l traefik.frontend.rule=Host:home-automation-dashboard.domain.tld \
|
||||||
|
-l traefik.frontend.passHostHeader=true \
|
||||||
|
-l traefik.port=5050 \
|
||||||
|
-v /etc/localtime:/etc/localtime:ro \
|
||||||
|
-v /var/home-assistant/appdaemon:/conf \
|
||||||
|
appdaemon:latest
|
|
@ -16,6 +16,8 @@ else
|
||||||
REPO="homeassistant/raspberrypi3-homeassistant"
|
REPO="homeassistant/raspberrypi3-homeassistant"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
docker pull ${REPO}
|
||||||
|
|
||||||
touch /var/home-assistant/known_devices.yaml
|
touch /var/home-assistant/known_devices.yaml
|
||||||
|
|
||||||
docker container stop home-assistant
|
docker container stop home-assistant
|
||||||
|
|
Loading…
Reference in New Issue