Merge PR #916: Unified energy charts
This commit is contained in:
commit
459a3ad595
@ -294,5 +294,9 @@
|
|||||||
<file>ui/images/sensors/o3.svg</file>
|
<file>ui/images/sensors/o3.svg</file>
|
||||||
<file>ui/images/sensors/pm10.svg</file>
|
<file>ui/images/sensors/pm10.svg</file>
|
||||||
<file>ui/images/sensors/no2.svg</file>
|
<file>ui/images/sensors/no2.svg</file>
|
||||||
|
<file>ui/images/power-grid.svg</file>
|
||||||
|
<file>ui/images/arrow-up.svg</file>
|
||||||
|
<file>ui/images/plus.svg</file>
|
||||||
|
<file>ui/images/minus.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -252,7 +252,6 @@
|
|||||||
<file>ui/devicepages/CoolingThingPage.qml</file>
|
<file>ui/devicepages/CoolingThingPage.qml</file>
|
||||||
<file>ui/devicepages/EvChargerThingPage.qml</file>
|
<file>ui/devicepages/EvChargerThingPage.qml</file>
|
||||||
<file>ui/components/NymeaSpinBox.qml</file>
|
<file>ui/components/NymeaSpinBox.qml</file>
|
||||||
<file>ui/mainviews/EnergyPieChartDelegate.qml</file>
|
|
||||||
<file>ui/mainviews/energy/PowerConsumptionBalanceHistory.qml</file>
|
<file>ui/mainviews/energy/PowerConsumptionBalanceHistory.qml</file>
|
||||||
<file>ui/mainviews/energy/PowerProductionBalanceHistory.qml</file>
|
<file>ui/mainviews/energy/PowerProductionBalanceHistory.qml</file>
|
||||||
<file>ui/mainviews/energy/ConsumersBarChart.qml</file>
|
<file>ui/mainviews/energy/ConsumersBarChart.qml</file>
|
||||||
@ -279,5 +278,7 @@
|
|||||||
<file>ui/components/ActivityIndicator.qml</file>
|
<file>ui/components/ActivityIndicator.qml</file>
|
||||||
<file>ui/system/zigbee/ZigbeeNodePage.qml</file>
|
<file>ui/system/zigbee/ZigbeeNodePage.qml</file>
|
||||||
<file>ui/utils/AirQualityIndex.qml</file>
|
<file>ui/utils/AirQualityIndex.qml</file>
|
||||||
|
<file>ui/mainviews/energy/PowerBalanceHistory.qml</file>
|
||||||
|
<file>ui/mainviews/energy/CurrentPowerBalancePieChart.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
165
nymea-app/ui/images/arrow-up.svg
Normal file
165
nymea-app/ui/images/arrow-up.svg
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="arrow-up.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4.3838822"
|
||||||
|
inkscape:cx="27.715161"
|
||||||
|
inkscape:cy="46.305989"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g4780"
|
||||||
|
showgrid="true"
|
||||||
|
showborder="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:window-width="1466"
|
||||||
|
inkscape:window-height="933"
|
||||||
|
inkscape:window-x="70"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid5451"
|
||||||
|
empspacing="8" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="8,-8.0000001"
|
||||||
|
id="guide4063" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="4,-8.0000001"
|
||||||
|
id="guide4065" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,88.000001"
|
||||||
|
id="guide4067" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,92.000001"
|
||||||
|
id="guide4069" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,8.0000001"
|
||||||
|
id="guide4073" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="92,-8.0000001"
|
||||||
|
id="guide4075" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="88,-8.0000001"
|
||||||
|
id="guide4077" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,84.000001"
|
||||||
|
id="guide4074" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="12,-8.0000001"
|
||||||
|
id="guide4076" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,12"
|
||||||
|
id="guide4078" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="84,-9.0000001"
|
||||||
|
id="guide4080" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="48,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4170" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="-8,48"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide4172" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(67.857146,-78.50504)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||||
|
id="g4845"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="next01.png"
|
||||||
|
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||||
|
id="g4778"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||||
|
id="g4780"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 352.96882,383.36222 h 32.01266 v -13.625 c 0,0 24.94685,11.15391 42.01662,23.62305 -17.06977,12.46913 -42.01662,23.62695 -42.01662,23.62695 v -13.625 h -32.01266 z m 4.00158,4 v 12 h 32.01266 v 11.21289 c 5.98966,-2.82047 18.03813,-8.81417 30.68011,-17.21484 -12.64206,-8.40027 -24.69078,-14.39149 -30.68011,-17.21094 v 11.21289 z"
|
||||||
|
id="path4179"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cccccccccccccccc" />
|
||||||
|
<rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||||
|
id="rect4782"
|
||||||
|
width="96.037987"
|
||||||
|
height="96"
|
||||||
|
x="-438.00244"
|
||||||
|
y="345.36221"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.1 KiB |
167
nymea-app/ui/images/minus.svg
Normal file
167
nymea-app/ui/images/minus.svg
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="minus.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="6.992261"
|
||||||
|
inkscape:cx="44.120207"
|
||||||
|
inkscape:cy="53.05866"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g4780"
|
||||||
|
showgrid="true"
|
||||||
|
showborder="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:window-width="1466"
|
||||||
|
inkscape:window-height="933"
|
||||||
|
inkscape:window-x="70"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid5451"
|
||||||
|
empspacing="8" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="8,-8.0000001"
|
||||||
|
id="guide4063" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="4,-8.0000001"
|
||||||
|
id="guide4065" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,88.000001"
|
||||||
|
id="guide4067" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,92.000001"
|
||||||
|
id="guide4069" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="92,-8.0000001"
|
||||||
|
id="guide4075" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="88,-8.0000001"
|
||||||
|
id="guide4077" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,84.000001"
|
||||||
|
id="guide4074" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="12,-8.0000001"
|
||||||
|
id="guide4076" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,12"
|
||||||
|
id="guide4078" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="84,-9.0000001"
|
||||||
|
id="guide4080" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="48,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4170" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="64,40"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide4172" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(67.857146,-78.50504)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||||
|
id="g4845"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="next01.png"
|
||||||
|
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||||
|
id="g4778"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||||
|
id="g4780"
|
||||||
|
style="display:inline">
|
||||||
|
<rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||||
|
id="rect4782"
|
||||||
|
width="96.037987"
|
||||||
|
height="96"
|
||||||
|
x="-438.00244"
|
||||||
|
y="345.36221"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 379.83753,393.36222 v -36 h 20.00792 v 36 h -4.00159 v -32 h -12.00474 v 32 z"
|
||||||
|
id="path1322"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 379.83753,393.36222 v 36 h 20.00792 v -36 h -4.00159 v 32 h -12.00474 v -32 z"
|
||||||
|
id="path1426"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.2 KiB |
179
nymea-app/ui/images/plus.svg
Normal file
179
nymea-app/ui/images/plus.svg
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="plus.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="6.992261"
|
||||||
|
inkscape:cx="44.120207"
|
||||||
|
inkscape:cy="53.05866"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g4780"
|
||||||
|
showgrid="true"
|
||||||
|
showborder="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:window-width="1466"
|
||||||
|
inkscape:window-height="933"
|
||||||
|
inkscape:window-x="70"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid5451"
|
||||||
|
empspacing="8" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="8,-8.0000001"
|
||||||
|
id="guide4063" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="4,-8.0000001"
|
||||||
|
id="guide4065" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,88.000001"
|
||||||
|
id="guide4067" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,92.000001"
|
||||||
|
id="guide4069" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="92,-8.0000001"
|
||||||
|
id="guide4075" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="88,-8.0000001"
|
||||||
|
id="guide4077" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,84.000001"
|
||||||
|
id="guide4074" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="12,-8.0000001"
|
||||||
|
id="guide4076" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,12"
|
||||||
|
id="guide4078" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="84,-9.0000001"
|
||||||
|
id="guide4080" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="48,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4170" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="64,40"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide4172" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(67.857146,-78.50504)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||||
|
id="g4845"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="next01.png"
|
||||||
|
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||||
|
id="g4778"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||||
|
id="g4780"
|
||||||
|
style="display:inline">
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 396.12781,383.36222 h 30.01187 v 20 h -30.01187 v -4 h 26.01029 v -12 h -26.01029 z"
|
||||||
|
id="path4179"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
<rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||||
|
id="rect4782"
|
||||||
|
width="96.037987"
|
||||||
|
height="96"
|
||||||
|
x="-438.00244"
|
||||||
|
y="345.36221"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 383.98,383.36222 h -30.01187 v 20 H 383.98 v -4 h -26.01029 v -12 H 383.98 Z"
|
||||||
|
id="path1320"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 379.83753,387.36222 v -30 h 20.00792 v 30 h -4.00159 v -26 h -12.00474 v 26 z"
|
||||||
|
id="path1322"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 379.83753,399.36222 v 30 h 20.00792 v -30 h -4.00159 v 26 h -12.00474 v -26 z"
|
||||||
|
id="path1426"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccccccccc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.1 KiB |
174
nymea-app/ui/images/power-grid.svg
Normal file
174
nymea-app/ui/images/power-grid.svg
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="power-grid.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="3.6036911"
|
||||||
|
inkscape:cx="65.072169"
|
||||||
|
inkscape:cy="44.676415"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="g4780"
|
||||||
|
showgrid="true"
|
||||||
|
showborder="true"
|
||||||
|
fit-margin-top="0"
|
||||||
|
fit-margin-left="0"
|
||||||
|
fit-margin-right="0"
|
||||||
|
fit-margin-bottom="0"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-nodes="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
inkscape:snap-global="true"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:window-width="1466"
|
||||||
|
inkscape:window-height="933"
|
||||||
|
inkscape:window-x="70"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid5451"
|
||||||
|
empspacing="8" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="8,-8.0000001"
|
||||||
|
id="guide4063" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="4,-8.0000001"
|
||||||
|
id="guide4065" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,88.000001"
|
||||||
|
id="guide4067" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,92.000001"
|
||||||
|
id="guide4069" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="104,4"
|
||||||
|
id="guide4071" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-5,8.0000001"
|
||||||
|
id="guide4073" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="88,-8.0000001"
|
||||||
|
id="guide4077" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="0,1"
|
||||||
|
position="-8,84.000001"
|
||||||
|
id="guide4074" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="12,-8.0000001"
|
||||||
|
id="guide4076" />
|
||||||
|
<sodipodi:guide
|
||||||
|
orientation="1,0"
|
||||||
|
position="84,-8.0000001"
|
||||||
|
id="guide4080" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="48,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4170" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="-8,48"
|
||||||
|
orientation="0,1"
|
||||||
|
id="guide4172" />
|
||||||
|
<sodipodi:guide
|
||||||
|
position="92,-8.0000001"
|
||||||
|
orientation="1,0"
|
||||||
|
id="guide4760" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata4879">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1"
|
||||||
|
transform="translate(67.857146,-78.50504)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||||
|
id="g4845"
|
||||||
|
style="display:inline">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="next01.png"
|
||||||
|
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||||
|
id="g4778"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||||
|
id="g4780"
|
||||||
|
style="display:inline">
|
||||||
|
<rect
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||||
|
id="rect4782"
|
||||||
|
width="96.037987"
|
||||||
|
height="96"
|
||||||
|
x="-438.00244"
|
||||||
|
y="345.36221"
|
||||||
|
transform="scale(-1,1)" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;enable-background:accumulate"
|
||||||
|
d="m 48.021484,8 0.002,0.00195 L 48.025391,8 Z m 7.802479,31.371037 c 1.56537,4.861206 10.147898,32.323098 12.076428,40.306639 -6.89531,-4.233055 -13.382787,-8.54967 -17.597657,-11.607422 l -2.345703,-1.699218 -2.349609,1.695312 c -4.13788,2.989737 -10.589945,7.26902 -17.583984,11.56836 1.89561,-7.866339 10.501857,-35.372181 12.107677,-40.326171 l -3.804688,-1.232364 c -2.255209,6.957347 -12.221108,38.502504 -14.351818,49.882811 0.003,0.002 0.0048,0.003 0.0098,0 0.006,0.003 0.0088,-0.0029 0.01172,-0.0039 0.007,0.001 0.01177,-9.53e-4 0.01367,-0.002 0.007,10e-4 0.0068,10e-4 0.0098,0 10.47791,-5.811711 20.148604,-12.464715 25.933594,-16.644531 5.92015,4.29487 15.830301,11.150802 25.994141,16.693359 0.003,-0.002 0.003,-0.0066 0.002,-0.01172 0.004,-0.004 0.002,-0.01077 0.002,-0.01367 0.003,-0.006 0.002,-0.0098 0.002,-0.01172 0.003,-0.006 0.0059,-0.0076 0.0059,-0.01172 C 71.669804,76.191995 61.820387,44.939924 59.632807,38.146442 Z m 34.221209,-0.787096 c -10e-4,-0.003 -0.0018,-0.0049 -0.0078,-0.0059 -0.003,-0.006 -0.0087,-0.0068 -0.01172,-0.0078 -0.004,-0.004 -0.01197,-0.0049 -0.01367,-0.0059 -0.004,-0.004 -0.0028,-0.0078 -0.0078,-0.0098 C 78.111466,37.097764 66.377304,36.800063 59.240234,36.78125 56.975133,29.827029 52.986923,18.457674 48.023438,8.0019531 c -0.0028,4.814e-4 -0.0063,0.00114 -0.0078,0.00586 -0.007,9.996e-4 -0.0078,0.00481 -0.0098,0.00781 -0.006,0.003 -0.0068,0.00872 -0.0078,0.011719 -0.006,0.003 -0.0068,0.00186 -0.0098,0.00586 -5.06033,10.8599829 -8.970109,21.9291509 -11.193359,28.7109379 -7.31383,0.006 -19.360537,0.283237 -30.841797,1.773437 l 9.785199,3.179689 c 8.066,-0.627982 15.850764,-0.951078 21.058594,-0.955078 l 2.896484,-0.002 0.902344,-2.751953 c 1.5904,-4.85137 4.294971,-12.105985 7.425781,-19.695312 3.08882,7.474003 5.801783,14.774656 7.414063,19.724609 l 0.896484,2.75586 2.896485,0.0078 c 5.1081,0.01346 12.847529,0.343693 21.037109,0.976562 z"
|
||||||
|
transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
|
||||||
|
id="path4170"
|
||||||
|
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#808080;stroke-width:4.00079123;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 405.98979,400.36222 -16.00633,-20"
|
||||||
|
id="path2355" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#808080;stroke-width:4.00079123;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
d="m 405.98979,386.36222 -16.00633,20"
|
||||||
|
id="path2357" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 7.3 KiB |
@ -108,37 +108,58 @@ MainViewBase {
|
|||||||
id: energyGrid
|
id: energyGrid
|
||||||
width: parent.width
|
width: parent.width
|
||||||
property int rawColumns: Math.floor(flickable.width / 300)
|
property int rawColumns: Math.floor(flickable.width / 300)
|
||||||
columns: Math.max(1, rawColumns - (rawColumns % 2))
|
columns: Math.min(3, Math.max(1, rawColumns /*- (rawColumns % 2)*/))
|
||||||
rowSpacing: 0
|
rowSpacing: 0
|
||||||
columnSpacing: 0
|
columnSpacing: 0
|
||||||
|
|
||||||
|
|
||||||
CurrentConsumptionBalancePieChart {
|
// CurrentConsumptionBalancePieChart {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// Layout.preferredHeight: width
|
||||||
|
// energyManager: energyManager
|
||||||
|
// visible: producers.count > 0
|
||||||
|
// animationsEnabled: Qt.application.active && root.isCurrentItem
|
||||||
|
// }
|
||||||
|
// CurrentProductionBalancePieChart {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// Layout.preferredHeight: width
|
||||||
|
// energyManager: energyManager
|
||||||
|
// visible: producers.count > 0
|
||||||
|
// animationsEnabled: Qt.application.active && root.isCurrentItem
|
||||||
|
// }
|
||||||
|
CurrentPowerBalancePieChart {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
Layout.preferredHeight: width
|
||||||
energyManager: energyManager
|
energyManager: energyManager
|
||||||
visible: producers.count > 0
|
visible: rootMeter != null || producers.count > 0
|
||||||
animationsEnabled: Qt.application.active && root.isCurrentItem
|
animationsEnabled: Qt.application.active && root.isCurrentItem
|
||||||
}
|
}
|
||||||
CurrentProductionBalancePieChart {
|
|
||||||
|
PowerBalanceHistory {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: width
|
||||||
|
visible: rootMeter != null || producers.count > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
PowerBalanceStats {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
Layout.preferredHeight: width
|
||||||
energyManager: energyManager
|
energyManager: energyManager
|
||||||
visible: producers.count > 0
|
visible: rootMeter != null || producers.count > 0
|
||||||
animationsEnabled: Qt.application.active && root.isCurrentItem
|
producers: producers
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerConsumptionBalanceHistory {
|
// PowerConsumptionBalanceHistory {
|
||||||
Layout.fillWidth: true
|
// Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
// Layout.preferredHeight: width
|
||||||
visible: producers.count > 0
|
// visible: producers.count > 0
|
||||||
}
|
// }
|
||||||
|
|
||||||
PowerProductionBalanceHistory {
|
// PowerProductionBalanceHistory {
|
||||||
Layout.fillWidth: true
|
// Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
// Layout.preferredHeight: width
|
||||||
visible: producers.count > 0
|
// visible: producers.count > 0
|
||||||
}
|
// }
|
||||||
|
|
||||||
ConsumersPieChart {
|
ConsumersPieChart {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@ -153,19 +174,11 @@ MainViewBase {
|
|||||||
ConsumersHistory {
|
ConsumersHistory {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
Layout.preferredHeight: width
|
||||||
visible: consumers.count > 0 || rootMeter != null
|
visible: consumers.count > 0
|
||||||
colors: root.thingColors
|
colors: root.thingColors
|
||||||
consumers: consumers
|
consumers: consumers
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerBalanceStats {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: width
|
|
||||||
energyManager: energyManager
|
|
||||||
visible: rootMeter != null || producers.count > 0
|
|
||||||
producers: producers
|
|
||||||
}
|
|
||||||
|
|
||||||
ConsumerStats {
|
ConsumerStats {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width
|
Layout.preferredHeight: width
|
||||||
|
|||||||
@ -160,12 +160,12 @@ StatsBase {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
// Label {
|
||||||
Layout.fillWidth: true
|
// Layout.fillWidth: true
|
||||||
Layout.margins: Style.smallMargins
|
// Layout.margins: Style.smallMargins
|
||||||
horizontalAlignment: Text.AlignHCenter
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
text: qsTr("Consumers totals")
|
// text: qsTr("Consumers totals")
|
||||||
}
|
// }
|
||||||
|
|
||||||
SelectionTabs {
|
SelectionTabs {
|
||||||
id: selectionTabs
|
id: selectionTabs
|
||||||
@ -207,9 +207,10 @@ StatsBase {
|
|||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
// margins.left: 0
|
// margins.left: 0
|
||||||
margins.right: 0
|
margins.right: 0
|
||||||
margins.bottom: 0
|
|
||||||
margins.top: 0
|
margins.top: 0
|
||||||
|
margins.bottom: Style.smallIconSize + Style.margins
|
||||||
|
|
||||||
|
legend.visible: false
|
||||||
legend.alignment: Qt.AlignBottom
|
legend.alignment: Qt.AlignBottom
|
||||||
legend.font: Style.extraSmallFont
|
legend.font: Style.extraSmallFont
|
||||||
legend.labelColor: Style.foregroundColor
|
legend.labelColor: Style.foregroundColor
|
||||||
@ -309,6 +310,29 @@ StatsBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||||
|
anchors.leftMargin: chartView.plotArea.x
|
||||||
|
height: Style.smallIconSize
|
||||||
|
anchors.margins: Style.margins
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.consumers
|
||||||
|
delegate: Item {
|
||||||
|
id: legendDelegate
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
readonly property Thing thing: root.consumers.get(index)
|
||||||
|
ColorIcon {
|
||||||
|
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: chartView.x + chartView.plotArea.x
|
anchors.leftMargin: chartView.x + chartView.plotArea.x
|
||||||
|
|||||||
@ -111,12 +111,12 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
// Label {
|
||||||
Layout.fillWidth: true
|
// Layout.fillWidth: true
|
||||||
Layout.margins: Style.smallMargins
|
// Layout.margins: Style.smallMargins
|
||||||
horizontalAlignment: Text.AlignHCenter
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
text: qsTr("Consumers history")
|
// text: qsTr("Consumers history")
|
||||||
}
|
// }
|
||||||
|
|
||||||
SelectionTabs {
|
SelectionTabs {
|
||||||
id: selectionTabs
|
id: selectionTabs
|
||||||
@ -186,9 +186,10 @@ Item {
|
|||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
margins.left: 0
|
margins.left: 0
|
||||||
margins.right: 0
|
margins.right: 0
|
||||||
margins.bottom: 0
|
|
||||||
margins.top: 0
|
margins.top: 0
|
||||||
|
margins.bottom: Style.smallIconSize + Style.margins
|
||||||
|
|
||||||
|
legend.visible: false
|
||||||
legend.alignment: Qt.AlignBottom
|
legend.alignment: Qt.AlignBottom
|
||||||
legend.font: Style.extraSmallFont
|
legend.font: Style.extraSmallFont
|
||||||
legend.labelColor: Style.foregroundColor
|
legend.labelColor: Style.foregroundColor
|
||||||
@ -470,6 +471,31 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||||
|
anchors.leftMargin: chartView.plotArea.x
|
||||||
|
height: Style.smallIconSize
|
||||||
|
anchors.margins: Style.margins
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.consumers
|
||||||
|
delegate: Item {
|
||||||
|
id: legendDelegate
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
readonly property Thing thing: root.consumers.get(index)
|
||||||
|
ColorIcon {
|
||||||
|
name: app.interfacesToIcon(legendDelegate.thing.thingClass.interfaces)
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: index >= 0 ? NymeaUtils.generateColor(Style.generationBaseColor, index) : "white"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@ -11,7 +11,7 @@ ChartView {
|
|||||||
id: root
|
id: root
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
title: qsTr("Consumers balance")
|
// title: qsTr("Consumers balance")
|
||||||
titleColor: Style.foregroundColor
|
titleColor: Style.foregroundColor
|
||||||
legend.visible: false
|
legend.visible: false
|
||||||
|
|
||||||
@ -66,6 +66,7 @@ ChartView {
|
|||||||
id: d
|
id: d
|
||||||
property var thingsColorMap: ({})
|
property var thingsColorMap: ({})
|
||||||
property PieSlice unknownSlice: null
|
property PieSlice unknownSlice: null
|
||||||
|
property PieSlice idleSlice: null
|
||||||
|
|
||||||
property double consumersSummation: 0
|
property double consumersSummation: 0
|
||||||
}
|
}
|
||||||
@ -73,6 +74,9 @@ ChartView {
|
|||||||
function updateConsumers() {
|
function updateConsumers() {
|
||||||
root.animationOptions = ChartView.NoAnimation
|
root.animationOptions = ChartView.NoAnimation
|
||||||
consumersBalanceSeries.clear();
|
consumersBalanceSeries.clear();
|
||||||
|
d.unknownSlice = null
|
||||||
|
d.idleSlice = null
|
||||||
|
print("cleared consumers pie chart")
|
||||||
|
|
||||||
if (engine.thingManager.fetchingData) {
|
if (engine.thingManager.fetchingData) {
|
||||||
return;
|
return;
|
||||||
@ -102,6 +106,11 @@ ChartView {
|
|||||||
d.unknownSlice.color = Style.gray
|
d.unknownSlice.color = Style.gray
|
||||||
d.unknownSlice.borderColor = Style.gray
|
d.unknownSlice.borderColor = Style.gray
|
||||||
d.unknownSlice.borderWidth = 0
|
d.unknownSlice.borderWidth = 0
|
||||||
|
} else {
|
||||||
|
d.idleSlice = consumersBalanceSeries.append(qsTr(""), 0.00001)
|
||||||
|
d.idleSlice.color = Style.tooltipBackgroundColor
|
||||||
|
d.idleSlice.borderColor = d.idleSlice.color
|
||||||
|
d.idleSlice.borderWidth = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
d.thingsColorMap = colorMap
|
d.thingsColorMap = colorMap
|
||||||
|
|||||||
867
nymea-app/ui/mainviews/energy/CurrentPowerBalancePieChart.qml
Normal file
867
nymea-app/ui/mainviews/energy/CurrentPowerBalancePieChart.qml
Normal file
@ -0,0 +1,867 @@
|
|||||||
|
import QtQuick 2.8
|
||||||
|
import QtQuick.Controls 2.1
|
||||||
|
import QtQuick.Controls.Material 2.1
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
import QtCharts 2.2
|
||||||
|
import Nymea 1.0
|
||||||
|
import "qrc:/ui/components"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool animationsEnabled: false
|
||||||
|
property EnergyManager energyManager: null
|
||||||
|
|
||||||
|
readonly property double fromGrid: Math.max(0, energyManager.currentPowerAcquisition)
|
||||||
|
readonly property double fromStorage: -Math.min(0, energyManager.currentPowerStorage)
|
||||||
|
readonly property double toStorage: -Math.min(0, -energyManager.currentPowerStorage)
|
||||||
|
readonly property double fromProduction: energyManager.currentPowerConsumption - fromGrid - fromStorage
|
||||||
|
readonly property double toGrid: Math.max(0, - energyManager.currentPowerAcquisition)
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
function formatValue(value) {
|
||||||
|
var ret
|
||||||
|
if (value >= 1000) {
|
||||||
|
ret = (value / 1000).toFixed(1) + "kW"
|
||||||
|
} else {
|
||||||
|
ret = value.toFixed(1) + "W"
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
property double progress: 0
|
||||||
|
onProgressChanged: canvas.requestPaint()
|
||||||
|
|
||||||
|
property int chartSize: width / 2.5
|
||||||
|
|
||||||
|
property point acquisitionPos: Qt.point(chartSize/2 + Style.margins, chartSize/2 + Style.margins)
|
||||||
|
property point productionPos: Qt.point(root.width - (chartSize/2 + Style.margins), chartSize/2 + Style.margins)
|
||||||
|
property point storagePos: Qt.point(chartSize/2 + Style.margins, root.height - (chartSize/2 + Style.margins))
|
||||||
|
property point consumptionPos: batteries.count > 0 || producers.count === 0
|
||||||
|
? Qt.point(root.width - (chartSize/2 + Style.margins), root.height - (chartSize/2 + Style.margins))
|
||||||
|
: Qt.point(root.width / 2, root.height - (chartSize/2 + Style.margins))
|
||||||
|
}
|
||||||
|
|
||||||
|
ThingsProxy {
|
||||||
|
id: batteries
|
||||||
|
engine: _engine
|
||||||
|
shownInterfaces: ["energystorage"]
|
||||||
|
}
|
||||||
|
ThingsProxy {
|
||||||
|
id: producers
|
||||||
|
engine: _engine
|
||||||
|
shownInterfaces: ["smartmeterproducer"]
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberAnimation {
|
||||||
|
id: progressAnimation
|
||||||
|
target: d
|
||||||
|
property: "progress"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
running: root.animationsEnabled
|
||||||
|
loops: Animation.Infinite
|
||||||
|
duration: 5000
|
||||||
|
}
|
||||||
|
|
||||||
|
Canvas {
|
||||||
|
id: canvas
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
onPaint: {
|
||||||
|
var ctx = getContext("2d");
|
||||||
|
|
||||||
|
var solarPos = Qt.point(d.productionPos.x - width / 2, d.productionPos.y - height / 2)
|
||||||
|
var storagePos = Qt.point(d.storagePos.x - width / 2, d.storagePos.y - width / 2)
|
||||||
|
var consumptionPos = Qt.point(d.consumptionPos.x - width / 2, d.consumptionPos.y - height / 2)
|
||||||
|
var gridPos = Qt.point(d.acquisitionPos.x - width / 2, d.acquisitionPos.y - height / 2)
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.reset()
|
||||||
|
|
||||||
|
ctx.translate(width / 2, height / 2);
|
||||||
|
|
||||||
|
ctx.strokeStyle = Style.foregroundColor
|
||||||
|
ctx.fillStyle = Style.foregroundColor
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
|
||||||
|
var biggest = Math.max(
|
||||||
|
Math.abs(energyManager.currentPowerAcquisition),
|
||||||
|
Math.abs(energyManager.currentPowerConsumption),
|
||||||
|
Math.abs(energyManager.currentPowerProduction),
|
||||||
|
Math.abs(energyManager.currentPowerStorage)
|
||||||
|
)
|
||||||
|
var size
|
||||||
|
|
||||||
|
|
||||||
|
if (root.toGrid > 0) {
|
||||||
|
size = root.toGrid / biggest
|
||||||
|
drawDottedCurve(ctx, solarPos, gridPos, size, Style.yellow)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (energyManager.currentPowerProduction < 0 && root.fromProduction) {
|
||||||
|
size = root.fromProduction / biggest
|
||||||
|
drawDottedCurve(ctx, solarPos, consumptionPos, size, Style.green)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batteries.count > 0) {
|
||||||
|
if (energyManager.currentPowerStorage > 0) {
|
||||||
|
if (energyManager.currentPowerProduction < 0) {
|
||||||
|
size = Math.abs(energyManager.currentPowerStorage) / biggest
|
||||||
|
drawDottedCurve(ctx, solarPos, storagePos, size, Style.purple)
|
||||||
|
} else {
|
||||||
|
size = Math.abs(energyManager.currentPowerStorage) / biggest
|
||||||
|
drawDottedCurve(ctx, gridPos, storagePos, size, Style.purple)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (energyManager.currentPowerStorage < 0) {
|
||||||
|
size = Math.abs(energyManager.currentPowerStorage) / biggest
|
||||||
|
drawDottedCurve(ctx, storagePos, consumptionPos, size, Style.orange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (energyManager.currentPowerAcquisition > 0) {
|
||||||
|
size = Math.abs(energyManager.currentPowerAcquisition) / biggest
|
||||||
|
drawDottedCurve(ctx, gridPos, consumptionPos, size, Style.red)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bezierCurvePoint(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, t) {
|
||||||
|
var x = Math.pow(1-t, 3)*p0x + 3*Math.pow(1-t, 2)*t*p1x + 3*(1-t)*Math.pow(t, 2)*p2x + Math.pow(t, 3)*p3x;
|
||||||
|
var y = Math.pow(1-t, 3)*p0y + 3*Math.pow(1-t, 2)*t*p1y + 3*(1-t)*Math.pow(t, 2)*p2y + Math.pow(t, 3)*p3y;
|
||||||
|
return Qt.point(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
function circlePoint(center, radius, angle) {
|
||||||
|
var x = center.x + radius * Math.cos(angle * 2 * Math.PI / 360)
|
||||||
|
var y = center.y + radius * Math.sin(angle * 2 * Math.PI / 360)
|
||||||
|
return Qt.point(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawDottedCurve(ctx, start, end, size, color) {
|
||||||
|
var c1 = getControlPoint(start)
|
||||||
|
var c2 = getControlPoint(end)
|
||||||
|
ctx.fillStyle = color
|
||||||
|
ctx.strokeStyle = color
|
||||||
|
var count = 10;
|
||||||
|
for (var i = 1; i <= count; i++) {
|
||||||
|
var offset = 1 / count;
|
||||||
|
var progress = d.progress + i * offset
|
||||||
|
if (progress > 1)
|
||||||
|
progress -= 1
|
||||||
|
var point = bezierCurvePoint(start.x, start.y, c1.x, c1.y, c2.x, c2.y, end.x, end.y, progress)
|
||||||
|
// print("painting", d.progress, point.x, point.y)
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(point.x, point.y, Math.max(1, size * 5), 0, 2 *Math.PI)
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getControlPoint(point) {
|
||||||
|
return Qt.point(point.x * .1, point.y * .1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: acquisitionItem
|
||||||
|
x: d.acquisitionPos.x - width / 2
|
||||||
|
y: d.acquisitionPos.y - height / 2
|
||||||
|
width: d.chartSize
|
||||||
|
height: d.chartSize
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: acquisitionChart.plotArea.width
|
||||||
|
height: acquisitionChart.plotArea.height
|
||||||
|
color: Style.backgroundColor
|
||||||
|
radius: width / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: acquisitionChart.plotArea.width * 0.8
|
||||||
|
ColorIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
size: Style.bigIconSize
|
||||||
|
// color: Style.red
|
||||||
|
name: "/ui/images/power-grid.svg"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: d.formatValue(Math.abs(energyManager.currentPowerAcquisition))
|
||||||
|
// color: energyManager.currentPowerAcquisition >= 0 ? Style.red : Style.yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: acquisitionChart
|
||||||
|
anchors.fill: parent
|
||||||
|
legend.visible: false
|
||||||
|
margins { left: 0; top: 0; right: 0; bottom: 0 }
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
animationOptions: root.animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
|
|
||||||
|
PieSeries {
|
||||||
|
size: 1
|
||||||
|
holeSize: 0.8
|
||||||
|
|
||||||
|
PieSlice {
|
||||||
|
color: Style.red
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.fromGrid
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.yellow
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.toGrid
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.tooltipBackgroundColor
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: energyManager.currentPowerAcquisition == 0 ? 1 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: productionItem
|
||||||
|
x: d.productionPos.x - width / 2
|
||||||
|
y: d.productionPos.y - height / 2
|
||||||
|
width: d.chartSize
|
||||||
|
height: d.chartSize
|
||||||
|
visible: producers.count > 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: productionChart.plotArea.width
|
||||||
|
height: productionChart.plotArea.height
|
||||||
|
color: Style.backgroundColor
|
||||||
|
radius: width / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: productionChart.plotArea.width * 0.8
|
||||||
|
ColorIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
size: Style.bigIconSize
|
||||||
|
// color: Style.yellow
|
||||||
|
name: "/ui/images/weathericons/weather-clear-day.svg"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: d.formatValue(Math.abs(energyManager.currentPowerProduction))
|
||||||
|
// color: energyManager.currentPowerAcquisition >= 0 ? Style.red : Style.green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: productionChart
|
||||||
|
anchors.fill: parent
|
||||||
|
legend.visible: false
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
margins { left: 0; top: 0; right: 0; bottom: 0 }
|
||||||
|
animationOptions: root.animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
|
|
||||||
|
PieSeries {
|
||||||
|
size: 1
|
||||||
|
holeSize: 0.8
|
||||||
|
|
||||||
|
PieSlice {
|
||||||
|
color: Style.green
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.fromProduction
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.purple
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.toStorage
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.yellow
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.toGrid
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.tooltipBackgroundColor
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: energyManager.currentPowerProduction == 0 ? 1 : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: consumptionItem
|
||||||
|
x: d.consumptionPos.x - width / 2
|
||||||
|
y: d.consumptionPos.y - height / 2
|
||||||
|
width: d.chartSize
|
||||||
|
height: d.chartSize
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: consumptionChart.plotArea.width
|
||||||
|
height: consumptionChart.plotArea.height
|
||||||
|
color: Style.backgroundColor
|
||||||
|
radius: width / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: consumptionChart.plotArea.width * 0.8
|
||||||
|
ColorIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
size: Style.bigIconSize
|
||||||
|
// color: Style.blue
|
||||||
|
name: "/ui/images/powersocket.svg"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: d.formatValue(energyManager.currentPowerConsumption)
|
||||||
|
// color: energyManager.currentPowerAcquisition >= 0 ? Style.red : Style.green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: consumptionChart
|
||||||
|
anchors.fill: parent
|
||||||
|
margins { left: 0; top: 0; right: 0; bottom: 0 }
|
||||||
|
legend.visible: false
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
animationOptions: root.animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
|
|
||||||
|
PieSeries {
|
||||||
|
size: 1
|
||||||
|
holeSize: 0.8
|
||||||
|
|
||||||
|
PieSlice {
|
||||||
|
color: Style.red
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.fromGrid
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.green
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.fromProduction
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.orange
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: root.fromStorage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: batteryItem
|
||||||
|
x: d.storagePos.x - width / 2
|
||||||
|
y: d.storagePos.y - height / 2
|
||||||
|
width: d.chartSize
|
||||||
|
height: d.chartSize
|
||||||
|
visible: batteries.count > 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: batteryChart.plotArea.width
|
||||||
|
height: batteryChart.plotArea.height
|
||||||
|
color: Style.backgroundColor
|
||||||
|
radius: width / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: productionChart.plotArea.width * 0.8
|
||||||
|
ColorIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
size: Style.bigIconSize
|
||||||
|
// color: Style.purple
|
||||||
|
name: "/ui/images/battery/battery-" + NymeaUtils.pad(Math.round(batteryChart.averageLevel / 10) * 10, 3) + ".svg"
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: d.formatValue(Math.abs(energyManager.currentPowerStorage))
|
||||||
|
// color: energyManager.currentPowerStorage >= 0 ? Style.green : Style.red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
y: batteryChart.y + batteryChart.plotArea.height * .2
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
font: Style.smallFont
|
||||||
|
text: batteryChart.averageLevel + "%"
|
||||||
|
// color: energyManager.currentPowerStorage >= 0 ? Style.green : Style.red
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: batteryChart
|
||||||
|
anchors.fill: parent
|
||||||
|
margins { left: 0; top: 0; right: 0; bottom: 0 }
|
||||||
|
legend.visible: false
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
animationOptions: root.animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
|
|
||||||
|
property double totalCapacity: {
|
||||||
|
var totalCapacity = 0;
|
||||||
|
for (var i = 0; i < batteriesRepeater.count; i++) {
|
||||||
|
totalCapacity += batteriesRepeater.itemAt(i).capacityState.value
|
||||||
|
}
|
||||||
|
return totalCapacity;
|
||||||
|
}
|
||||||
|
property double averageLevel: {
|
||||||
|
if (batteriesRepeater.count == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var averageLevel = 0;
|
||||||
|
for (var i = 0; i < batteriesRepeater.count; i++) {
|
||||||
|
averageLevel += batteriesRepeater.itemAt(i).batteryLevelState.value
|
||||||
|
}
|
||||||
|
averageLevel /= batteriesRepeater.count
|
||||||
|
return averageLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: batteriesRepeater
|
||||||
|
model: batteries
|
||||||
|
delegate: Item {
|
||||||
|
property Thing thing: batteries.get(index)
|
||||||
|
property State batteryLevelState: thing.stateByName("batteryLevel")
|
||||||
|
property State capacityState: thing.stateByName("capacity")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PieSeries {
|
||||||
|
id: batterySeries
|
||||||
|
size: 1
|
||||||
|
holeSize: 0.8
|
||||||
|
|
||||||
|
PieSlice {
|
||||||
|
color: energyManager.currentPowerStorage == 0
|
||||||
|
? Style.foregroundColor
|
||||||
|
: root.toStorage > 0
|
||||||
|
? Style.purple
|
||||||
|
: Style.orange
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: batteryChart.averageLevel
|
||||||
|
}
|
||||||
|
PieSlice {
|
||||||
|
color: Style.tooltipBackgroundColor
|
||||||
|
borderColor: color
|
||||||
|
borderWidth: 0
|
||||||
|
value: 100 - batteryChart.averageLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//ChartView {
|
||||||
|
// id: consumptionPieChart
|
||||||
|
// backgroundColor: "transparent"
|
||||||
|
// animationOptions: animationsEnabled ? NymeaUtils.chartsAnimationOptions : ChartView.NoAnimation
|
||||||
|
// title: qsTr("My energy mix")
|
||||||
|
// titleColor: Style.foregroundColor
|
||||||
|
// legend.visible: false
|
||||||
|
|
||||||
|
// margins.left: 0
|
||||||
|
// margins.right: 0
|
||||||
|
// margins.bottom: 0
|
||||||
|
// margins.top: 0
|
||||||
|
|
||||||
|
// property bool animationsEnabled: true
|
||||||
|
// property EnergyManager energyManager: null
|
||||||
|
|
||||||
|
// ThingsProxy {
|
||||||
|
// id: batteries
|
||||||
|
// engine: _engine
|
||||||
|
// shownInterfaces: ["energystorage"]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// PieSeries {
|
||||||
|
// id: consumptionBalanceSeries
|
||||||
|
// size: 0.88
|
||||||
|
// holeSize: 0.7
|
||||||
|
|
||||||
|
// property double fromGrid: Math.max(0, energyManager.currentPowerAcquisition)
|
||||||
|
// property double fromStorage: -Math.min(0, energyManager.currentPowerStorage)
|
||||||
|
// property double toStorage: -Math.min(0, -energyManager.currentPowerStorage)
|
||||||
|
// property double fromProduction: energyManager.currentPowerConsumption - fromGrid - fromStorage
|
||||||
|
// property double toGrid: Math.max(0, - energyManager.currentPowerAcquisition)
|
||||||
|
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.red
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.fromGrid
|
||||||
|
// }
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.green
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.fromProduction
|
||||||
|
// }
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.purple
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.fromStorage
|
||||||
|
// }
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.yellow
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.toGrid
|
||||||
|
// }
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.orange
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.toStorage
|
||||||
|
// }
|
||||||
|
|
||||||
|
// PieSlice {
|
||||||
|
// color: Style.tooltipBackgroundColor
|
||||||
|
// borderColor: color
|
||||||
|
// borderWidth: 0
|
||||||
|
// value: consumptionBalanceSeries.fromGrid == 0 && consumptionBalanceSeries.fromProduction == 0 && consumptionBalanceSeries.fromStorage == 0 ? 1 : 0
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Item {
|
||||||
|
// id: centerItem
|
||||||
|
|
||||||
|
// x: consumptionPieChart.plotArea.x + (consumptionPieChart.plotArea.width - width) / 2
|
||||||
|
// y: consumptionPieChart.plotArea.y + (consumptionPieChart.plotArea.height - height) / 2
|
||||||
|
// width: consumptionPieChart.plotArea.width * 0.65
|
||||||
|
// height: width
|
||||||
|
|
||||||
|
//// Rectangle {
|
||||||
|
//// anchors.fill: parent
|
||||||
|
//// color: "white"
|
||||||
|
//// }
|
||||||
|
|
||||||
|
// QtObject {
|
||||||
|
// id: d
|
||||||
|
// property double progress: 0
|
||||||
|
// onProgressChanged: canvas.requestPaint()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// NumberAnimation {
|
||||||
|
// id: progressAnimation
|
||||||
|
// target: d
|
||||||
|
// property: "progress"
|
||||||
|
// from: 0
|
||||||
|
// to: 1
|
||||||
|
// running: true
|
||||||
|
// loops: Animation.Infinite
|
||||||
|
// duration: 5000
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// Canvas {
|
||||||
|
// id: canvas
|
||||||
|
// anchors.fill: parent
|
||||||
|
|
||||||
|
// property int itemCount: batteries.count > 0 ? 4 : 3
|
||||||
|
|
||||||
|
// ColorIcon {
|
||||||
|
// property var point: canvas.circlePoint(Qt.point(canvas.width / 2, canvas.height / 2), canvas.height / 2, -90)
|
||||||
|
// x: point.x - width / 2
|
||||||
|
// y: point.y - height / 2
|
||||||
|
// name: "weathericons/weather-clear-day"
|
||||||
|
// }
|
||||||
|
// ColorIcon {
|
||||||
|
// property var point: canvas.circlePoint(Qt.point(canvas.width / 2, canvas.height / 2), canvas.height / 2, -90 + 360 / canvas.itemCount)
|
||||||
|
// x: point.x - width / 2
|
||||||
|
// y: point.y - height / 2
|
||||||
|
// name: "battery/battery-080"
|
||||||
|
// visible: batteries.count > 0
|
||||||
|
// }
|
||||||
|
// ColorIcon {
|
||||||
|
// property var point: canvas.circlePoint(Qt.point(canvas.width / 2, canvas.height / 2), canvas.height / 2, -90 + 360 / canvas.itemCount * (batteries.count > 0 ? 2 : 1))
|
||||||
|
// x: point.x - width / 2
|
||||||
|
// y: point.y - height / 2
|
||||||
|
// name: "things"
|
||||||
|
// }
|
||||||
|
// ColorIcon {
|
||||||
|
// property var point: canvas.circlePoint(Qt.point(canvas.width / 2, canvas.height / 2), canvas.height / 2, -90 + 360 / canvas.itemCount * (batteries.count > 0 ? 3 : 2))
|
||||||
|
// x: point.x - width / 2
|
||||||
|
// y: point.y - height / 2
|
||||||
|
// name: "energy"
|
||||||
|
// }
|
||||||
|
|
||||||
|
// onPaint: {
|
||||||
|
// var ctx = getContext("2d");
|
||||||
|
|
||||||
|
// var solarPos = circlePoint(Qt.point(0, 0), height / 2, -90)
|
||||||
|
// var storagePos = circlePoint(Qt.point(0, 0), height / 2, -90 / 360 * itemCount * 1)
|
||||||
|
// var consumptionPos = circlePoint(Qt.point(0, 0), height / 2, -90 + 360 / itemCount * (batteries.count > 0 ? 2 : 1))
|
||||||
|
// var gridPos = circlePoint(Qt.point(0, 0), height / 2, -90 + 360 / itemCount * (batteries.count > 0 ? 3 : 2))
|
||||||
|
|
||||||
|
// ctx.save();
|
||||||
|
// ctx.reset()
|
||||||
|
|
||||||
|
// ctx.translate(width / 2, height / 2);
|
||||||
|
|
||||||
|
// ctx.strokeStyle = Style.foregroundColor
|
||||||
|
// ctx.fillStyle = Style.foregroundColor
|
||||||
|
// ctx.lineWidth = 2
|
||||||
|
|
||||||
|
//// ctx.beginPath();
|
||||||
|
//// ctx.moveTo(0, -height / 2);
|
||||||
|
//// ctx.bezierCurveTo(0, -height / 10, -width / 10, 0, -width / 2, 0)
|
||||||
|
//// ctx.stroke();
|
||||||
|
//// ctx.closePath();
|
||||||
|
|
||||||
|
//// ctx.beginPath();
|
||||||
|
//// ctx.moveTo(-width / 2, 0);
|
||||||
|
//// ctx.bezierCurveTo(-width / 10, 0, 0, height / 10, 0, height / 2)
|
||||||
|
//// ctx.stroke();
|
||||||
|
//// ctx.closePath();
|
||||||
|
|
||||||
|
//// ctx.beginPath();
|
||||||
|
//// ctx.moveTo(0, height / 2);
|
||||||
|
//// ctx.bezierCurveTo(0, height / 10, width / 10, 0, width / 2, 0)
|
||||||
|
//// ctx.stroke();
|
||||||
|
//// ctx.closePath();
|
||||||
|
|
||||||
|
//// ctx.beginPath();
|
||||||
|
//// ctx.moveTo(width / 2, 0);
|
||||||
|
//// ctx.bezierCurveTo(width / 10, 0, 0, -height / 10, 0, -height / 2)
|
||||||
|
//// ctx.stroke();
|
||||||
|
//// ctx.closePath();
|
||||||
|
|
||||||
|
// var size = Math.abs(energyManager.currentPowerAcquisition) / Math.abs(energyManager.currentPowerProduction)
|
||||||
|
// drawDottedCurve(ctx, solarPos, gridPos, size)
|
||||||
|
|
||||||
|
// size = Math.abs(energyManager.currentPowerConsumption) / Math.abs(energyManager.currentPowerProduction)
|
||||||
|
// drawDottedCurve(ctx, solarPos, consumptionPos, size)
|
||||||
|
|
||||||
|
// if (batteries.count > 0) {
|
||||||
|
// size = Math.abs(energyManager.currentPowerStorage) / Math.abs(energyManager.currentPowerProduction)
|
||||||
|
// drawDottedCurve(ctx, solarPos, storagePos, size)
|
||||||
|
|
||||||
|
// if (energyManager.currentPowerStorage < 0) {
|
||||||
|
// size = Math.abs(energyManager.currentPowerStorage) / Math.abs(energyManager.currentPowerConsumption)
|
||||||
|
// drawDottedCurve(ctx, storagePos, consumptionPos, size)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (energyManager.currentPowerAcquisition > 0) {
|
||||||
|
// size = Math.abs(energyManager.currentPowerAcquisition) / Math.abs(energyManager.currentPowerConsumption)
|
||||||
|
// drawDottedCurve(ctx, gridPos, consumptionPos, size)
|
||||||
|
// }
|
||||||
|
|
||||||
|
//// var count = 5;
|
||||||
|
//// for (var i = 1; i <= count; i++) {
|
||||||
|
//// var offset = 1 / count;
|
||||||
|
//// var progress = d.progress + i * offset
|
||||||
|
//// if (progress > 1)
|
||||||
|
//// progress -= 1
|
||||||
|
//// var point = bezierCurvePoint(width / 2, 0, width / 10, 0, 0, -height / 10, 0, -height / 2, progress)
|
||||||
|
//// // print("painting", d.progress, point.x, point.y)
|
||||||
|
//// ctx.beginPath();
|
||||||
|
//// ctx.arc(point.x, point.y, 4, 0, 2 *Math.PI)
|
||||||
|
//// ctx.stroke();
|
||||||
|
//// ctx.closePath();
|
||||||
|
|
||||||
|
//// }
|
||||||
|
|
||||||
|
|
||||||
|
// ctx.restore();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function bezierCurvePoint(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, t) {
|
||||||
|
// var x = Math.pow(1-t, 3)*p0x + 3*Math.pow(1-t, 2)*t*p1x + 3*(1-t)*Math.pow(t, 2)*p2x + Math.pow(t, 3)*p3x;
|
||||||
|
// var y = Math.pow(1-t, 3)*p0y + 3*Math.pow(1-t, 2)*t*p1y + 3*(1-t)*Math.pow(t, 2)*p2y + Math.pow(t, 3)*p3y;
|
||||||
|
// return Qt.point(x, y)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function circlePoint(center, radius, angle) {
|
||||||
|
// var x = center.x + radius * Math.cos(angle * 2 * Math.PI / 360)
|
||||||
|
// var y = center.y + radius * Math.sin(angle * 2 * Math.PI / 360)
|
||||||
|
// return Qt.point(x, y)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function drawDottedCurve(ctx, start, end, size) {
|
||||||
|
// var c1 = getControlPoint(start)
|
||||||
|
// var c2 = getControlPoint(end)
|
||||||
|
// var count = 10;
|
||||||
|
// for (var i = 1; i <= count; i++) {
|
||||||
|
// var offset = 1 / count;
|
||||||
|
// var progress = d.progress + i * offset
|
||||||
|
// if (progress > 1)
|
||||||
|
// progress -= 1
|
||||||
|
// var point = bezierCurvePoint(start.x, start.y, c1.x, c1.y, c2.x, c2.y, end.x, end.y, progress)
|
||||||
|
// // print("painting", d.progress, point.x, point.y)
|
||||||
|
// ctx.beginPath();
|
||||||
|
// ctx.arc(point.x, point.y, size * 5, 0, 2 *Math.PI)
|
||||||
|
// ctx.stroke();
|
||||||
|
// ctx.fill();
|
||||||
|
// ctx.closePath();
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function getControlPoint(point) {
|
||||||
|
// return Qt.point(point.x * .1, point.y * .1)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// Column {
|
||||||
|
// id: centerLayout
|
||||||
|
// x: consumptionPieChart.plotArea.x + (consumptionPieChart.plotArea.width - width) / 2
|
||||||
|
// y: consumptionPieChart.plotArea.y + (consumptionPieChart.plotArea.height - height) / 2
|
||||||
|
// width: consumptionPieChart.plotArea.width * 0.65
|
||||||
|
//// height: consumptionPieChart.plotArea.height * 0.65
|
||||||
|
// height: childrenRect.height
|
||||||
|
// spacing: Style.smallMargins
|
||||||
|
|
||||||
|
// visible: false
|
||||||
|
|
||||||
|
// ColumnLayout {
|
||||||
|
// width: parent.width
|
||||||
|
// spacing: 0
|
||||||
|
// Label {
|
||||||
|
// text: qsTr("Consumption")
|
||||||
|
// font: Style.smallFont
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Label {
|
||||||
|
// text: "%1 %2"
|
||||||
|
// .arg((energyManager.currentPowerConsumption / (energyManager.currentPowerConsumption > 1000 ? 1000 : 1)).toFixed(1))
|
||||||
|
// .arg(energyManager.currentPowerConsumption > 1000 ? "kW" : "W")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
//// font: Style.smallFont
|
||||||
|
// color: Style.blue
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ColumnLayout {
|
||||||
|
// width: parent.width
|
||||||
|
// spacing: 0
|
||||||
|
// Label {
|
||||||
|
// text: qsTr("Production")
|
||||||
|
// font: Style.smallFont
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Label {
|
||||||
|
// property double absValue: Math.abs(energyManager.currentPowerProduction)
|
||||||
|
// text: "%1 %2"
|
||||||
|
// .arg((absValue / (absValue > 1000 ? 1000 : 1)).toFixed(1))
|
||||||
|
// .arg(absValue > 1000 ? "kW" : "W")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
//// font: Style.bigFont
|
||||||
|
// color: Style.yellow
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// ColumnLayout {
|
||||||
|
// width: parent.width
|
||||||
|
// spacing: 0
|
||||||
|
// Label {
|
||||||
|
// text: qsTr("From grid")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.extraSmallFont
|
||||||
|
// }
|
||||||
|
// Label {
|
||||||
|
// property double absValue: consumptionBalanceSeries.fromGrid
|
||||||
|
// color: Style.red
|
||||||
|
// text: "%1 %2"
|
||||||
|
// .arg((absValue / (absValue > 1000 ? 1000 : 1)).toFixed(1))
|
||||||
|
// .arg(absValue > 1000 ? "kW" : "W")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.smallFont
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// ColumnLayout {
|
||||||
|
// width: parent.width
|
||||||
|
// spacing: 0
|
||||||
|
// Label {
|
||||||
|
// text: qsTr("From self production")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.extraSmallFont
|
||||||
|
// }
|
||||||
|
// Label {
|
||||||
|
// color: Style.green
|
||||||
|
// property double absValue: consumptionBalanceSeries.fromProduction
|
||||||
|
// text: "%1 %2".arg((absValue / (absValue > 1000 ? 1000 : 1)).toFixed(1))
|
||||||
|
// .arg(absValue > 1000 ? "kW" : "W")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.smallFont
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ColumnLayout {
|
||||||
|
// width: parent.width
|
||||||
|
// spacing: 0
|
||||||
|
// visible: batteries.count > 0
|
||||||
|
// Label {
|
||||||
|
// text: energyManager.currentPowerStorage < 0 ? qsTr("From battery") : qsTr("To battery")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.extraSmallFont
|
||||||
|
// }
|
||||||
|
// Label {
|
||||||
|
// color: value < 0 ? Style.purple : Style.orange
|
||||||
|
// property double value: energyManager.currentPowerStorage
|
||||||
|
// property double absValue: Math.abs(energyManager.currentPowerStorage)
|
||||||
|
// text: "%1 %2".arg((absValue / (absValue > 1000 ? 1000 : 1)).toFixed(1))
|
||||||
|
// .arg(absValue > 1000 ? "kW" : "W")
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// font: Style.smallFont
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
791
nymea-app/ui/mainviews/energy/PowerBalanceHistory.qml
Normal file
791
nymea-app/ui/mainviews/energy/PowerBalanceHistory.qml
Normal file
@ -0,0 +1,791 @@
|
|||||||
|
import QtQuick 2.0
|
||||||
|
import QtCharts 2.2
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
|
import QtQuick.Controls 2.2
|
||||||
|
import Nymea 1.0
|
||||||
|
import "qrc:/ui/components"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
PowerBalanceLogs {
|
||||||
|
id: powerBalanceLogs
|
||||||
|
engine: _engine
|
||||||
|
startTime: new Date(d.startTime.getTime() - d.range * 60000)
|
||||||
|
endTime: new Date(d.endTime.getTime() + d.range * 60000)
|
||||||
|
sampleRate: d.sampleRate
|
||||||
|
Component.onCompleted: fetchLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
property ThingsProxy batteries: ThingsProxy {
|
||||||
|
engine: _engine
|
||||||
|
shownInterfaces: ["energystorage"]
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
property date now: new Date()
|
||||||
|
|
||||||
|
readonly property int range: selectionTabs.currentValue.range
|
||||||
|
readonly property int sampleRate: selectionTabs.currentValue.sampleRate
|
||||||
|
readonly property int visibleValues: range / sampleRate
|
||||||
|
|
||||||
|
readonly property var startTime: {
|
||||||
|
var date = new Date(fixTime(now));
|
||||||
|
date.setTime(date.getTime() - range * 60000 + 2000);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var endTime: {
|
||||||
|
var date = new Date(fixTime(now));
|
||||||
|
date.setTime(date.getTime() + 2000)
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixTime(timestamp) {
|
||||||
|
switch (sampleRate) {
|
||||||
|
case EnergyLogs.SampleRate1Min:
|
||||||
|
timestamp.setSeconds(0, 0)
|
||||||
|
break;
|
||||||
|
case EnergyLogs.SampleRate15Mins:
|
||||||
|
timestamp.setMinutes(timestamp.getMinutes() - timestamp.getMinutes() % 15, 0, 0)
|
||||||
|
break;
|
||||||
|
case EnergyLogs.SampleRate1Hour:
|
||||||
|
timestamp.setMinutes(0, 0, 0);
|
||||||
|
break;
|
||||||
|
case EnergyLogs.SampleRate3Hours:
|
||||||
|
timestamp.setHours(timestamp.getHours() % 3, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
case EnergyLogs.SampleRate1Day:
|
||||||
|
timestamp.setHours(0, 0, 0, 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: powerBalanceLogs
|
||||||
|
|
||||||
|
onEntriesAdded: {
|
||||||
|
// print("entries added", index, entries.length)
|
||||||
|
for (var i = 0; i < entries.length; i++) {
|
||||||
|
var entry = entries[i]
|
||||||
|
// print("got entry", entry.timestamp)
|
||||||
|
|
||||||
|
zeroSeries.ensureValue(entry.timestamp)
|
||||||
|
// For debugging, to see if the other maths line up with the plain production graph
|
||||||
|
productionSeries.insertEntry(index + i, entry)
|
||||||
|
consumptionSeries.insertEntry(index + i, entry)
|
||||||
|
selfProductionConsumptionSeries.insertEntry(index + i, entry)
|
||||||
|
toStorageSeries.insertEntry(index + i, entry)
|
||||||
|
fromStorageSeries.insertEntry(index + i, entry)
|
||||||
|
returnSeries.insertEntry(index + i, entry)
|
||||||
|
acquisitionSeries.insertEntry(index + i, entry)
|
||||||
|
if (entry.timestamp > d.now && new Date().getTime() - d.now.getTime() < 120000) {
|
||||||
|
d.now = entry.timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onEntriesRemoved: {
|
||||||
|
acquisitionUpperSeries.removePoints(index, count)
|
||||||
|
returnUpperSeries.removePoints(index, count)
|
||||||
|
fromStorageUpperSeries.removePoints(index, count)
|
||||||
|
toStorageUpperSeries.removePoints(index, count)
|
||||||
|
selfProductionConsumptionUpperSeries.removePoints(index, count)
|
||||||
|
productionSeries.removePoints(index, count)
|
||||||
|
consumptionSeries.removePoints(index, count)
|
||||||
|
zeroSeries.shrink()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// Label {
|
||||||
|
// Layout.fillWidth: true
|
||||||
|
// Layout.margins: Style.smallMargins
|
||||||
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
|
// text: qsTr("My production history")
|
||||||
|
// }
|
||||||
|
|
||||||
|
SelectionTabs {
|
||||||
|
id: selectionTabs
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.leftMargin: Style.smallMargins
|
||||||
|
Layout.rightMargin: Style.smallMargins
|
||||||
|
currentIndex: 1
|
||||||
|
model: ListModel {
|
||||||
|
ListElement {
|
||||||
|
modelData: qsTr("Hours")
|
||||||
|
sampleRate: EnergyLogs.SampleRate1Min
|
||||||
|
range: 180 // 3 Hours: 3 * 60
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
modelData: qsTr("Days")
|
||||||
|
sampleRate: EnergyLogs.SampleRate15Mins
|
||||||
|
range: 1440 // 1 Day: 24 * 60
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
modelData: qsTr("Weeks")
|
||||||
|
sampleRate: EnergyLogs.SampleRate1Hour
|
||||||
|
range: 10080 // 7 Days: 7 * 24 * 60
|
||||||
|
}
|
||||||
|
ListElement {
|
||||||
|
modelData: qsTr("Months")
|
||||||
|
sampleRate: EnergyLogs.SampleRate3Hours
|
||||||
|
range: 43200 // 30 Days: 30 * 24 * 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onTabSelected: {
|
||||||
|
d.now = new Date()
|
||||||
|
powerBalanceLogs.fetchLogs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
Label {
|
||||||
|
x: chartView.x + chartView.plotArea.x + (chartView.plotArea.width - width) / 2
|
||||||
|
y: chartView.y + chartView.plotArea.y + Style.smallMargins
|
||||||
|
text: {
|
||||||
|
switch (d.sampleRate) {
|
||||||
|
case EnergyLogs.SampleRate1Min:
|
||||||
|
return d.startTime.toLocaleDateString(Qt.locale(), Locale.LongFormat)
|
||||||
|
case EnergyLogs.SampleRate15Mins:
|
||||||
|
case EnergyLogs.SampleRate1Hour:
|
||||||
|
case EnergyLogs.SampleRate3Hours:
|
||||||
|
case EnergyLogs.SampleRate1Day:
|
||||||
|
case EnergyLogs.SampleRate1Week:
|
||||||
|
case EnergyLogs.SampleRate1Month:
|
||||||
|
case EnergyLogs.SampleRate1Year:
|
||||||
|
return d.startTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat) + " - " + d.endTime.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
font: Style.smallFont
|
||||||
|
opacity: ((new Date().getTime() - d.now.getTime()) / d.sampleRate / 60000) > d.visibleValues ? .5 : 0
|
||||||
|
Behavior on opacity { NumberAnimation {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartView {
|
||||||
|
id: chartView
|
||||||
|
anchors.fill: parent
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
margins.left: 0
|
||||||
|
margins.right: 0
|
||||||
|
margins.bottom: Style.smallIconSize + Style.margins
|
||||||
|
margins.top: 0
|
||||||
|
|
||||||
|
legend.alignment: Qt.AlignBottom
|
||||||
|
legend.labelColor: Style.foregroundColor
|
||||||
|
legend.font: Style.extraSmallFont
|
||||||
|
legend.visible: false
|
||||||
|
|
||||||
|
ActivityIndicator {
|
||||||
|
x: chartView.plotArea.x + (chartView.plotArea.width - width) / 2
|
||||||
|
y: chartView.plotArea.y + (chartView.plotArea.height - height) / 2 + (chartView.plotArea.height / 8)
|
||||||
|
visible: powerBalanceLogs.fetchingData && (powerBalanceLogs.count == 0 || powerBalanceLogs.get(0).timestamp > d.startTime)
|
||||||
|
opacity: .5
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
x: chartView.plotArea.x + (chartView.plotArea.width - width) / 2
|
||||||
|
y: chartView.plotArea.y + (chartView.plotArea.height - height) / 2 + (chartView.plotArea.height / 8)
|
||||||
|
text: qsTr("No data available")
|
||||||
|
visible: !powerBalanceLogs.fetchingData && (powerBalanceLogs.count == 0 || powerBalanceLogs.get(0).timestamp > d.now)
|
||||||
|
font: Style.smallFont
|
||||||
|
opacity: .5
|
||||||
|
}
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: valueAxis
|
||||||
|
min: 0
|
||||||
|
max: Math.ceil(Math.max(-powerBalanceLogs.minValue, powerBalanceLogs.maxValue) / 100) * 100
|
||||||
|
labelFormat: ""
|
||||||
|
gridLineColor: Style.tileOverlayColor
|
||||||
|
labelsVisible: false
|
||||||
|
lineVisible: false
|
||||||
|
titleVisible: false
|
||||||
|
shadesVisible: false
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
id: labelsLayout
|
||||||
|
x: Style.smallMargins
|
||||||
|
y: chartView.plotArea.y
|
||||||
|
height: chartView.plotArea.height
|
||||||
|
width: chartView.plotArea.x - x
|
||||||
|
Repeater {
|
||||||
|
model: valueAxis.tickCount
|
||||||
|
delegate: Label {
|
||||||
|
y: parent.height / (valueAxis.tickCount - 1) * index - font.pixelSize / 2
|
||||||
|
width: parent.width - Style.smallMargins
|
||||||
|
horizontalAlignment: Text.AlignRight
|
||||||
|
text: ((valueAxis.max - (index * valueAxis.max / (valueAxis.tickCount - 1))) / 1000).toFixed(2) + "kW"
|
||||||
|
verticalAlignment: Text.AlignTop
|
||||||
|
font: Style.extraSmallFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeAxis {
|
||||||
|
id: dateTimeAxis
|
||||||
|
min: d.startTime
|
||||||
|
max: d.endTime
|
||||||
|
format: {
|
||||||
|
switch (selectionTabs.currentValue.sampleRate) {
|
||||||
|
case EnergyLogs.SampleRate1Min:
|
||||||
|
case EnergyLogs.SampleRate15Mins:
|
||||||
|
return "hh:mm"
|
||||||
|
case EnergyLogs.SampleRate1Hour:
|
||||||
|
case EnergyLogs.SampleRate3Hours:
|
||||||
|
case EnergyLogs.SampleRate1Day:
|
||||||
|
return "dd.MM."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tickCount: {
|
||||||
|
switch (selectionTabs.currentValue.sampleRate) {
|
||||||
|
case EnergyLogs.SampleRate1Min:
|
||||||
|
case EnergyLogs.SampleRate15Mins:
|
||||||
|
return root.width > 500 ? 13 : 7
|
||||||
|
case EnergyLogs.SampleRate1Hour:
|
||||||
|
return 7
|
||||||
|
case EnergyLogs.SampleRate3Hours:
|
||||||
|
case EnergyLogs.SampleRate1Day:
|
||||||
|
return root.width > 500 ? 12 : 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
labelsFont: Style.extraSmallFont
|
||||||
|
gridVisible: false
|
||||||
|
minorGridVisible: false
|
||||||
|
lineVisible: false
|
||||||
|
shadesVisible: false
|
||||||
|
labelsColor: Style.foregroundColor
|
||||||
|
}
|
||||||
|
AreaSeries {
|
||||||
|
id: selfProductionConsumptionSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.green
|
||||||
|
// borderWidth: 2
|
||||||
|
borderColor: color
|
||||||
|
name: qsTr("From self production")
|
||||||
|
// visible: false
|
||||||
|
|
||||||
|
lowerSeries: LineSeries {
|
||||||
|
id: zeroSeries
|
||||||
|
XYPoint { x: dateTimeAxis.min.getTime(); y: 0 }
|
||||||
|
XYPoint { x: dateTimeAxis.max.getTime(); y: 0 }
|
||||||
|
function ensureValue(timestamp) {
|
||||||
|
if (count == 0) {
|
||||||
|
append(timestamp, 0)
|
||||||
|
} else if (count == 1) {
|
||||||
|
if (timestamp.getTime() < at(0).x) {
|
||||||
|
insert(0, timestamp, 0)
|
||||||
|
} else {
|
||||||
|
append(timestamp, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (timestamp.getTime() < at(0).x) {
|
||||||
|
remove(0)
|
||||||
|
insert(0, timestamp, 0)
|
||||||
|
} else if (timestamp.getTime() > at(1).x) {
|
||||||
|
remove(1)
|
||||||
|
append(timestamp, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function shrink() {
|
||||||
|
clear();
|
||||||
|
if (powerBalanceLogs.count > 0) {
|
||||||
|
ensureValue(powerBalanceLogs.get(0).timestamp)
|
||||||
|
ensureValue(powerBalanceLogs.get(powerBalanceLogs.count-1).timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: selfProductionConsumptionUpperSeries
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return Math.max(0, -entry.production) - Math.max(0, -entry.acquisition) - Math.max(0, entry.storage)
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEntry(entry) {
|
||||||
|
selfProductionConsumptionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
selfProductionConsumptionUpperSeries.insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
id: toStorageSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.purple
|
||||||
|
borderWidth: 0
|
||||||
|
borderColor: color
|
||||||
|
visible: root.batteries.count > 0
|
||||||
|
name: qsTr("To battery")
|
||||||
|
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return selfProductionConsumptionSeries.calculateValue(entry) + Math.max(0, entry.storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEntry(entry) {
|
||||||
|
toStorageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
toStorageUpperSeries.insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerSeries: selfProductionConsumptionUpperSeries
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: toStorageUpperSeries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
id: returnSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.yellow
|
||||||
|
borderWidth: 0
|
||||||
|
borderColor: color
|
||||||
|
name: qsTr("To grid")
|
||||||
|
// visible: false
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return toStorageSeries.calculateValue(entry) + Math.max(0, -entry.acquisition)
|
||||||
|
}
|
||||||
|
function addEntry(entry) {
|
||||||
|
returnUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
returnUpperSeries.insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerSeries: toStorageUpperSeries
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: returnUpperSeries
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
id: fromStorageSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.orange
|
||||||
|
borderWidth: 0
|
||||||
|
borderColor: color
|
||||||
|
name: qsTr("From battery")
|
||||||
|
visible: root.batteries.count > 0
|
||||||
|
|
||||||
|
lowerSeries: selfProductionConsumptionUpperSeries
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: fromStorageUpperSeries
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return selfProductionConsumptionSeries.calculateValue(entry) + Math.abs(Math.min(0, entry.storage));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEntry(entry) {
|
||||||
|
fromStorageUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
fromStorageUpperSeries.insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
id: acquisitionSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.red
|
||||||
|
borderWidth: 0
|
||||||
|
borderColor: color
|
||||||
|
name: qsTr("From grid")
|
||||||
|
// visible: false
|
||||||
|
|
||||||
|
lowerSeries: fromStorageUpperSeries
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
id: acquisitionUpperSeries
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return fromStorageSeries.calculateValue(entry) + Math.max(0, entry.acquisition)
|
||||||
|
}
|
||||||
|
function addEntry(entry) {
|
||||||
|
acquisitionUpperSeries.append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
acquisitionUpperSeries.insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineSeries {
|
||||||
|
id: productionSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.white
|
||||||
|
width: 1
|
||||||
|
name: "Total production"
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return Math.abs(Math.min(0, entry.production))
|
||||||
|
}
|
||||||
|
function addEntry(entry) {
|
||||||
|
append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineSeries {
|
||||||
|
id: consumptionSeries
|
||||||
|
axisX: dateTimeAxis
|
||||||
|
axisY: valueAxis
|
||||||
|
color: Style.red
|
||||||
|
width: 1
|
||||||
|
name: "Total consumption"
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
function calculateValue(entry) {
|
||||||
|
return Math.max(0, entry.consumption)
|
||||||
|
}
|
||||||
|
function addEntry(entry) {
|
||||||
|
append(entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
function insertEntry(index, entry) {
|
||||||
|
insert(index, entry.timestamp.getTime(), calculateValue(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||||
|
anchors.leftMargin: chartView.plotArea.x
|
||||||
|
height: Style.smallIconSize
|
||||||
|
anchors.margins: Style.margins
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
ColorIcon {
|
||||||
|
name: "weathericons/weather-clear-day"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.green
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "power-grid"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.red
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "arrow-down"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "power-grid"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.yellow
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "arrow-up"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
visible: batteries.count > 0
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "battery/battery-080"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.purple
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "plus"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.purple
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
visible: batteries.count > 0
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "battery/battery-040"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.orange
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "minus"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.orange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: chartView.plotArea.x
|
||||||
|
anchors.topMargin: chartView.plotArea.y
|
||||||
|
anchors.rightMargin: chartView.width - chartView.plotArea.width - chartView.plotArea.x
|
||||||
|
anchors.bottomMargin: chartView.height - chartView.plotArea.height - chartView.plotArea.y
|
||||||
|
|
||||||
|
hoverEnabled: true
|
||||||
|
preventStealing: tooltipping || dragging
|
||||||
|
|
||||||
|
property int startMouseX: 0
|
||||||
|
property bool dragging: false
|
||||||
|
property bool tooltipping: false
|
||||||
|
|
||||||
|
property var startDatetime: null
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 300
|
||||||
|
running: mouseArea.pressed
|
||||||
|
onTriggered: {
|
||||||
|
if (!mouseArea.dragging) {
|
||||||
|
mouseArea.tooltipping = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onReleased: {
|
||||||
|
if (mouseArea.dragging) {
|
||||||
|
powerBalanceLogs.fetchLogs()
|
||||||
|
mouseArea.dragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseArea.tooltipping = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
startMouseX = mouseX
|
||||||
|
startDatetime = d.now
|
||||||
|
}
|
||||||
|
|
||||||
|
onDoubleClicked: {
|
||||||
|
if (selectionTabs.currentIndex == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx = Math.ceil(mouseArea.mouseX * d.visibleValues / mouseArea.width)
|
||||||
|
var timestamp = new Date(d.startTime.getTime() + (idx * d.sampleRate * 60000))
|
||||||
|
selectionTabs.currentIndex--
|
||||||
|
d.now = new Date(Math.min(new Date().getTime(), timestamp.getTime() + (d.visibleValues / 2) * d.sampleRate * 60000))
|
||||||
|
powerBalanceLogs.fetchLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseXChanged: {
|
||||||
|
if (!pressed || mouseArea.tooltipping) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Math.abs(startMouseX - mouseX) < 10) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragging = true
|
||||||
|
|
||||||
|
var dragDelta = startMouseX - mouseX
|
||||||
|
var totalTime = d.endTime.getTime() - d.startTime.getTime()
|
||||||
|
// dragDelta : timeDelta = width : totalTime
|
||||||
|
var timeDelta = dragDelta * totalTime / mouseArea.width
|
||||||
|
print("dragging", dragDelta, totalTime, mouseArea.width)
|
||||||
|
d.now = new Date(Math.min(new Date(), new Date(startDatetime.getTime() + timeDelta)))
|
||||||
|
}
|
||||||
|
|
||||||
|
onWheel: {
|
||||||
|
startDatetime = d.now
|
||||||
|
var totalTime = d.endTime.getTime() - d.startTime.getTime()
|
||||||
|
// pixelDelta : timeDelta = width : totalTime
|
||||||
|
var timeDelta = wheel.pixelDelta.x * totalTime / mouseArea.width
|
||||||
|
print("wheeling", wheel.pixelDelta.x, totalTime, mouseArea.width)
|
||||||
|
d.now = new Date(Math.min(new Date(), new Date(startDatetime.getTime() - timeDelta)))
|
||||||
|
wheelStopTimer.restart()
|
||||||
|
}
|
||||||
|
Timer {
|
||||||
|
id: wheelStopTimer
|
||||||
|
interval: 300
|
||||||
|
repeat: false
|
||||||
|
onTriggered: powerBalanceLogs.fetchLogs()
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
height: parent.height
|
||||||
|
width: 1
|
||||||
|
color: Style.foregroundColor
|
||||||
|
x: Math.min(mouseArea.width, Math.max(0, mouseArea.mouseX))
|
||||||
|
visible: (mouseArea.containsMouse || mouseArea.tooltipping) && !mouseArea.dragging
|
||||||
|
}
|
||||||
|
|
||||||
|
NymeaToolTip {
|
||||||
|
id: toolTip
|
||||||
|
visible: (mouseArea.containsMouse || mouseArea.tooltipping) && !mouseArea.dragging
|
||||||
|
|
||||||
|
backgroundItem: chartView
|
||||||
|
backgroundRect: Qt.rect(mouseArea.x + toolTip.x, mouseArea.y + toolTip.y, toolTip.width, toolTip.height)
|
||||||
|
|
||||||
|
property int idx: Math.min(d.visibleValues, Math.max(0, Math.round(mouseArea.mouseX * d.visibleValues / mouseArea.width)))
|
||||||
|
property var timestamp: new Date(Math.min(d.endTime.getTime(), Math.max(d.startTime, d.startTime.getTime() + (idx * d.sampleRate * 60000))))
|
||||||
|
property PowerBalanceLogEntry entry: powerBalanceLogs.find(timestamp)
|
||||||
|
|
||||||
|
property int xOnRight: Math.max(0, mouseArea.mouseX) + Style.smallMargins
|
||||||
|
property int xOnLeft: Math.min(mouseArea.mouseX, mouseArea.width) - Style.smallMargins - width
|
||||||
|
x: xOnRight + width < mouseArea.width ? xOnRight : xOnLeft
|
||||||
|
property double maxValue: toolTip.entry ? Math.max(0, -entry.production) : 0
|
||||||
|
y: Math.min(Math.max(mouseArea.height - (maxValue * mouseArea.height / valueAxis.max) - height - Style.margins, 0), mouseArea.height - height)
|
||||||
|
|
||||||
|
width: tooltipLayout.implicitWidth + Style.smallMargins * 2
|
||||||
|
height: tooltipLayout.implicitHeight + Style.smallMargins * 2
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: tooltipLayout
|
||||||
|
width: parent.width
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
top: parent.top
|
||||||
|
margins: Style.smallMargins
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: toolTip.entry.timestamp.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||||
|
font: Style.smallFont
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
property double value: toolTip.entry
|
||||||
|
? (toolTip.entry.acquisition >= 0 ? toolTip.entry.consumption : Math.max(0, -toolTip.entry.production))
|
||||||
|
: 0
|
||||||
|
property bool translate: value >= 1000
|
||||||
|
property double translatedValue: value / (translate ? 1000 : 1)
|
||||||
|
text: toolTip.entry.acquisition >= 0 ? qsTr("Consumed: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
: qsTr("Produced: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
font: Style.smallFont
|
||||||
|
}
|
||||||
|
// Label {
|
||||||
|
// property double value: toolTip.entry ? toolTip.entry.consumption : 0
|
||||||
|
// property bool translate: value >= 1000
|
||||||
|
// property double translatedValue: value / (translate ? 1000 : 1)
|
||||||
|
// text: qsTr("Total consumption: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
// font: Style.extraSmallFont
|
||||||
|
// }
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Rectangle {
|
||||||
|
width: Style.extraSmallFont.pixelSize
|
||||||
|
height: width
|
||||||
|
color: toolTip.entry.acquisition >= 0 ? Style.red : Style.yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
// Workaround for Qt bug that lowerSeries is non-notifyable and throws warnings
|
||||||
|
Component.onCompleted: lowerSeries = returnSeries.lowerSeries
|
||||||
|
property XYSeries lowerSeries: null
|
||||||
|
|
||||||
|
property double value: toolTip.entry ? Math.abs(toolTip.entry.acquisition) : 0
|
||||||
|
property bool translate: value >= 1000
|
||||||
|
property double translatedValue: value / (translate ? 1000 : 1)
|
||||||
|
text: toolTip.entry.acquisition >= 0 ? qsTr("From grid: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
: qsTr("To grid: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
font: Style.extraSmallFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
Rectangle {
|
||||||
|
width: Style.extraSmallFont.pixelSize
|
||||||
|
height: width
|
||||||
|
color: Style.green
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
// Workaround for Qt bug that lowerSeries is non-notifyable and throws warnings
|
||||||
|
Component.onCompleted: lowerSeries = selfProductionConsumptionSeries.lowerSeries
|
||||||
|
property XYSeries lowerSeries: null
|
||||||
|
|
||||||
|
property double value: toolTip.entry ? Math.min(Math.max(0, toolTip.entry.consumption), -toolTip.entry.production) : 0
|
||||||
|
property bool translate: value >= 1000
|
||||||
|
property double translatedValue: value / (translate ? 1000 : 1)
|
||||||
|
text: toolTip.entry.acquisition >= 0 ? qsTr("From self production: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
: qsTr("Consumed: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
font: Style.extraSmallFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RowLayout {
|
||||||
|
visible: root.batteries.count > 0
|
||||||
|
Rectangle {
|
||||||
|
width: Style.extraSmallFont.pixelSize
|
||||||
|
height: width
|
||||||
|
color: toolTip.entry.storage > 0 ? Style.purple : Style.orange
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
// Workaround for Qt bug that lowerSeries is non-notifyable and throws warnings
|
||||||
|
Component.onCompleted: lowerSeries = toStorageSeries.lowerSeries
|
||||||
|
property XYSeries lowerSeries: null
|
||||||
|
|
||||||
|
property double value: toolTip.entry ? Math.abs(toolTip.entry.storage) : 0
|
||||||
|
property bool translate: value >= 1000
|
||||||
|
property double translatedValue: value / (translate ? 1000 : 1)
|
||||||
|
text: toolTip.entry.storage > 0 ? qsTr("To battery: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W") :
|
||||||
|
qsTr("From battery: %1 %2").arg(translatedValue.toFixed(2)).arg(translate ? "kW" : "W")
|
||||||
|
font: Style.extraSmallFont
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -106,12 +106,12 @@ StatsBase {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
||||||
Label {
|
// Label {
|
||||||
Layout.fillWidth: true
|
// Layout.fillWidth: true
|
||||||
Layout.margins: Style.smallMargins
|
// Layout.margins: Style.smallMargins
|
||||||
horizontalAlignment: Text.AlignHCenter
|
// horizontalAlignment: Text.AlignHCenter
|
||||||
text: qsTr("Totals")
|
// text: qsTr("Totals")
|
||||||
}
|
// }
|
||||||
|
|
||||||
SelectionTabs {
|
SelectionTabs {
|
||||||
id: selectionTabs
|
id: selectionTabs
|
||||||
@ -186,13 +186,15 @@ StatsBase {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
|
|
||||||
|
legend.visible: false
|
||||||
legend.alignment: Qt.AlignBottom
|
legend.alignment: Qt.AlignBottom
|
||||||
legend.font: Style.extraSmallFont
|
legend.font: Style.extraSmallFont
|
||||||
legend.labelColor: Style.foregroundColor
|
legend.labelColor: Style.foregroundColor
|
||||||
|
|
||||||
// margins.left: 0
|
// margins.left: 0
|
||||||
margins.right: 0
|
margins.right: 0
|
||||||
margins.bottom: 0
|
margins.bottom: Style.smallIconSize + Style.margins
|
||||||
margins.top: 0
|
margins.top: 0
|
||||||
|
|
||||||
ActivityIndicator {
|
ActivityIndicator {
|
||||||
@ -290,7 +292,7 @@ StatsBase {
|
|||||||
BarSet {
|
BarSet {
|
||||||
id: productionSet
|
id: productionSet
|
||||||
label: qsTr("Produced")
|
label: qsTr("Produced")
|
||||||
color: Style.yellow
|
color: Style.green
|
||||||
borderColor: color
|
borderColor: color
|
||||||
borderWidth: 0
|
borderWidth: 0
|
||||||
values: {
|
values: {
|
||||||
@ -301,7 +303,6 @@ StatsBase {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BarSet {
|
BarSet {
|
||||||
id: acquisitionSet
|
id: acquisitionSet
|
||||||
label: qsTr("From grid")
|
label: qsTr("From grid")
|
||||||
@ -319,7 +320,7 @@ StatsBase {
|
|||||||
BarSet {
|
BarSet {
|
||||||
id: returnSet
|
id: returnSet
|
||||||
label: qsTr("To grid")
|
label: qsTr("To grid")
|
||||||
color: Style.green
|
color: Style.yellow
|
||||||
borderColor: color
|
borderColor: color
|
||||||
borderWidth: 0
|
borderWidth: 0
|
||||||
values: {
|
values: {
|
||||||
@ -333,6 +334,71 @@ StatsBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
|
||||||
|
anchors.leftMargin: chartView.plotArea.x
|
||||||
|
height: Style.smallIconSize
|
||||||
|
anchors.margins: Style.margins
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
ColorIcon {
|
||||||
|
name: "powersocket"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.blue
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
ColorIcon {
|
||||||
|
name: "weathericons/weather-clear-day"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.green
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "power-grid"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.red
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "arrow-down"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Row {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
ColorIcon {
|
||||||
|
name: "power-grid"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.yellow
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
name: "arrow-up"
|
||||||
|
size: Style.smallIconSize
|
||||||
|
color: Style.yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.leftMargin: chartView.x + chartView.plotArea.x
|
anchors.leftMargin: chartView.x + chartView.plotArea.x
|
||||||
|
|||||||
Reference in New Issue
Block a user