diff --git a/.gitignore b/.gitignore index 45e72d96..b18dabc2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ /node_modules/ /docs/_build Makefile.ini +/custom/* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..12ff2fdb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "restructuredtext.confPath": "${workspaceFolder}/docs" +} \ No newline at end of file diff --git a/css/creative.css b/css/creative.css index 29f23077..bc13fb14 100644 --- a/css/creative.css +++ b/css/creative.css @@ -612,25 +612,58 @@ a.playlist { color: #bbb; white-space:nowrap } -.graphpopup {overflow:hidden;} -/*To change the default height of the graph popup adapt the height value*/ +/*To change the default height of the graph popup adapt the height value in custom.css + Example: .graphheight { - width: 100%; - height: calc(80vh - 200px); + height: 300px; } +*/ -/*To remove the close button of the graph popup: -.graphclose { - display: none; +.modal.opengraph .modal-body { + background-color: #222; + color: white; + margin: 5px; +} + +.modal .graph { + height: calc(100vh - 250px); } -*/ +/* graphwidth for small screens.*/ .graphwidth { min-width: 30px; - width: 70vw; + width: 100vw; +} + +@media (min-width: 768px) { + .graphwidth { + width: 80vw; + } } +.graphheader { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} + +.graphtitle { + font-size: 150%; +} + +.graphbuttons { +} + +.graph { + flex: 1 +} + +.block_graph { + display: flex; + flex-direction: column; + +} /*To remove the close button of a popup frame: .frameclose { display: none; @@ -1097,6 +1130,7 @@ Only add this hover on NON touch devices .navbar-default.affix .nav > li > a:focus:hover { color: #F05F40; } + } img.icon { @@ -1507,3 +1541,4 @@ a:not([href]) { /*SPECTRUM*/ .sp-container{position:absolute;top:0;left:0;display:inline-block;*display:inline;*zoom:1;z-index:9999994;overflow:hidden}.sp-container.sp-flat{position:relative}.sp-container,.sp-container *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.sp-top{position:relative;width:100%;display:inline-block}.sp-top-inner{position:absolute;top:0;left:0;bottom:0;right:0}.sp-color{position:absolute;top:0;left:0;bottom:0;right:20%}.sp-hue{position:absolute;top:0;right:0;bottom:0;left:84%;height:100%}.sp-clear-enabled .sp-hue{top:33px;height:77.5%}.sp-fill{padding-top:80%}.sp-sat,.sp-val{position:absolute;top:0;left:0;right:0;bottom:0}.sp-alpha-enabled .sp-top{margin-bottom:18px}.sp-alpha-enabled .sp-alpha{display:block}.sp-alpha-handle{position:absolute;top:-4px;bottom:-4px;width:6px;left:50%;cursor:pointer;border:1px solid #000;background:#fff;opacity:.8}.sp-alpha{display:none;position:absolute;bottom:-14px;right:0;left:0;height:8px}.sp-alpha-inner{border:solid 1px #333}.sp-clear{display:none}.sp-clear.sp-clear-display{background-position:center}.sp-clear-enabled .sp-clear{display:block;position:absolute;top:0;right:0;bottom:0;left:84%;height:28px}.sp-container,.sp-replacer,.sp-preview,.sp-dragger,.sp-slider,.sp-alpha,.sp-clear,.sp-alpha-handle,.sp-container.sp-dragging .sp-input,.sp-container button{-webkit-user-select:none;-moz-user-select:-moz-none;-o-user-select:none;user-select:none}.sp-container.sp-input-disabled .sp-input-container{display:none}.sp-container.sp-buttons-disabled .sp-button-container{display:none}.sp-container.sp-palette-buttons-disabled .sp-palette-button-container{display:none}.sp-palette-only .sp-picker-container{display:none}.sp-palette-disabled .sp-palette-container{display:none}.sp-initial-disabled .sp-initial{display:none}.sp-sat{background-image:-webkit-gradient(linear,0 0,100% 0,from(#FFF),to(rgba(204,154,129,0)));background-image:-webkit-linear-gradient(left,#FFF,rgba(204,154,129,0));background-image:-moz-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:-o-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:-ms-linear-gradient(left,#fff,rgba(204,154,129,0));background-image:linear-gradient(to right,#fff,rgba(204,154,129,0));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(GradientType = 1,startColorstr=#FFFFFFFF,endColorstr=#00CC9A81)";filter:progid:DXImageTransform.Microsoft.gradient(GradientType = 1,startColorstr='#FFFFFFFF',endColorstr='#00CC9A81')}.sp-val{background-image:-webkit-gradient(linear,0 100%,0 0,from(#000),to(rgba(204,154,129,0)));background-image:-webkit-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-moz-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-o-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:-ms-linear-gradient(bottom,#000,rgba(204,154,129,0));background-image:linear-gradient(to top,#000,rgba(204,154,129,0));-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81,endColorstr=#FF000000)";filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81',endColorstr='#FF000000')}.sp-hue{background:-moz-linear-gradient(top,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-ms-linear-gradient(top,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-o-linear-gradient(top,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(0.17,#ff0),color-stop(0.33,#0f0),color-stop(0.5,#0ff),color-stop(0.67,#00f),color-stop(0.83,#f0f),to(red));background:-webkit-linear-gradient(top,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);background:linear-gradient(to bottom,red 0%,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.sp-1{height:17%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000',endColorstr='#ffff00')}.sp-2{height:16%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00',endColorstr='#00ff00')}.sp-3{height:17%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00',endColorstr='#00ffff')}.sp-4{height:17%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff',endColorstr='#0000ff')}.sp-5{height:16%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff',endColorstr='#ff00ff')}.sp-6{height:17%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff',endColorstr='#ff0000')}.sp-hidden{display:none!important}.sp-cf:before,.sp-cf:after{content:"";display:table}.sp-cf:after{clear:both}.sp-cf{*zoom:1}@media (max-device-width: 480px){.sp-color{right:40%}.sp-hue{left:63%}.sp-fill{padding-top:60%}}.sp-dragger{border-radius:5px;height:5px;width:5px;border:1px solid #fff;background:#000;cursor:pointer;position:absolute;top:0;left:0}.sp-slider{position:absolute;top:0;cursor:pointer;height:3px;left:-1px;right:-1px;border:1px solid #000;background:#fff;opacity:.8}.sp-container{border-radius:0;background-color:#ECECEC;border:solid 1px #f0c49B;padding:0}.sp-container,.sp-container button,.sp-container input,.sp-color,.sp-hue,.sp-clear{font:normal 12px "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.sp-top{margin-bottom:3px}.sp-color,.sp-hue,.sp-clear{border:solid 1px #666}.sp-input-container{float:right;width:100px;margin-bottom:4px}.sp-initial-disabled .sp-input-container{width:100%}.sp-input{font-size:12px!important;border:1px inset;padding:4px 5px;margin:0;width:100%;background:transparent;border-radius:3px;color:#222}.sp-input:focus{border:1px solid orange}.sp-input.sp-validation-error{border:1px solid red;background:#fdd}.sp-picker-container,.sp-palette-container{float:left;position:relative;padding:10px;padding-bottom:300px;margin-bottom:-290px}.sp-picker-container{width:172px;border-left:solid 1px #fff}.sp-palette-container{border-right:solid 1px #ccc}.sp-palette-only .sp-palette-container{border:0}.sp-palette .sp-thumb-el{display:block;position:relative;float:left;width:24px;height:15px;margin:3px;cursor:pointer;border:solid 2px transparent}.sp-palette .sp-thumb-el:hover,.sp-palette .sp-thumb-el.sp-thumb-active{border-color:orange}.sp-thumb-el{position:relative}.sp-initial{float:left;border:solid 1px #333}.sp-initial span{width:30px;height:25px;border:none;display:block;float:left;margin:0}.sp-initial .sp-clear-display{background-position:center}.sp-palette-button-container,.sp-button-container{float:right}.sp-replacer{cursor:pointer;border:solid 1px #91765d;background:#eee;color:#333;float:left}.sp-replacer:hover,.sp-replacer.sp-active{border-color:#F0C49B;color:#111}.sp-replacer.sp-disabled{cursor:default;border-color:silver;color:silver}.sp-dd{padding:0;margin-right:3px;height:16px;line-height:16px;float:left;font-size:10px}.sp-preview{position:relative;width:25px;height:20px;border:solid 1px #222;margin-right:5px;float:left;z-index:0}.sp-palette{*width:220px;max-width:220px}.sp-palette .sp-thumb-el{width:16px;height:16px;margin:2px 1px;border:solid 1px #d0d0d0}.sp-container{padding-bottom:0}.sp-container button{background-color:#eee;background-image:-webkit-linear-gradient(top,#eee,#ccc);background-image:-moz-linear-gradient(top,#eee,#ccc);background-image:-ms-linear-gradient(top,#eee,#ccc);background-image:-o-linear-gradient(top,#eee,#ccc);background-image:linear-gradient(to bottom,#eee,#ccc);border:1px solid #ccc;border-bottom:1px solid #bbb;border-radius:3px;color:#333;font-size:14px;line-height:1;padding:5px 4px;text-align:center;text-shadow:0 1px 0 #eee;vertical-align:middle}.sp-container button:hover{background-color:#ddd;background-image:-webkit-linear-gradient(top,#ddd,#bbb);background-image:-moz-linear-gradient(top,#ddd,#bbb);background-image:-ms-linear-gradient(top,#ddd,#bbb);background-image:-o-linear-gradient(top,#ddd,#bbb);background-image:linear-gradient(to bottom,#ddd,#bbb);border:1px solid #bbb;border-bottom:1px solid #999;cursor:pointer;text-shadow:0 1px 0 #ddd}.sp-container button:active{border:1px solid #aaa;border-bottom:1px solid #888;-webkit-box-shadow:inset 0 0 5px 2px #aaaaaa,0 1px 0 0 #eee;-moz-box-shadow:inset 0 0 5px 2px #aaaaaa,0 1px 0 0 #eee;-ms-box-shadow:inset 0 0 5px 2px #aaaaaa,0 1px 0 0 #eee;-o-box-shadow:inset 0 0 5px 2px #aaaaaa,0 1px 0 0 #eee;box-shadow:inset 0 0 5px 2px #aaaaaa,0 1px 0 0 #eee}.sp-cancel{font-size:11px;color:#d93f3f!important;margin:0;padding:2px;margin-right:5px;vertical-align:middle;text-decoration:none}.sp-cancel:hover{color:#d93f3f!important;text-decoration:underline}.sp-palette span:hover,.sp-palette span.sp-thumb-active{border-color:#000}.sp-preview,.sp-alpha,.sp-thumb-el{position:relative;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.sp-preview-inner,.sp-alpha-inner,.sp-thumb-inner{display:block;position:absolute;top:0;left:0;bottom:0;right:0}.sp-palette .sp-thumb-inner{background-position:50% 50%;background-repeat:no-repeat}.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=)}.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=)}.sp-clear-display{background-repeat:no-repeat;background-position:center;background-image:url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==)} + diff --git a/docs/blocks/blocks.rst b/docs/blocks/blocks.rst index 9eb8f6c1..a57cda31 100644 --- a/docs/blocks/blocks.rst +++ b/docs/blocks/blocks.rst @@ -7,6 +7,7 @@ The visible elements on the Dashticz dashboard are called blocks. Several block :maxdepth: 2 domoticzblocks + graphs buttons frames specials diff --git a/docs/blocks/domoticzblocks.rst b/docs/blocks/domoticzblocks.rst index 80670241..022fe1a8 100644 --- a/docs/blocks/domoticzblocks.rst +++ b/docs/blocks/domoticzblocks.rst @@ -151,21 +151,8 @@ Block parameters - Open a popup when a device changes to off. See :ref:`openpopup` * - type - Set this parameter to ``'blocktitle'`` if you want to define a block title instead of a normal block. See :ref:`blocktitle` - * - graph - - | Sets the graph type - | ``'line'`` Line graph (default) - | ``'bar'`` Bar graph - * - graphTypes - - | Array of values you want to show in the graph. Can be used for Domoticz devices having several values. - | ``['te']``: Temperature - | ``['hu']``: Humidity - | ``['ba']``: Barometer - | ``['gu', 'sp']``: wind guts and speed - | ``['uvi']``, ``['lux']``, ``['lux_avg']``, ``['mm']``, ``['v_max']`` - | ``['v2']``, ``['mm']``, ``['eu']``, ``['u']``, ``['u_max']``,``['co2']`` - * - graphProperties - - Set this parameter to control the visual appearance of the graph. See :ref:`dom_graphs` +There are several additional parameters for Graphs. See :ref:`dom_graphs` Usage ----- @@ -302,101 +289,3 @@ Example ``custom.css`` (only needed in case you want to change the default flash background-color: #0f0 !important; } -.. _dom_graphs: - -Graphs -~~~~~~ -If your Domoticz device contains a value (temperature, humidity, power, etc.) -then when you click on the block a popup window will appear showing a graph of the values of the device. - -To change the default size of the graph popup windows add the following style blocks to your custom.css:: - - .graphheight { - height: 400px; - } - - .graphwidth { - width: 400px; - } - -To remove the close button of the graph popup add the following text to custom.css:: - - .graphclose { display: none; } - -Besides popup graphs it's also possible to show the graph directly on the dashboard itself, -by adding the graph-id to a column definition as follows:: - - //Adding a graph of device 691 to column 2 - columns[2]['blocks'] = [ - ..., - 'graph_691', //691 is the device id for which you want to show the graph - ... - ] - -.. note:: Using both a graph-block as well as a popup graph of the same device is not supported - -The following block parameters can be used to configure the graph: - -* ``graph`` -* ``graphTypes`` -* ``graphProperties`` - -With the ``graph`` parameter you can define the graph type (``line`` for a line graph and ``bar`` for a bar graph) - -In case of multi-value devices, like temp-hum-bar, you can select the data to show in the graph via the ``graphTypes`` parameter. - -Examples:: - - // To show the temperature values of device 658 - // in a popup graph - blocks[658] = { - graphTypes: ['te'] - } - - // To show the barometer values of device 659 - // on the dashboard directly - blocks['graph_659'] = { - graphTypes: ['ba'] - } - -You can combine the values in one graph. Example:: - - graphTypes: ['te', 'hu'] - -The title and width parameters are applicable to graph-blocks as well. - -So now you can do:: - - //To show a graph of device id 12 - //on the Dashboard - //with a custom title and a 50% column width - blocks['graph_12'] = { - title: 'Custom graph title', - width: 6, - graphTypes: ['te', 'hu'] - }; - -With the parameter ``graphProperties`` you can provide an object to define the visual appearance. -Example: Stacked bar graph (of a P1 smart meter with index 43 in this case) :: - - blocks['graph_43'] = { - title: 'My Power', - graph: 'bar', - graphProperties : { - gridTextColor : '#c3f6fe', - barColors: ['#f1c40f', '#40e0d0', '#eee'], - ymax:10 //set to 'auto' for auto scaling - } - } - -This will give the following result: - -.. image :: img/graph_bar.jpg - - -For all possible graphProperties see: - -* https://morrisjs.github.io/morris.js/lines.html (for line graphs) -* https://morrisjs.github.io/morris.js/bars.html (for bar graphs) - - diff --git a/docs/blocks/frames.rst b/docs/blocks/frames.rst index 5f3e8598..d15b2f12 100644 --- a/docs/blocks/frames.rst +++ b/docs/blocks/frames.rst @@ -1,3 +1,5 @@ +.. _Frames: + Frames ====== diff --git a/docs/blocks/graphs.rst b/docs/blocks/graphs.rst new file mode 100644 index 00000000..4c516196 --- /dev/null +++ b/docs/blocks/graphs.rst @@ -0,0 +1,396 @@ +.. _dom_graphs: + +Graphs +====== + +If your Domoticz device contains a value (temperature, humidity, power, etc.) +then when you click on the block a popup window will appear showing a graph of the values of the device. + +Besides popup graphs it's also possible to show the graph directly on the dashboard itself, +by adding the graph-id to a column definition as follows:: + + //Adding a graph of device 691 to column 2 + columns[2]['blocks'] = [ + ..., + 'graph_691', //691 is the device id for which you want to show the graph + ... + ] + +The following block parameters can be used to configure the graph: + +.. list-table:: + :header-rows: 1 + :widths: 5 30 + :class: tight-table + + * - Parameter + - Description + * - graph + - | Sets the graph type + | ``'line'`` Line graph (default) + | ``'bar'`` Bar graph + * - graphTypes + - | Array of values you want to show in the graph. Can be used for Domoticz devices having several values. + | ``['te']``: Temperature + | ``['hu']``: Humidity + | ``['ba']``: Barometer + | ``['gu', 'sp']``: wind guts and speed + | ``['uvi']``, ``['lux']``, ``['lux_avg']``, ``['mm']``, ``['v_max']`` + | ``['v2']``, ``['mm']``, ``['eu']``, ``['u']``, ``['u_max']``,``['co2']`` + * - height + - ``'300px'``: Height of the graph in the graph block + * - displayFormats + - Object to set the time display format on the x-axis. See below for an example. + * - custom + - Customized graph. See below for examples + +We will show the possibilities by showing a: + +* Simple energy device (Solar panel) +* Climate device (temperature, humidity, barometer) +* P1 Smart Meter + +Simple energy device +-------------------- + +The solar panel device has device id 6. First we add it to a column without any additional configuration parameters, +to show the default result:: + + columns[2]['blocks'] = [ + 6 + ] + + +.. image :: img/solar_default.jpg + +As you see three buttons are generated (actual power, energy today, total energy). +I only want to have one button, so I change my column definition to:: + + columns[2]['blocks'] = [ + '6_1' + ] + +By pressing the button the following graphs pops up: + +.. image :: img/solar_1_default.jpg + +So, nothing special. Only the red line color is maybe a bit too much. Let's change it into a yellow bar graph. +We have to add a block definition:: + + blocks['graph_6'] = { + graph: 'bar', + datasetColors: ['yellow'] + } + +.. image :: img/solar_yellow_bar.jpg + +Now I want to add a legend at the bottom:: + + blocks['graph_6'] = { + graph: 'bar', + datasetColors: ['yellow'], + legend: true + } + +.. image :: img/solar_legend.jpg + +As you can see the data points are labeled as 'V'. This name is generated by Domoticz. We can translate the Domoticz name in something else, by extending the legend parameter :: + + blocks['graph_6'] = { + graph: 'bar', + datasetColors: ['yellow'], + legend: { + 'v': 'Power generation' + } + } + +``legend`` is an object consisting of key-value pairs for the translation from Domoticz names to custom names. + +After pressing the 'Month' button on the popup graph: + +.. image :: img/solar_custom_legend.jpg + +Climate device +-------------- +First let's add a climate device with Domoticz ID 659 to a column:: + + columns[3]['blocks'] = [ + 'graph_659' + ] + +This will show the graph directly on the Dashticz dashboard: + +.. image :: img/climate.jpg + +As you can see the climate device has three subdevices (temperature, humidity, pressure). +Since these are different properties three Y axes are being created. + +If you prefer to only see the temperature and humidity add a block definition:: + + blocks['graph_659'] = { + graphTypes : ['te', 'hu'], + legend: true + } + + +.. image :: img/climate_te_hu.jpg + +Of course you can add a legend as well. See the previous section for an example. + +P1 smart meter +-------------- + +First let's show the default P1 smart meter graph: + +.. image :: img/p1.jpg + +You see a lot of lines. What do they mean? Let's add a legend :: + + blocks['graph_43'] = { + legend: true + } + +This gives: + +.. image :: img/p1_legend.jpg + +That doesn't tell too much. However, this are the value names as provided by Domoticz. +Now you have to know that a P1 power meter has 4 values: + +* Power usage tariff 1 +* Power usage tariff 2 +* Power delivery tariff 1 +* Power delivery tariff 2 + +The first two represent the energy that flows into your house. The last two represent the energy that your house delivers back to the grid. + +So we can add a more meaningful legend as follows:: + + blocks['graph_43'] = { + legend: { + v: "Usage 1", + v2: "Usage 2", + r1: "Return 1", + r2: "Return 2" + } + +Resulting in: + +.. image :: img/p1_legend_2.jpg + +However what I would like to see is: + +* The sum of Usage 1 and Usage 2 +* The sum of Return 1 and Return 2, but then negative +* A line to show the nett energy usage: Usage 1 + Usage 2 - Return 1 - Return +* The usage and return data should be presented as bars. The nett energy as a line. + +Can we do that? Yes, with custom graphs! + +Custom graphs +------------- + +I use the P1 smart meter as an example again to demonstrate how to create custom graphs. First the code and result. +The explanation will follow after that:: + + blocks['graph_43'] = { + title: 'My Power', + graph: ['line','bar','bar'], + custom : { + "last day": { + range: 'day', + filter: '24 hours', + data: { + nett: 'd.v+d.v2-d.r1-d.r2', + usage: 'd.v+d.v2', + generation: '-d.r1-d.r2' + } + }, + "last 2 weeks": { + range: 'month', + filter: '14 days', + data: { + nett: 'd.v+d.v2-d.r1-d.r2', + usage: 'd.v+d.v2', + generation: '-d.r1-d.r2' + } + }, + "last 6 months": { + range: 'year', + filter: '6 months', + data: { + nett: 'd.v+d.v2-d.r1-d.r2', + usage: 'd.v+d.v2', + generation: '-d.r1-d.r2' + } + } + }, + legend: true, + datasetColors:['blue','red','yellow'] + } + +This will give: + +.. image :: img/p1_custom.jpg + +As you can see, the graph has + +* title, set via the ``title`` parameter +* custom colors, defined by the parameter ``datasetColors`` +* The ``graph`` parameter is used to define the graph types. This time it's an array, because we want to select the graph type per value. +* ``legend`` set to true, to show a default legend +* custom buttons, defined by the ``custom`` parameter + +A ``custom`` object start with the name of the button. The button should contain the following three parameters: + +* ``range``. This is the name of the range as requested from Domoticz, and can be ``'day'``, ``'month'`` or ``'year'``. +* ``filter`` (optional). This limits the amount of data to the period as defined by this parameter. Examples: ``'2 hours'``, ``'4 days'``, ``'3 months'`` +* ``data``. This is an object that defines the values to use for the graph. + +As you can see in the example the first value will have the name 'nett'. The formula to compute the value is:: + + 'd.v+d.v2-d.r1-d.r2' + +The ``d`` object contains the data as delivered by Domoticz. As you maybe remember from a previous example +Domoticz provides the two power usage values (v and v2) and the two power return values (r1 and r2). + +So the first part sums the two power usage values (``d.v+d.v2``) and the last parts substracts the two return values (``-d.r1-d.r2``), + +The two other value-names in the data object (usage and generation) will compute the sum of the power usage values and the power return values respectively. + +Maybe a bit complex in the beginning, but the Dashticz forum is not far away. + +Below another example to adapt the reported values of a watermeter to liters:: + + blocks['graph_903'] = { + graph: 'bar', + datasetColors: ['lightblue'], + legend: true, + custom : { + "last hours": { + range: 'day', + filter: '6 hours', + data: { + liter: 'd.v*100' } + }, + + "today": { + range: 'day', + filter: '12 hours', + data: { + liter: 'd.v*100' } + }, + + "last week": { + range: 'month', + filter: '7 days', + data: { + liter: 'd.v*1000' } + } + + + } + } + +.. image :: img/water.jpg + + +Time format on the x-axis +------------------------- + +The chart module uses moments.js for displaying the times and dates. +The locale will be set via the Domoticz setting for the calendar language:: + + config['calendarlanguage'] = 'nl_NL'; + +To set the time (or date) format for the x-axis add the ``displayFormats`` parameter to the block definition:: + + blocks['graph_6'] = { + displayFormats : { + minute: 'h:mm a', + hour: 'hA', + day: 'MMM D', + week: 'll', + month: 'MMM D', + }, + } + +The previous example sets the time formats to UK style. See https://www.chartjs.org/docs/latest/axes/cartesian/time.html#display-formats for time/date formats. + +Modifying the y-axes +-------------------- + +You can modify the y-axes by setting the options parameter. Below you see an example how to define the min and max values of two y-axes:: + + blocks['graph_659'] = { + graph: 'line', + graphTypes: ['te', 'hu'], + options: { + scales: { + yAxes: [{ + ticks: { + min: 0, + max: 30 + } + }, { + ticks: { + min: 50, + max: 100 + } + }] + } + } + } + +The ``yAxes`` parameter in the ``options`` block is an array, with an entry for each y-axis. + +Styling +------- + +For graphs the following css-classes are used: + +* .graph_header: The graph header, including title and buttons +* .graph_title: The title of the graph, including the current value +* .graph_buttons: The buttons for the graph + +You can modify the class definition in custom.css. If you want to hide the header:: + + .graph_header { + display: none; + } + +You can also modify the class for a specific graph only :: + + .block_graph_43 .graph_header { + display: none; + } + +In the previous example only the graph for device id 43 will be affected. + +To change the default size of the graph popup windows add the following style blocks to your custom.css:: + + .graphheight { + height: 400px; + } + + .graphwidth { + width: 400px; + } + +To remove the close button of the graph popup add the following text to custom.css:: + + .graphclose { display: none; } + + + +To be detailed... :: + + .opengraph, .opengraphp, #opengraphp //classes attached to the graph popup dialog + .graphcurrent //class attached to the div with the current value + +For internal use:: + + block_graph_ //The div to which the graph needs to be attached. + #graphoutput //The canvas for the graph output + + diff --git a/docs/blocks/img/climate.jpg b/docs/blocks/img/climate.jpg new file mode 100644 index 00000000..e4d57bf6 Binary files /dev/null and b/docs/blocks/img/climate.jpg differ diff --git a/docs/blocks/img/climate_te_hu.jpg b/docs/blocks/img/climate_te_hu.jpg new file mode 100644 index 00000000..73fbde3f Binary files /dev/null and b/docs/blocks/img/climate_te_hu.jpg differ diff --git a/docs/blocks/img/p1.jpg b/docs/blocks/img/p1.jpg new file mode 100644 index 00000000..a51d4737 Binary files /dev/null and b/docs/blocks/img/p1.jpg differ diff --git a/docs/blocks/img/p1_custom.jpg b/docs/blocks/img/p1_custom.jpg new file mode 100644 index 00000000..4b661f35 Binary files /dev/null and b/docs/blocks/img/p1_custom.jpg differ diff --git a/docs/blocks/img/p1_legend.jpg b/docs/blocks/img/p1_legend.jpg new file mode 100644 index 00000000..b08575d3 Binary files /dev/null and b/docs/blocks/img/p1_legend.jpg differ diff --git a/docs/blocks/img/p1_legend_2.jpg b/docs/blocks/img/p1_legend_2.jpg new file mode 100644 index 00000000..d18ab60c Binary files /dev/null and b/docs/blocks/img/p1_legend_2.jpg differ diff --git a/docs/blocks/img/solar_1_default.jpg b/docs/blocks/img/solar_1_default.jpg new file mode 100644 index 00000000..64fa93fb Binary files /dev/null and b/docs/blocks/img/solar_1_default.jpg differ diff --git a/docs/blocks/img/solar_custom_legend.jpg b/docs/blocks/img/solar_custom_legend.jpg new file mode 100644 index 00000000..521e9031 Binary files /dev/null and b/docs/blocks/img/solar_custom_legend.jpg differ diff --git a/docs/blocks/img/solar_default.jpg b/docs/blocks/img/solar_default.jpg new file mode 100644 index 00000000..782058fc Binary files /dev/null and b/docs/blocks/img/solar_default.jpg differ diff --git a/docs/blocks/img/solar_legend.jpg b/docs/blocks/img/solar_legend.jpg new file mode 100644 index 00000000..8eaac3d0 Binary files /dev/null and b/docs/blocks/img/solar_legend.jpg differ diff --git a/docs/blocks/img/solar_yellow_bar.jpg b/docs/blocks/img/solar_yellow_bar.jpg new file mode 100644 index 00000000..90c50977 Binary files /dev/null and b/docs/blocks/img/solar_yellow_bar.jpg differ diff --git a/docs/blocks/img/water.jpg b/docs/blocks/img/water.jpg new file mode 100644 index 00000000..0d36f2b7 Binary files /dev/null and b/docs/blocks/img/water.jpg differ diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst index fd3b23c6..67b09b43 100644 --- a/docs/releasenotes.rst +++ b/docs/releasenotes.rst @@ -3,12 +3,13 @@ Release Notes A link to the release notes will be posted in the Dashticz support forum. The total overview can be found below. -Latest changes --------------- +3.1.0 (18-9-2019) +----------------- Enhancements * New config setting ``'start_page'`` to set Dashticz start page number - * New parameter ``'scrollbars'`` to set scrollbars in frame + * New parameter ``'scrollbars'`` to set scrollbars in frame. See :ref:`Frames` + * New graph module. It's not completely backwards compatible. Especialy styling will be different. See :ref:`dom_graphs` Fixes * Faster initial display of the Dashticz dashboard. @@ -25,7 +26,6 @@ Fixes * Robustness install script and makefile * Auto restart docker container after reboot * Documentation updates (Thanks to HansieNL) - * 3.0.5 (4-8-2019) ------------------ diff --git a/index.html b/index.html index e7ede604..64dd1bd9 100644 --- a/index.html +++ b/index.html @@ -67,6 +67,7 @@ "vendor/spotify/spotify-web-api.js", "vendor/plugins.js", "vendor/moment.js", + "vendor/chart/chart.min.js", "js/functions.js", "css/creative.css?v=" + cache, "js/main.js?v="+cache, function() { diff --git a/index2.html b/index2.html index ffb6f860..fc1d9ede 100644 --- a/index2.html +++ b/index2.html @@ -67,6 +67,7 @@ "vendor/spotify/spotify-web-api.js", "vendor/plugins.js", "vendor/moment.js", + "vendor/chart/chart.min.js", "js/functions.js", "css/creative.css?v=" + cache, "js/main.js?v="+cache, function() { diff --git a/js/blocks.js b/js/blocks.js index 524ea7c2..debee94a 100644 --- a/js/blocks.js +++ b/js/blocks.js @@ -115,8 +115,9 @@ function getBlock(cols, c, columndiv, standby) { } var blockIndex = 'block_'+myBlockNumbering; +// console.log(blockIndex); blockIndex += standby ? '_sb':''; - $(columndiv).append('
'); + $(columndiv).append('
'); var myIndex = myBlockNumbering++; var myblockselector = '#'+blockIndex; @@ -377,6 +378,10 @@ function handleStringBlock(block, columndiv, width, c) { getNews(columndiv, block, blocks[block]['feed']); return; } + if (block.substring(0, 6) === 'graph_') { + $(columndiv).append('
'); + return; + } $(columndiv).append('
'); return; } @@ -600,6 +605,8 @@ function getBlockClick(idx, device) { || device['Type'] == 'Temp + Humidity' || device['Type'] == 'Temp + Humidity + Baro' || device['SubType'] == 'kWh' || device['SubType'] === 'Lux' || device['SubType'] === 'Solar Radiation' ) { + /* In this case we want to the popup graph + getButtonGraphs(device); if ($('.block_' + idx).length > 0) { $('.block_' + idx).addClass('hover'); @@ -609,7 +616,23 @@ function getBlockClick(idx, device) { $('.block_' + device['idx']).addClass('hover'); $('.block_' + device['idx']).attr('data-toggle', 'modal'); $('.block_' + device['idx']).attr('data-target', '#opengraph' + device['idx']); + } */ +// console.log('idx '+idx+'device[idx] '+device['idx']); + var blockSel = '.block_' + idx; + if ($(blockSel).length == 0) { + blockSel = 0; + } + if(blockSel == 0) { + blockSel = '.block_' + device['idx']; + if ($(blockSel).length == 0) { + blockSel = 0 + } + } + if(blockSel !== 0) { + $(blockSel).addClass('hover'); + $(blockSel).attr('onclick', 'showPopupGraph(\'' + device['idx'] + '\',\'' + idx + '\');'); } + } } } diff --git a/js/graphs.js b/js/graphs.js index 8eea081d..1a461dfb 100644 --- a/js/graphs.js +++ b/js/graphs.js @@ -1,4 +1,7 @@ +var dtGraphs = []; + function getGraphs(device, popup) { + moment.locale(settings['calendarlanguage']); var sensor = 'counter'; var txtUnit = '?'; var currentValue = device['Data']; @@ -42,22 +45,22 @@ function getGraphs(device, popup) { case 'RFXMeter': txtUnit = device['CounterToday'].split(' ')[1]; currentValue = device['CounterToday'].split(' ')[0]; - switch (device['SwitchTypeVal']) { - case 0: //Energy - break; - case 1: //Gas - break; - case 2: //Water - decimals = 0; - break; - case 3: //Counter - break; - case 4: //Energy generated - break; - case 5: //Time - break; - } - break; + switch (device['SwitchTypeVal']) { + case 0: //Energy + break; + case 1: //Gas + break; + case 2: //Water + decimals = 0; + break; + case 3: //Counter + break; + case 4: //Energy generated + break; + case 5: //Time + break; + } + break; case 'Air Quality': sensor = 'counter'; txtUnit = 'ppm'; @@ -82,7 +85,7 @@ function getGraphs(device, popup) { case 'Electric': txtUnit = 'Watt'; break; - case 'Energy': + case 'Energy': case 'kWh': case 'YouLess counter': txtUnit = 'kWh'; @@ -105,10 +108,10 @@ function getGraphs(device, popup) { case 'Leaf Wetness': txtUnit = 'Range'; break; - case 'A/D': + case 'A/D': txtUnit = 'mV'; break; - case 'Voltage': + case 'Voltage': case 'VoltageGeneral': txtUnit = 'V'; break; @@ -120,7 +123,7 @@ function getGraphs(device, popup) { txtUnit = 'dB'; break; case 'CurrentGeneral': - case 'CM113, Electrisave': + case 'CM113, Electrisave': case 'Current': txtUnit = 'A'; break; @@ -136,305 +139,634 @@ function getGraphs(device, popup) { currentValue = device['CounterToday'].split(' ')[0]; break; } + currentValue = number_format(currentValue, decimals); - showGraph(device['idx'], device['Name'], txtUnit, 'initial', currentValue, false, sensor, popup); + var graphIdx = device.idx; + if (popup) graphIdx += 'p'; + if (typeof dtGraphs[graphIdx] == 'undefined') { + dtGraphs[graphIdx] = { + idx: device.idx, + title: device.Name, + type: device.Type, + subtype: device.SubType, + sensor: sensor, + txtUnit: txtUnit, + currentValue: currentValue, + decimals: decimals, + popup: popup, + range: 'initial', + lastRefreshTime: 0, + forced: false, + graphIdx: graphIdx + // forced: false + } + } + dtGraphs[graphIdx].currentValue = currentValue; + showGraph(graphIdx); } function getGraphByIDX(idx) { getGraphs(alldevices[idx], true); } -function getButtonGraphs(device) { +function showPopupGraph(idx, subidx) { + var device = alldevices[idx]; if ($('#opengraph' + device['idx']).length === 0) { - var html = '