Merge PR #496: Improve smartmeter and sensor views
This commit is contained in:
commit
913b7741ba
@ -140,7 +140,7 @@ void UpnpDiscovery::readData()
|
|||||||
data.resize(socket->pendingDatagramSize());
|
data.resize(socket->pendingDatagramSize());
|
||||||
socket->readDatagram(data.data(), data.size(), &hostAddress, &port);
|
socket->readDatagram(data.data(), data.size(), &hostAddress, &port);
|
||||||
|
|
||||||
qDebug() << "Received UPnP datagram:" << data;
|
// qDebug() << "Received UPnP datagram:" << data;
|
||||||
|
|
||||||
// if the data contains the HTTP OK header...
|
// if the data contains the HTTP OK header...
|
||||||
if (data.contains("HTTP/1.1 200 OK")) {
|
if (data.contains("HTTP/1.1 200 OK")) {
|
||||||
|
|||||||
@ -322,7 +322,7 @@ void LogsModel::fetchMore(const QModelIndex &parent)
|
|||||||
params.insert("limit", m_blockSize);
|
params.insert("limit", m_blockSize);
|
||||||
params.insert("offset", m_list.count());
|
params.insert("offset", m_list.count());
|
||||||
|
|
||||||
qDebug() << "Fetching logs from" << m_startTime.toString() << "to" << m_endTime.toString() << "with offset" << m_list.count() << "and limit" << m_blockSize;
|
// qDebug() << "Fetching logs from" << m_startTime.toString() << "to" << m_endTime.toString() << "with offset" << m_list.count() << "and limit" << m_blockSize;
|
||||||
|
|
||||||
m_engine->jsonRpcClient()->sendCommand("Logging.GetLogEntries", params, this, "logsReply");
|
m_engine->jsonRpcClient()->sendCommand("Logging.GetLogEntries", params, this, "logsReply");
|
||||||
// qDebug() << "GetLogEntries called";
|
// qDebug() << "GetLogEntries called";
|
||||||
|
|||||||
@ -419,7 +419,7 @@ void LogsModelNg::fetchMore(const QModelIndex &parent)
|
|||||||
params.insert("limit", m_blockSize);
|
params.insert("limit", m_blockSize);
|
||||||
params.insert("offset", m_list.count());
|
params.insert("offset", m_list.count());
|
||||||
|
|
||||||
qDebug() << "Fetching logs:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
|
// qDebug() << "Fetching logs:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
|
||||||
|
|
||||||
m_engine->jsonRpcClient()->sendCommand("Logging.GetLogEntries", params, this, "logsReply");
|
m_engine->jsonRpcClient()->sendCommand("Logging.GetLogEntries", params, this, "logsReply");
|
||||||
// qDebug() << "GetLogEntries called";
|
// qDebug() << "GetLogEntries called";
|
||||||
|
|||||||
@ -46,12 +46,34 @@ void XYSeriesAdapter::setBaseSeries(QtCharts::QXYSeries *series)
|
|||||||
|
|
||||||
connect(m_baseSeries, &QtCharts::QXYSeries::pointAdded, this, [=](int index){
|
connect(m_baseSeries, &QtCharts::QXYSeries::pointAdded, this, [=](int index){
|
||||||
if (m_series->count() > index) {
|
if (m_series->count() > index) {
|
||||||
m_series->replace(index, m_series->at(index).x(), calculateSampleValue(index));
|
qreal value = calculateSampleValue(index);
|
||||||
|
m_series->replace(index, m_series->at(index).x(), value);
|
||||||
|
if (value < m_minValue) {
|
||||||
|
m_minValue = value;
|
||||||
|
qDebug() << "New min:" << m_minValue;
|
||||||
|
emit minValueChanged();
|
||||||
|
}
|
||||||
|
if (value > m_maxValue) {
|
||||||
|
m_maxValue = value;
|
||||||
|
qDebug() << "New max:" << m_maxValue;
|
||||||
|
emit maxValueChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(m_baseSeries, &QtCharts::QXYSeries::pointReplaced, this, [=](int index){
|
connect(m_baseSeries, &QtCharts::QXYSeries::pointReplaced, this, [=](int index){
|
||||||
if (m_series->count() > index) {
|
if (m_series->count() > index) {
|
||||||
m_series->replace(index, m_series->at(index).x(), calculateSampleValue(index));
|
qreal value = calculateSampleValue(index);
|
||||||
|
m_series->replace(index, m_series->at(index).x(), value);
|
||||||
|
if (value < m_minValue) {
|
||||||
|
m_minValue = value;
|
||||||
|
qDebug() << "New min:" << m_minValue;
|
||||||
|
emit minValueChanged();
|
||||||
|
}
|
||||||
|
if (value > m_maxValue) {
|
||||||
|
m_maxValue = value;
|
||||||
|
qDebug() << "New max:" << m_maxValue;
|
||||||
|
emit maxValueChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -155,10 +177,12 @@ void XYSeriesAdapter::logEntryAdded(LogEntry *entry)
|
|||||||
|
|
||||||
if (value < m_minValue) {
|
if (value < m_minValue) {
|
||||||
m_minValue = value;
|
m_minValue = value;
|
||||||
|
// qDebug() << "New min:" << m_minValue;
|
||||||
emit minValueChanged();
|
emit minValueChanged();
|
||||||
}
|
}
|
||||||
if (value > m_maxValue) {
|
if (value > m_maxValue) {
|
||||||
m_maxValue = value;
|
m_maxValue = value;
|
||||||
|
// qDebug() << "New max:" << m_maxValue;
|
||||||
emit maxValueChanged();
|
emit maxValueChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -297,6 +297,8 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent)
|
|||||||
addInterface("wirelessconnectable", tr("Wireless devices"), {"connectable"});
|
addInterface("wirelessconnectable", tr("Wireless devices"), {"connectable"});
|
||||||
addStateType("wirelessconnectable", "signalStrength", QVariant::UInt, false, tr("Signal strength"), tr("Signal strength changed"));
|
addStateType("wirelessconnectable", "signalStrength", QVariant::UInt, false, tr("Signal strength"), tr("Signal strength changed"));
|
||||||
|
|
||||||
|
addInterface("watersensor", tr("Water sensors"), {"sensor"});
|
||||||
|
addStateType("watersensor", "watterDetected", QVariant::Double, false, tr("Water detected"), tr("Water detected changed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
int Interfaces::rowCount(const QModelIndex &parent) const
|
int Interfaces::rowCount(const QModelIndex &parent) const
|
||||||
|
|||||||
@ -253,5 +253,6 @@
|
|||||||
<file>ui/images/media/ambeo.svg</file>
|
<file>ui/images/media/ambeo.svg</file>
|
||||||
<file>ui/images/thermostat/cooling.svg</file>
|
<file>ui/images/thermostat/cooling.svg</file>
|
||||||
<file>ui/images/thermostat/heating.svg</file>
|
<file>ui/images/thermostat/heating.svg</file>
|
||||||
|
<file>ui/images/sensors/water.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@ -291,6 +291,8 @@ ApplicationWindow {
|
|||||||
return Qt.resolvedUrl("images/sensors/closable.svg")
|
return Qt.resolvedUrl("images/sensors/closable.svg")
|
||||||
case "windspeedsensor":
|
case "windspeedsensor":
|
||||||
return Qt.resolvedUrl("images/sensors/windspeed.svg")
|
return Qt.resolvedUrl("images/sensors/windspeed.svg")
|
||||||
|
case "watersensor":
|
||||||
|
return Qt.resolvedUrl("images/sensors/water.svg")
|
||||||
case "media":
|
case "media":
|
||||||
case "mediacontroller":
|
case "mediacontroller":
|
||||||
case "mediaplayer":
|
case "mediaplayer":
|
||||||
@ -390,6 +392,31 @@ ApplicationWindow {
|
|||||||
id: styleBase
|
id: styleBase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stateColor(stateName) {
|
||||||
|
// Try to load color map from style
|
||||||
|
if (Style.stateColors[stateName]) {
|
||||||
|
return Style.stateColors[stateName];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (styleBase.stateColors[stateName]) {
|
||||||
|
return styleBase.stateColors[stateName];
|
||||||
|
}
|
||||||
|
console.warn("stateColor(): Color not set for state", stateName)
|
||||||
|
return "grey";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stateIcon(stateName) {
|
||||||
|
var iconMap = {
|
||||||
|
"currentPower": "energy.svg",
|
||||||
|
"totalEnergyConsumed": "smartmeter.svg",
|
||||||
|
"totalEnergyProduced": "smartmeter.svg",
|
||||||
|
}
|
||||||
|
if (!iconMap[stateName]) {
|
||||||
|
console.warn("stateIcon(): Icon not set for state", stateName)
|
||||||
|
}
|
||||||
|
return Qt.resolvedUrl("images/" + iconMap[stateName]);
|
||||||
|
}
|
||||||
|
|
||||||
function interfaceToColor(name) {
|
function interfaceToColor(name) {
|
||||||
// Try to load color map from style
|
// Try to load color map from style
|
||||||
if (Style.interfaceColors[name]) {
|
if (Style.interfaceColors[name]) {
|
||||||
|
|||||||
@ -35,13 +35,20 @@ Item {
|
|||||||
"presencesensor": "darkblue",
|
"presencesensor": "darkblue",
|
||||||
"closablesensor": "green",
|
"closablesensor": "green",
|
||||||
"smartmeterproducer": "lightgreen",
|
"smartmeterproducer": "lightgreen",
|
||||||
"smartmeterconsumer": "orange",
|
"extendedsmartmeterproducer": "lightgreen",
|
||||||
"extendedsmartmeterproducer": "blue",
|
"smartmeterconsumer": "deepskyblue",
|
||||||
"extendedsmartmeterconsumer": "blue",
|
"extendedsmartmeterconsumer": "deepskyblue",
|
||||||
"heating" : "gainsboro",
|
"heating" : "gainsboro",
|
||||||
"thermostat": "dodgerblue",
|
"thermostat": "dodgerblue",
|
||||||
"irrigation": "lightblue",
|
"irrigation": "lightblue",
|
||||||
"windspeedsensor": "blue",
|
"windspeedsensor": "blue",
|
||||||
"ventilation": "lightblue"
|
"ventilation": "lightblue",
|
||||||
|
"watersensor": "aqua"
|
||||||
|
}
|
||||||
|
|
||||||
|
property var stateColors: {
|
||||||
|
"totalEnergyConsumed": "orange",
|
||||||
|
"totalEnergyProduced": "lightgreen",
|
||||||
|
"currentPower": "deepskyblue",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,8 +36,8 @@ ToolButton {
|
|||||||
property alias color: image.color
|
property alias color: image.color
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
height: 20
|
height: app.iconSize
|
||||||
width: 20
|
width: app.iconSize
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
id: image
|
id: image
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@ -37,7 +37,8 @@ import Nymea 1.0
|
|||||||
|
|
||||||
ChartView {
|
ChartView {
|
||||||
id: chart
|
id: chart
|
||||||
backgroundColor: Style.backgroundColor
|
backgroundColor: Style.tileBackgroundColor
|
||||||
|
backgroundRoundness: Style.tileRadius
|
||||||
theme: ChartView.ChartThemeLight
|
theme: ChartView.ChartThemeLight
|
||||||
legend.labelColor: Style.foregroundColor
|
legend.labelColor: Style.foregroundColor
|
||||||
legend.font.pixelSize: app.smallFont
|
legend.font.pixelSize: app.smallFont
|
||||||
|
|||||||
@ -44,13 +44,15 @@ Item {
|
|||||||
property Device device: null
|
property Device device: null
|
||||||
property StateType stateType: null
|
property StateType stateType: null
|
||||||
property int roundTo: 2
|
property int roundTo: 2
|
||||||
|
property color color: Style.accentColor
|
||||||
|
property string iconSource: ""
|
||||||
|
property alias title: titleLabel.text
|
||||||
|
|
||||||
readonly property var valueState: device.states.getState(stateType.id)
|
readonly property var valueState: device.states.getState(stateType.id)
|
||||||
readonly property var deviceClass: engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
|
readonly property var deviceClass: engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
|
||||||
readonly property bool hasConnectable: deviceClass.interfaces.indexOf("connectable") >= 0
|
readonly property bool hasConnectable: deviceClass.interfaces.indexOf("connectable") >= 0
|
||||||
readonly property var connectedStateType: hasConnectable ? deviceClass.stateTypes.findByName("connected") : null
|
readonly property var connectedStateType: hasConnectable ? deviceClass.stateTypes.findByName("connected") : null
|
||||||
|
|
||||||
property color color: Style.accentColor
|
|
||||||
property string iconSource: ""
|
|
||||||
|
|
||||||
LogsModelNg {
|
LogsModelNg {
|
||||||
id: logsModelNg
|
id: logsModelNg
|
||||||
@ -72,11 +74,27 @@ Item {
|
|||||||
viewStartTime: xAxis.min
|
viewStartTime: xAxis.min
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ChartView {
|
||||||
|
id: chartView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
margins.top: app.iconSize + app.margins
|
||||||
|
margins.bottom: app.margins / 2
|
||||||
|
margins.left: 0
|
||||||
|
margins.right: 0
|
||||||
|
backgroundColor: Style.tileBackgroundColor
|
||||||
|
backgroundRoundness: Style.tileRadius
|
||||||
|
legend.visible: false
|
||||||
|
legend.labelColor: Style.foregroundColor
|
||||||
|
|
||||||
|
titleColor: Style.foregroundColor
|
||||||
|
titleFont.pixelSize: app.largeFont
|
||||||
|
|
||||||
|
animationDuration: 300
|
||||||
|
animationOptions: ChartView.SeriesAnimations
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
|
anchors { left: parent.left; top: parent.top; right: parent.right; topMargin: app.margins / 2; leftMargin: app.margins * 1.5; rightMargin: app.margins }
|
||||||
|
|
||||||
ColorIcon {
|
ColorIcon {
|
||||||
Layout.preferredHeight: app.iconSize
|
Layout.preferredHeight: app.iconSize
|
||||||
Layout.preferredWidth: app.iconSize
|
Layout.preferredWidth: app.iconSize
|
||||||
@ -84,21 +102,14 @@ Item {
|
|||||||
visible: root.iconSource.length > 0
|
visible: root.iconSource.length > 0
|
||||||
color: root.color
|
color: root.color
|
||||||
}
|
}
|
||||||
|
|
||||||
Led {
|
|
||||||
visible: root.stateType.type.toLowerCase() === "bool"
|
|
||||||
state: root.valueState.value === true ? "on" : "off"
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
id: titleLabel
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: root.stateType.type.toLowerCase() === "bool"
|
text: root.stateType.type.toLowerCase() === "bool"
|
||||||
? root.stateType.displayName
|
? root.stateType.displayName
|
||||||
: 1.0 * Math.round(Types.toUiValue(root.valueState.value, root.stateType.unit) * Math.pow(10, root.roundTo)) / Math.pow(10, root.roundTo) + " " + Types.toUiUnit(root.stateType.unit)
|
: 1.0 * Math.round(Types.toUiValue(root.valueState.value, root.stateType.unit) * Math.pow(10, root.roundTo)) / Math.pow(10, root.roundTo) + " " + Types.toUiUnit(root.stateType.unit)
|
||||||
font.pixelSize: app.largeFont
|
font.pixelSize: app.largeFont
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HeaderButton {
|
HeaderButton {
|
||||||
imageSource: "../images/zoom-out.svg"
|
imageSource: "../images/zoom-out.svg"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
@ -106,7 +117,6 @@ Item {
|
|||||||
xAxis.min = newTime;
|
xAxis.min = newTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HeaderButton {
|
HeaderButton {
|
||||||
imageSource: "../images/zoom-in.svg"
|
imageSource: "../images/zoom-in.svg"
|
||||||
enabled: xAxis.timeDiff > (60 * 30)
|
enabled: xAxis.timeDiff > (60 * 30)
|
||||||
@ -117,333 +127,318 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ChartView {
|
ValueAxis {
|
||||||
id: chartView
|
id: yAxis
|
||||||
Layout.fillWidth: true
|
max: {
|
||||||
Layout.fillHeight: true
|
switch (root.stateType.type.toLowerCase()) {
|
||||||
margins.top: 0
|
case "bool":
|
||||||
margins.bottom: 0
|
return 1;
|
||||||
margins.left: 0
|
default:
|
||||||
margins.right: 0
|
Math.ceil(logsModelNg.maxValue + Math.abs(logsModelNg.maxValue * .05))
|
||||||
backgroundColor: Material.background
|
|
||||||
legend.visible: false
|
|
||||||
legend.labelColor: Style.foregroundColor
|
|
||||||
|
|
||||||
animationDuration: 300
|
|
||||||
animationOptions: ChartView.SeriesAnimations
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: yAxis
|
|
||||||
max: {
|
|
||||||
switch (root.stateType.type.toLowerCase()) {
|
|
||||||
case "bool":
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
Math.ceil(logsModelNg.maxValue + Math.abs(logsModelNg.maxValue * .05))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
min: Math.floor(logsModelNg.minValue - Math.abs(logsModelNg.minValue * .05))
|
|
||||||
// onMinChanged: applyNiceNumbers();
|
|
||||||
// onMaxChanged: applyNiceNumbers();
|
|
||||||
labelsFont.pixelSize: app.smallFont
|
|
||||||
labelFormat: {
|
|
||||||
switch (root.stateType.type.toLowerCase()) {
|
|
||||||
case "bool":
|
|
||||||
return "x";
|
|
||||||
default:
|
|
||||||
return "%d";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
labelsColor: Style.foregroundColor
|
|
||||||
tickCount: root.stateType.type.toLowerCase() === "bool" ? 2 : chartView.height / 40
|
|
||||||
color: Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, .2)
|
|
||||||
gridLineColor: color
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueAxis {
|
|
||||||
id: connectedAxis
|
|
||||||
min: 0
|
|
||||||
max: 1
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTimeAxis {
|
|
||||||
id: xAxis
|
|
||||||
gridVisible: false
|
|
||||||
color: Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, .2)
|
|
||||||
tickCount: chartView.width / 70
|
|
||||||
labelsFont.pixelSize: app.smallFont
|
|
||||||
labelsColor: Style.foregroundColor
|
|
||||||
property int timeDiff: (xAxis.max.getTime() - xAxis.min.getTime()) / 1000
|
|
||||||
|
|
||||||
function getTimeSpanString() {
|
|
||||||
var td = Math.round(timeDiff)
|
|
||||||
if (td < 60) {
|
|
||||||
return qsTr("%n seconds", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td / 60)
|
|
||||||
if (td < 60) {
|
|
||||||
return qsTr("%n minutes", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td / 60)
|
|
||||||
if (td < 48) {
|
|
||||||
return qsTr("%n hours", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td / 24);
|
|
||||||
if (td < 14) {
|
|
||||||
return qsTr("%n days", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td / 7)
|
|
||||||
if (td < 9) {
|
|
||||||
return qsTr("%n weeks", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td * 7 / 30)
|
|
||||||
if (td < 24) {
|
|
||||||
return qsTr("%n months", "", td);
|
|
||||||
}
|
|
||||||
td = Math.round(td * 30 / 356)
|
|
||||||
return qsTr("%n years", "", td)
|
|
||||||
}
|
|
||||||
|
|
||||||
titleText: {
|
|
||||||
if (xAxis.min.getYear() === xAxis.max.getYear()
|
|
||||||
&& xAxis.min.getMonth() === xAxis.max.getMonth()
|
|
||||||
&& xAxis.min.getDate() === xAxis.max.getDate()) {
|
|
||||||
return Qt.formatDate(xAxis.min) + " (" + getTimeSpanString() + ")"
|
|
||||||
}
|
|
||||||
return Qt.formatDate(xAxis.min) + " - " + Qt.formatDate(xAxis.max) + " (" + getTimeSpanString() + ")"
|
|
||||||
}
|
|
||||||
titleBrush: Style.foregroundColor
|
|
||||||
format: {
|
|
||||||
if (timeDiff < 60) { // one minute
|
|
||||||
return "mm:ss"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60) { // one hour
|
|
||||||
return "hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 2) { // two day
|
|
||||||
return "hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 7) { // one week
|
|
||||||
return "ddd hh:mm"
|
|
||||||
}
|
|
||||||
if (timeDiff < 60 * 60 * 24 * 7 * 30) { // one month
|
|
||||||
return "dd.MM."
|
|
||||||
}
|
|
||||||
return "MMM yy"
|
|
||||||
}
|
|
||||||
|
|
||||||
min: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setTime(date.getTime() - (1000 * 60 * 60 * 6) + 2000);
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
max: {
|
|
||||||
var date = new Date();
|
|
||||||
date.setTime(date.getTime() + 2000)
|
|
||||||
return date;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
min: Math.floor(logsModelNg.minValue - Math.abs(logsModelNg.minValue * .05))
|
||||||
AreaSeries {
|
// onMinChanged: applyNiceNumbers();
|
||||||
axisX: xAxis
|
// onMaxChanged: applyNiceNumbers();
|
||||||
axisY: connectedAxis
|
labelsFont.pixelSize: app.smallFont
|
||||||
name: qsTr("Not connected")
|
labelFormat: {
|
||||||
visible: root.hasConnectable
|
switch (root.stateType.type.toLowerCase()) {
|
||||||
upperSeries: LineSeries {
|
case "bool":
|
||||||
XYPoint {x: xAxis.min.getTime(); y: 1}
|
return "x";
|
||||||
XYPoint {x: xAxis.max.getTime(); y: 1}
|
default:
|
||||||
|
return "%d";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
labelsColor: Style.foregroundColor
|
||||||
|
tickCount: root.stateType.type.toLowerCase() === "bool" ? 2 : chartView.height / 40
|
||||||
|
color: Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, .2)
|
||||||
|
gridLineColor: color
|
||||||
|
}
|
||||||
|
|
||||||
lowerSeries: LineSeries {
|
ValueAxis {
|
||||||
id: connectedLineSeries
|
id: connectedAxis
|
||||||
onPointAdded: {
|
min: 0
|
||||||
var newPoint = connectedLineSeries.at(index)
|
max: 1
|
||||||
// print("pointadded", newPoint.x, newPoint.y)
|
visible: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DateTimeAxis {
|
||||||
|
id: xAxis
|
||||||
|
gridVisible: false
|
||||||
|
color: Qt.rgba(Style.foregroundColor.r, Style.foregroundColor.g, Style.foregroundColor.b, .2)
|
||||||
|
tickCount: chartView.width / 70
|
||||||
|
labelsFont.pixelSize: app.smallFont
|
||||||
|
labelsColor: Style.foregroundColor
|
||||||
|
property int timeDiff: (xAxis.max.getTime() - xAxis.min.getTime()) / 1000
|
||||||
|
|
||||||
|
function getTimeSpanString() {
|
||||||
|
var td = Math.round(timeDiff)
|
||||||
|
if (td < 60) {
|
||||||
|
return qsTr("%n seconds", "", td);
|
||||||
}
|
}
|
||||||
color: "#55ff0000"
|
td = Math.round(td / 60)
|
||||||
borderWidth: 0
|
if (td < 60) {
|
||||||
|
return qsTr("%n minutes", "", td);
|
||||||
|
}
|
||||||
|
td = Math.round(td / 60)
|
||||||
|
if (td < 48) {
|
||||||
|
return qsTr("%n hours", "", td);
|
||||||
|
}
|
||||||
|
td = Math.round(td / 24);
|
||||||
|
if (td < 14) {
|
||||||
|
return qsTr("%n days", "", td);
|
||||||
|
}
|
||||||
|
td = Math.round(td / 7)
|
||||||
|
if (td < 9) {
|
||||||
|
return qsTr("%n weeks", "", td);
|
||||||
|
}
|
||||||
|
td = Math.round(td * 7 / 30)
|
||||||
|
if (td < 24) {
|
||||||
|
return qsTr("%n months", "", td);
|
||||||
|
}
|
||||||
|
td = Math.round(td * 30 / 356)
|
||||||
|
return qsTr("%n years", "", td)
|
||||||
}
|
}
|
||||||
|
|
||||||
AreaSeries {
|
titleText: {
|
||||||
id: mainSeries
|
if (xAxis.min.getYear() === xAxis.max.getYear()
|
||||||
axisX: xAxis
|
&& xAxis.min.getMonth() === xAxis.max.getMonth()
|
||||||
axisY: yAxis
|
&& xAxis.min.getDate() === xAxis.max.getDate()) {
|
||||||
name: root.stateType.displayName
|
return Qt.formatDate(xAxis.min) + " (" + getTimeSpanString() + ")"
|
||||||
borderColor: root.color
|
}
|
||||||
borderWidth: 4
|
return Qt.formatDate(xAxis.min) + " - " + Qt.formatDate(xAxis.max) + " (" + getTimeSpanString() + ")"
|
||||||
lowerSeries: LineSeries {
|
}
|
||||||
id: lineSeries0
|
titleBrush: Style.foregroundColor
|
||||||
XYPoint { x: xAxis.max.getTime(); y: 0 }
|
format: {
|
||||||
XYPoint { x: xAxis.min.getTime(); y: 0 }
|
if (timeDiff < 60) { // one minute
|
||||||
|
return "mm:ss"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60) { // one hour
|
||||||
|
return "hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 2) { // two day
|
||||||
|
return "hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 7) { // one week
|
||||||
|
return "ddd hh:mm"
|
||||||
|
}
|
||||||
|
if (timeDiff < 60 * 60 * 24 * 7 * 30) { // one month
|
||||||
|
return "dd.MM."
|
||||||
|
}
|
||||||
|
return "MMM yy"
|
||||||
|
}
|
||||||
|
|
||||||
|
min: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() - (1000 * 60 * 60 * 6) + 2000);
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
max: {
|
||||||
|
var date = new Date();
|
||||||
|
date.setTime(date.getTime() + 2000)
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AreaSeries {
|
||||||
|
axisX: xAxis
|
||||||
|
axisY: connectedAxis
|
||||||
|
name: qsTr("Not connected")
|
||||||
|
visible: root.hasConnectable
|
||||||
|
upperSeries: LineSeries {
|
||||||
|
XYPoint {x: xAxis.min.getTime(); y: 1}
|
||||||
|
XYPoint {x: xAxis.max.getTime(); y: 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
lowerSeries: LineSeries {
|
||||||
|
id: connectedLineSeries
|
||||||
|
onPointAdded: {
|
||||||
|
var newPoint = connectedLineSeries.at(index)
|
||||||
|
// print("pointadded", newPoint.x, newPoint.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
upperSeries: LineSeries {
|
}
|
||||||
id: lineSeries1
|
color: "#55ff0000"
|
||||||
onPointAdded: {
|
borderWidth: 0
|
||||||
var newPoint = lineSeries1.at(index)
|
}
|
||||||
// print("pointadded", newPoint.x, newPoint.y)
|
|
||||||
|
|
||||||
if (newPoint.x > lineSeries0.at(0).x) {
|
AreaSeries {
|
||||||
lineSeries0.replace(0, newPoint.x, 0)
|
id: mainSeries
|
||||||
}
|
axisX: xAxis
|
||||||
if (newPoint.x < lineSeries0.at(1).x) {
|
axisY: yAxis
|
||||||
lineSeries0.replace(1, newPoint.x, 0)
|
name: root.stateType.displayName
|
||||||
}
|
borderColor: root.color
|
||||||
|
borderWidth: 4
|
||||||
|
lowerSeries: LineSeries {
|
||||||
|
id: lineSeries0
|
||||||
|
XYPoint { x: xAxis.max.getTime(); y: 0 }
|
||||||
|
XYPoint { x: xAxis.min.getTime(); y: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
if (newPoint.x <= xAxis.max.getTime() || logsModelNg.busy) {
|
upperSeries: LineSeries {
|
||||||
return;
|
id: lineSeries1
|
||||||
}
|
onPointAdded: {
|
||||||
|
var newPoint = lineSeries1.at(index)
|
||||||
var diffMaxToNew = newPoint.x - xAxis.max.getTime();
|
// print("pointadded", newPoint.x, newPoint.y)
|
||||||
if (diffMaxToNew < 1000 * 60 * 5) {
|
|
||||||
chartView.animationOptions = ChartView.NoAnimation
|
|
||||||
var newMin = xAxis.min.getTime() + diffMaxToNew;
|
|
||||||
xAxis.max = new Date(newPoint.x);
|
|
||||||
xAxis.min = new Date(newMin)
|
|
||||||
chartView.animationOptions = ChartView.SeriesAnimations
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (newPoint.x > lineSeries0.at(0).x) {
|
||||||
|
lineSeries0.replace(0, newPoint.x, 0)
|
||||||
|
}
|
||||||
|
if (newPoint.x < lineSeries0.at(1).x) {
|
||||||
|
lineSeries0.replace(1, newPoint.x, 0)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
color: Qt.rgba(root.color.r, root.color.g, root.color.b, .3)
|
|
||||||
onHovered: {
|
|
||||||
markClosestPoint(point)
|
|
||||||
}
|
|
||||||
|
|
||||||
function markClosestPoint(point) {
|
if (newPoint.x <= xAxis.max.getTime() || logsModelNg.busy) {
|
||||||
if (lineSeries1.count == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lineSeries1.count == 1) {
|
var diffMaxToNew = newPoint.x - xAxis.max.getTime();
|
||||||
selectedHighlights.removePoints(0, selectedHighlights.count)
|
if (diffMaxToNew < 1000 * 60 * 5) {
|
||||||
selectedHighlights.append(lineSeries1.at(0).x, lineSeries1.at(1).y)
|
chartView.animationOptions = ChartView.NoAnimation
|
||||||
return;
|
var newMin = xAxis.min.getTime() + diffMaxToNew;
|
||||||
|
xAxis.max = new Date(newPoint.x);
|
||||||
|
xAxis.min = new Date(newMin)
|
||||||
|
chartView.animationOptions = ChartView.SeriesAnimations
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchIndex = Math.floor(lineSeries1.count / 2)
|
}
|
||||||
var previousIndex = 0;
|
}
|
||||||
var nextIndex = lineSeries1.count - 1;
|
color: Qt.rgba(root.color.r, root.color.g, root.color.b, .3)
|
||||||
|
onHovered: {
|
||||||
|
markClosestPoint(point)
|
||||||
|
}
|
||||||
|
|
||||||
while (previousIndex + 1 != nextIndex) {
|
function markClosestPoint(point) {
|
||||||
if (point.x < lineSeries1.at(searchIndex).x) {
|
if (lineSeries1.count == 0) {
|
||||||
previousIndex = searchIndex;
|
return;
|
||||||
} else if (point.x > lineSeries1.at(searchIndex).x) {
|
}
|
||||||
nextIndex = searchIndex;
|
|
||||||
}
|
|
||||||
searchIndex = previousIndex + Math.floor((nextIndex - previousIndex) / 2);
|
|
||||||
}
|
|
||||||
var diffToPrevious = Math.abs(point.x - lineSeries1.at(previousIndex).x)
|
|
||||||
var diffToNext = Math.abs(point.x - lineSeries1.at(nextIndex).x)
|
|
||||||
var closestPoint = diffToPrevious < diffToNext ? lineSeries1.at(previousIndex) : lineSeries1.at(nextIndex);
|
|
||||||
|
|
||||||
|
if (lineSeries1.count == 1) {
|
||||||
selectedHighlights.removePoints(0, selectedHighlights.count)
|
selectedHighlights.removePoints(0, selectedHighlights.count)
|
||||||
selectedHighlights.append(closestPoint.x, closestPoint.y)
|
selectedHighlights.append(lineSeries1.at(0).x, lineSeries1.at(1).y)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ScatterSeries {
|
var searchIndex = Math.floor(lineSeries1.count / 2)
|
||||||
id: selectedHighlights
|
var previousIndex = 0;
|
||||||
color: root.color
|
var nextIndex = lineSeries1.count - 1;
|
||||||
markerSize: 10
|
|
||||||
borderWidth: 2
|
|
||||||
borderColor: root.color
|
|
||||||
axisX: xAxis
|
|
||||||
axisY: yAxis
|
|
||||||
pointLabelsVisible: root.stateType.type.toLowerCase() !== "bool"
|
|
||||||
pointLabelsColor: Style.foregroundColor
|
|
||||||
pointLabelsFont.pixelSize: app.smallFont
|
|
||||||
pointLabelsFormat: "@yPoint"
|
|
||||||
pointLabelsClipping: false
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
while (previousIndex + 1 != nextIndex) {
|
||||||
anchors.centerIn: parent
|
if (point.x < lineSeries1.at(searchIndex).x) {
|
||||||
visible: logsModelNg.busy
|
previousIndex = searchIndex;
|
||||||
}
|
} else if (point.x > lineSeries1.at(searchIndex).x) {
|
||||||
|
nextIndex = searchIndex;
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: scrollMouseArea
|
|
||||||
x: chartView.plotArea.x
|
|
||||||
y: chartView.plotArea.y
|
|
||||||
width: chartView.plotArea.width
|
|
||||||
height: chartView.plotArea.height
|
|
||||||
property int lastX: 0
|
|
||||||
property int startX: 0
|
|
||||||
preventStealing: false
|
|
||||||
|
|
||||||
property bool autoScroll: true
|
|
||||||
|
|
||||||
function scrollRightLimited(dx) {
|
|
||||||
chartView.animationOptions = ChartView.NoAnimation
|
|
||||||
var now = new Date()
|
|
||||||
// if we're already at the limit, don't even start scrolling
|
|
||||||
if (dx < 0 || xAxis.max < now) {
|
|
||||||
chartView.scrollRight(dx)
|
|
||||||
}
|
}
|
||||||
// figure out if we scrolled too far
|
searchIndex = previousIndex + Math.floor((nextIndex - previousIndex) / 2);
|
||||||
var overshoot = xAxis.max.getTime() - now.getTime()
|
|
||||||
// print("overshoot is:", overshoot, "oldMax", xAxis.max, "newMax", now, "oldMin", xAxis.min, "newMin", new Date(xAxis.min.getTime() - overshoot))
|
|
||||||
if (overshoot > 0) {
|
|
||||||
var range = xAxis.max - xAxis.min
|
|
||||||
xAxis.max = now
|
|
||||||
xAxis.min = new Date(xAxis.max.getTime() - range)
|
|
||||||
}
|
|
||||||
// If the user scrolled closer than 5 pixels to the right edge, enable autoscroll
|
|
||||||
autoScroll = overshoot > -5;
|
|
||||||
|
|
||||||
chartView.animationOptions = ChartView.SeriesAnimations
|
|
||||||
}
|
}
|
||||||
|
var diffToPrevious = Math.abs(point.x - lineSeries1.at(previousIndex).x)
|
||||||
|
var diffToNext = Math.abs(point.x - lineSeries1.at(nextIndex).x)
|
||||||
|
var closestPoint = diffToPrevious < diffToNext ? lineSeries1.at(previousIndex) : lineSeries1.at(nextIndex);
|
||||||
|
|
||||||
function zoomInLimited(dy) {
|
selectedHighlights.removePoints(0, selectedHighlights.count)
|
||||||
chartView.animationOptions = ChartView.NoAnimation
|
selectedHighlights.append(closestPoint.x, closestPoint.y)
|
||||||
var oldMax = xAxis.max;
|
}
|
||||||
chartView.scrollRight(dy);
|
}
|
||||||
xAxis.min = new Date(xAxis.min.getTime() - xAxis.timeDiff * 1000 * 2)
|
|
||||||
chartView.animationOptions = ChartView.SeriesAnimations
|
ScatterSeries {
|
||||||
|
id: selectedHighlights
|
||||||
|
color: root.color
|
||||||
|
markerSize: 10
|
||||||
|
borderWidth: 2
|
||||||
|
borderColor: root.color
|
||||||
|
axisX: xAxis
|
||||||
|
axisY: yAxis
|
||||||
|
pointLabelsVisible: root.stateType.type.toLowerCase() !== "bool"
|
||||||
|
pointLabelsColor: Style.foregroundColor
|
||||||
|
pointLabelsFont.pixelSize: app.smallFont
|
||||||
|
pointLabelsFormat: "@yPoint"
|
||||||
|
pointLabelsClipping: false
|
||||||
|
}
|
||||||
|
|
||||||
|
BusyIndicator {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
visible: logsModelNg.busy
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: scrollMouseArea
|
||||||
|
x: chartView.plotArea.x
|
||||||
|
y: chartView.plotArea.y
|
||||||
|
width: chartView.plotArea.width
|
||||||
|
height: chartView.plotArea.height
|
||||||
|
property int lastX: 0
|
||||||
|
property int startX: 0
|
||||||
|
preventStealing: false
|
||||||
|
|
||||||
|
property bool autoScroll: true
|
||||||
|
|
||||||
|
function scrollRightLimited(dx) {
|
||||||
|
chartView.animationOptions = ChartView.NoAnimation
|
||||||
|
var now = new Date()
|
||||||
|
// if we're already at the limit, don't even start scrolling
|
||||||
|
if (dx < 0 || xAxis.max < now) {
|
||||||
|
chartView.scrollRight(dx)
|
||||||
}
|
}
|
||||||
|
// figure out if we scrolled too far
|
||||||
|
var overshoot = xAxis.max.getTime() - now.getTime()
|
||||||
|
// print("overshoot is:", overshoot, "oldMax", xAxis.max, "newMax", now, "oldMin", xAxis.min, "newMin", new Date(xAxis.min.getTime() - overshoot))
|
||||||
|
if (overshoot > 0) {
|
||||||
|
var range = xAxis.max - xAxis.min
|
||||||
|
xAxis.max = now
|
||||||
|
xAxis.min = new Date(xAxis.max.getTime() - range)
|
||||||
|
}
|
||||||
|
// If the user scrolled closer than 5 pixels to the right edge, enable autoscroll
|
||||||
|
autoScroll = overshoot > -5;
|
||||||
|
|
||||||
onPressed: {
|
chartView.animationOptions = ChartView.SeriesAnimations
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomInLimited(dy) {
|
||||||
|
chartView.animationOptions = ChartView.NoAnimation
|
||||||
|
var oldMax = xAxis.max;
|
||||||
|
chartView.scrollRight(dy);
|
||||||
|
xAxis.min = new Date(xAxis.min.getTime() - xAxis.timeDiff * 1000 * 2)
|
||||||
|
chartView.animationOptions = ChartView.SeriesAnimations
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: {
|
||||||
|
lastX = mouse.x
|
||||||
|
startX = mouse.x
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
var pt = chartView.mapToValue(Qt.point(mouse.x + chartView.plotArea.x, mouse.y + chartView.plotArea.y), mainSeries)
|
||||||
|
mainSeries.markClosestPoint(pt)
|
||||||
|
}
|
||||||
|
|
||||||
|
onWheel: {
|
||||||
|
scrollRightLimited(-wheel.pixelDelta.x)
|
||||||
|
// zoomInLimited(wheel.pixelDelta.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPositionChanged: {
|
||||||
|
if (lastX !== mouse.x) {
|
||||||
|
scrollRightLimited(lastX - mouseX)
|
||||||
lastX = mouse.x
|
lastX = mouse.x
|
||||||
startX = mouse.x
|
|
||||||
}
|
|
||||||
onClicked: {
|
|
||||||
var pt = chartView.mapToValue(Qt.point(mouse.x + chartView.plotArea.x, mouse.y + chartView.plotArea.y), mainSeries)
|
|
||||||
mainSeries.markClosestPoint(pt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWheel: {
|
if (Math.abs(startX - mouse.x) > 10) {
|
||||||
scrollRightLimited(-wheel.pixelDelta.x)
|
preventStealing = true;
|
||||||
// zoomInLimited(wheel.pixelDelta.y)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onPositionChanged: {
|
onReleased: preventStealing = false;
|
||||||
if (lastX !== mouse.x) {
|
|
||||||
scrollRightLimited(lastX - mouseX)
|
|
||||||
lastX = mouse.x
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.abs(startX - mouse.x) > 10) {
|
|
||||||
preventStealing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onReleased: preventStealing = false;
|
|
||||||
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
running: scrollMouseArea.autoScroll
|
running: scrollMouseArea.autoScroll
|
||||||
interval: 1000
|
interval: 1000
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
scrollMouseArea.scrollRightLimited(10)
|
scrollMouseArea.scrollRightLimited(10)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -627,6 +627,7 @@ MainPageTile {
|
|||||||
ListElement { ifaceName: "presencesensor"; stateName: "isPresent" }
|
ListElement { ifaceName: "presencesensor"; stateName: "isPresent" }
|
||||||
ListElement { ifaceName: "closablesensor"; stateName: "closed" }
|
ListElement { ifaceName: "closablesensor"; stateName: "closed" }
|
||||||
ListElement { ifaceName: "lightsensor"; stateName: "lightIntensity" }
|
ListElement { ifaceName: "lightsensor"; stateName: "lightIntensity" }
|
||||||
|
ListElement { ifaceName: "watersensor"; stateName: "waterDetected" }
|
||||||
ListElement { ifaceName: "co2sensor"; stateName: "co2" }
|
ListElement { ifaceName: "co2sensor"; stateName: "co2" }
|
||||||
ListElement { ifaceName: "conductivity"; stateName: "conductivity" }
|
ListElement { ifaceName: "conductivity"; stateName: "conductivity" }
|
||||||
ListElement { ifaceName: "noisesensor"; stateName: "noise" }
|
ListElement { ifaceName: "noisesensor"; stateName: "noise" }
|
||||||
@ -717,6 +718,5 @@ MainPageTile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,6 +85,7 @@ DeviceListPageBase {
|
|||||||
ListElement { interfaceName: "closablesensor"; stateName: "closed" }
|
ListElement { interfaceName: "closablesensor"; stateName: "closed" }
|
||||||
ListElement { interfaceName: "heating"; stateName: "power" }
|
ListElement { interfaceName: "heating"; stateName: "power" }
|
||||||
ListElement { interfaceName: "thermostat"; stateName: "targetTemperature" }
|
ListElement { interfaceName: "thermostat"; stateName: "targetTemperature" }
|
||||||
|
ListElement { interfaceName: "watersensor"; stateName: "waterDetected" }
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: RowLayout {
|
delegate: RowLayout {
|
||||||
@ -128,6 +129,8 @@ DeviceListPageBase {
|
|||||||
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Presence") : qsTr("Vacant");
|
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Presence") : qsTr("Vacant");
|
||||||
case "daylightsensor":
|
case "daylightsensor":
|
||||||
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Daytime") : qsTr("Nighttime");
|
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Daytime") : qsTr("Nighttime");
|
||||||
|
case "watersensor":
|
||||||
|
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Wet") : qsTr("Dry");
|
||||||
case "heating":
|
case "heating":
|
||||||
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("On") : qsTr("Off");
|
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("On") : qsTr("Off");
|
||||||
default:
|
default:
|
||||||
@ -144,7 +147,7 @@ DeviceListPageBase {
|
|||||||
}
|
}
|
||||||
Led {
|
Led {
|
||||||
id: led
|
id: led
|
||||||
visible: sensorValueDelegate.stateType && sensorValueDelegate.stateType.type.toLowerCase() === "bool" && ["presencesensor", "daylightsensor", "heating", "closablesensor"].indexOf(model.interfaceName) < 0
|
visible: sensorValueDelegate.stateType && sensorValueDelegate.stateType.type.toLowerCase() === "bool" && ["presencesensor", "daylightsensor", "heating", "closablesensor", "watersensor"].indexOf(model.interfaceName) < 0
|
||||||
state: visible && sensorValueDelegate.stateValue.value === true ? "on" : "off"
|
state: visible && sensorValueDelegate.stateValue.value === true ? "on" : "off"
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
|
|||||||
@ -103,8 +103,8 @@ DeviceListPageBase {
|
|||||||
Layout.preferredHeight: app.iconSize
|
Layout.preferredHeight: app.iconSize
|
||||||
Layout.preferredWidth: height
|
Layout.preferredWidth: height
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
color: app.interfaceToColor(model.interfaceName)
|
color: app.stateColor(model.stateName)
|
||||||
name: app.interfaceToIcon(model.interfaceName)
|
name: app.stateIcon(model.stateName)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
|
|||||||
@ -41,18 +41,22 @@ DevicePageBase {
|
|||||||
Flickable {
|
Flickable {
|
||||||
id: listView
|
id: listView
|
||||||
anchors { fill: parent }
|
anchors { fill: parent }
|
||||||
|
topMargin: app.margins / 2
|
||||||
interactive: contentHeight > height
|
interactive: contentHeight > height
|
||||||
contentHeight: contentGrid.implicitHeight
|
contentHeight: contentGrid.implicitHeight
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
id: contentGrid
|
id: contentGrid
|
||||||
width: parent.width
|
width: parent.width - app.margins
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
columns: Math.ceil(width / 600)
|
columns: Math.ceil(width / 600)
|
||||||
|
rowSpacing: 0
|
||||||
|
columnSpacing: 0
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var supportedInterfaces = ["temperaturesensor", "humiditysensor", "pressuresensor", "moisturesensor", "lightsensor", "conductivitysensor", "noisesensor", "co2sensor", "presencesensor", "daylightsensor", "closablesensor"]
|
var supportedInterfaces = ["temperaturesensor", "humiditysensor", "pressuresensor", "moisturesensor", "lightsensor", "conductivitysensor", "noisesensor", "co2sensor", "presencesensor", "daylightsensor", "closablesensor", "watersensor"]
|
||||||
for (var i = 0; i < supportedInterfaces.length; i++) {
|
for (var i = 0; i < supportedInterfaces.length; i++) {
|
||||||
if (root.deviceClass.interfaces.indexOf(supportedInterfaces[i]) >= 0) {
|
if (root.deviceClass.interfaces.indexOf(supportedInterfaces[i]) >= 0) {
|
||||||
append({name: supportedInterfaces[i]});
|
append({name: supportedInterfaces[i]});
|
||||||
@ -67,6 +71,7 @@ DevicePageBase {
|
|||||||
Layout.preferredHeight: item.implicitHeight
|
Layout.preferredHeight: item.implicitHeight
|
||||||
|
|
||||||
property StateType stateType: root.deviceClass.stateTypes.findByName(interfaceStateMap[modelData])
|
property StateType stateType: root.deviceClass.stateTypes.findByName(interfaceStateMap[modelData])
|
||||||
|
property State state: root.thing.stateByName(interfaceStateMap[modelData])
|
||||||
property string interfaceName: modelData
|
property string interfaceName: modelData
|
||||||
|
|
||||||
// sourceComponent: stateType && stateType.type.toLowerCase() === "bool" ? boolComponent : graphComponent
|
// sourceComponent: stateType && stateType.type.toLowerCase() === "bool" ? boolComponent : graphComponent
|
||||||
@ -83,7 +88,8 @@ DevicePageBase {
|
|||||||
"co2sensor": "co2",
|
"co2sensor": "co2",
|
||||||
"presencesensor": "isPresent",
|
"presencesensor": "isPresent",
|
||||||
"daylightsensor": "daylight",
|
"daylightsensor": "daylight",
|
||||||
"closablesensor": "closed"
|
"closablesensor": "closed",
|
||||||
|
"watersensor": "waterDetected"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,12 +102,32 @@ DevicePageBase {
|
|||||||
id: graphComponent
|
id: graphComponent
|
||||||
|
|
||||||
GenericTypeGraph {
|
GenericTypeGraph {
|
||||||
|
id: graph
|
||||||
device: root.device
|
device: root.device
|
||||||
color: app.interfaceToColor(interfaceName)
|
color: app.interfaceToColor(interfaceName)
|
||||||
iconSource: app.interfaceToIcon(interfaceName)
|
iconSource: app.interfaceToIcon(interfaceName)
|
||||||
implicitHeight: width * .6
|
implicitHeight: width * .6
|
||||||
property string interfaceName: parent.interfaceName
|
property string interfaceName: parent.interfaceName
|
||||||
stateType: parent.stateType
|
stateType: parent.stateType
|
||||||
|
property State state: parent.state
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: graph
|
||||||
|
property: "title"
|
||||||
|
when: ["presencesensor", "daylightsensor", "closablesensor", "watersensor"].indexOf(graph.interfaceName) >= 0
|
||||||
|
value: {
|
||||||
|
switch (graph.interfaceName) {
|
||||||
|
case "presencesensor":
|
||||||
|
return graph.state.value === true ? qsTr("Presence") : qsTr("Vacant")
|
||||||
|
case "daylightsensor":
|
||||||
|
return graph.state.value === true ? qsTr("Daytimet") : qsTr("Nighttime")
|
||||||
|
case "closablesensor":
|
||||||
|
return graph.state.value === true ? qsTr("Closed") : qsTr("Open")
|
||||||
|
case "watersensor":
|
||||||
|
return graph.state.value === true ? qsTr("Wet") : qsTr("Dry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,41 +38,67 @@ import "../customviews"
|
|||||||
DevicePageBase {
|
DevicePageBase {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property State totalEnergyConsumedState: root.thing.stateByName("totalEnergyConsumed")
|
||||||
|
readonly property StateType totalEnergyConsumedStateType: root.thing.thingClass.stateTypes.findByName("totalEnergyConsumed")
|
||||||
|
readonly property State totalEnergyProducedState: root.thing.stateByName("totalEnergyProduced")
|
||||||
|
readonly property StateType totalEnergyProducedStateType: root.thing.thingClass.stateTypes.findByName("totalEnergyProduced")
|
||||||
|
|
||||||
Flickable {
|
Flickable {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
topMargin: app.margins / 2
|
||||||
contentHeight: contentGrid.height
|
contentHeight: contentGrid.height
|
||||||
interactive: contentHeight > height
|
interactive: contentHeight > height
|
||||||
|
|
||||||
GridLayout {
|
GridLayout {
|
||||||
id: contentGrid
|
id: contentGrid
|
||||||
width: parent.width
|
width: parent.width - app.margins
|
||||||
columns: Math.min(width / 300, contentModel.count)
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
columns: 1
|
||||||
|
|
||||||
Repeater {
|
BigTile {
|
||||||
model: ListModel {
|
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||||
id: contentModel
|
showHeader: true
|
||||||
Component.onCompleted: {
|
header: Label {
|
||||||
if (root.deviceClass.interfaces.indexOf("extendedsmartmeterproducer") >= 0
|
text: qsTr("Total energy consumption")
|
||||||
|| root.deviceClass.interfaces.indexOf("extendedsmartmeterconsumer") >= 0) {
|
}
|
||||||
append( {interface: "extendedsmartmeterproducer", stateTypeName: "currentPower" })
|
|
||||||
}
|
contentItem: RowLayout {
|
||||||
if (root.deviceClass.interfaces.indexOf("smartmeterproducer") >= 0) {
|
ColorIcon {
|
||||||
append( {interface: "smartmeterproducer", stateTypeName: "totalEnergyProduced" })
|
Layout.preferredHeight: app.iconSize
|
||||||
}
|
Layout.preferredWidth: app.iconSize
|
||||||
if (root.deviceClass.interfaces.indexOf("smartmeterconsumer") >= 0) {
|
name: app.stateIcon("totalEnergyConsumed")
|
||||||
append( {interface: "smartmeterconsumer", stateTypeName: "totalEnergyConsumed" })
|
color: app.stateColor("totalEnergyConsumed")
|
||||||
}
|
}
|
||||||
print("shown graphs are", count)
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.totalEnergyConsumedState.value.toFixed(2) + " " + root.totalEnergyConsumedStateType.unitString
|
||||||
|
font.pixelSize: app.largeFont
|
||||||
|
}
|
||||||
|
ColorIcon {
|
||||||
|
Layout.preferredHeight: app.iconSize
|
||||||
|
Layout.preferredWidth: app.iconSize
|
||||||
|
name: app.stateIcon("totalEnergyProduced")
|
||||||
|
color: app.stateColor("totalEnergyProduced")
|
||||||
|
visible: root.totalEnergyProducedState !== null
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: root.totalEnergyProducedState.value.toFixed(2) + " " + root.totalEnergyProducedStateType.unitString
|
||||||
|
font.pixelSize: app.largeFont
|
||||||
|
visible: root.totalEnergyProducedState !== null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delegate: GenericTypeGraph {
|
}
|
||||||
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
|
||||||
device: root.device
|
GenericTypeGraph {
|
||||||
stateType: root.deviceClass.stateTypes.findByName(model.stateTypeName)
|
Layout.preferredWidth: contentGrid.width / contentGrid.columns
|
||||||
color: app.interfaceToColor(model.interface)
|
device: root.device
|
||||||
iconSource: app.interfaceToIcon(model.interface)
|
stateType: root.deviceClass.stateTypes.findByName("currentPower")
|
||||||
roundTo: 5
|
color: app.stateColor("currentPower")
|
||||||
}
|
iconSource: app.stateIcon("currentPower")
|
||||||
|
roundTo: 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
177
nymea-app/ui/images/sensors/water.svg
Normal file
177
nymea-app/ui/images/sensors/water.svg
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="96"
|
||||||
|
height="96"
|
||||||
|
id="svg4874"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="1.0.1 (1.0.1+r74)"
|
||||||
|
viewBox="0 0 96 96.000001"
|
||||||
|
sodipodi:docname="water.svg">
|
||||||
|
<defs
|
||||||
|
id="defs4876" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="5.6199993"
|
||||||
|
inkscape:cx="42.494274"
|
||||||
|
inkscape:cy="50.51304"
|
||||||
|
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:document-rotation="0"
|
||||||
|
inkscape:window-width="1380"
|
||||||
|
inkscape:window-height="873"
|
||||||
|
inkscape:window-x="60"
|
||||||
|
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" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</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:0.8;marker:none;enable-background:accumulate"
|
||||||
|
d="m 410.99179,429.36224 h -4.0016 c 0,0 4.20227,-10.94333 4.00158,-19.82534 -0.20069,-8.88201 -7.79075,-23.17621 -8.00316,-32.09889 -0.21242,-8.92267 4.00158,-20.07579 4.00158,-20.07579 h 4.0016 c 0,0 -4.2233,11.28389 -4.00158,20.2116 0.22172,8.92771 7.80091,23.13419 8.00316,31.99414 0.20225,8.85995 -4.00158,19.79428 -4.00158,19.79428 z"
|
||||||
|
id="path4182"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cczzcczzc" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;marker:none;enable-background:accumulate"
|
||||||
|
d="m 392.09463,429.36224 h -4.0016 c 0,0 4.20227,-10.94333 4.00158,-19.82534 -0.20069,-8.88201 -7.79075,-23.17621 -8.00316,-32.09889 -0.21242,-8.92267 4.00158,-20.07579 4.00158,-20.07579 h 4.0016 c 0,0 -4.2233,11.28389 -4.00158,20.2116 0.22172,8.92771 7.80091,23.13419 8.00316,31.99414 0.20225,8.85995 -4.00158,19.79428 -4.00158,19.79428 z"
|
||||||
|
id="path851"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cczzcczzc" />
|
||||||
|
<path
|
||||||
|
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8;marker:none;enable-background:accumulate"
|
||||||
|
d="m 373.01945,429.36224 h -4.0016 c 0,0 4.20227,-10.94333 4.00158,-19.82534 -0.20069,-8.88201 -7.79075,-23.17621 -8.00316,-32.09889 -0.21242,-8.92267 4.00158,-20.07579 4.00158,-20.07579 h 4.0016 c 0,0 -4.2233,11.28389 -4.00158,20.2116 0.22172,8.92771 7.80091,23.13419 8.00316,31.99414 0.20225,8.85995 -4.00158,19.79428 -4.00158,19.79428 z"
|
||||||
|
id="path853"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="cczzcczzc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 6.5 KiB |
@ -79,7 +79,8 @@ MainViewBase {
|
|||||||
legend.alignment: Qt.AlignBottom
|
legend.alignment: Qt.AlignBottom
|
||||||
legend.font.pixelSize: app.smallFont
|
legend.font.pixelSize: app.smallFont
|
||||||
legend.visible: false
|
legend.visible: false
|
||||||
backgroundColor: Style.backgroundColor
|
backgroundColor: Style.tileBackgroundColor
|
||||||
|
backgroundRoundness: Style.tileRadius
|
||||||
titleColor: Style.foregroundColor
|
titleColor: Style.foregroundColor
|
||||||
title: qsTr("Power usage history")
|
title: qsTr("Power usage history")
|
||||||
|
|
||||||
@ -150,7 +151,7 @@ MainViewBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
print("creating series")
|
print("creating series", consumer.thing.name, index)
|
||||||
seriesAdapter.ensureSamples(xAxis.min, xAxis.max)
|
seriesAdapter.ensureSamples(xAxis.min, xAxis.max)
|
||||||
var areaSeries = chartView.createSeries(ChartView.SeriesTypeArea, consumer.thing.name, xAxis, yAxis)
|
var areaSeries = chartView.createSeries(ChartView.SeriesTypeArea, consumer.thing.name, xAxis, yAxis)
|
||||||
areaSeries.upperSeries = upperSeries;
|
areaSeries.upperSeries = upperSeries;
|
||||||
@ -179,8 +180,8 @@ MainViewBase {
|
|||||||
ValueAxis {
|
ValueAxis {
|
||||||
id: yAxis
|
id: yAxis
|
||||||
readonly property XYSeriesAdapter adapter: consumersRepeater.itemAt(consumersRepeater.count - 1).adapter;
|
readonly property XYSeriesAdapter adapter: consumersRepeater.itemAt(consumersRepeater.count - 1).adapter;
|
||||||
max: Math.ceil(adapter.maxValue + Math.abs(adapter.maxValue * .05))
|
max: Math.ceil(Math.max(adapter.maxValue * 0.95, adapter.maxValue * 1.05))
|
||||||
min: Math.floor(adapter.minValue - Math.abs(adapter.minValue * .05))
|
min: Math.floor(Math.min(adapter.minValue * 0.95, adapter.minValue * 1.05))
|
||||||
// This seems to crash occationally
|
// This seems to crash occationally
|
||||||
// onMinChanged: applyNiceNumbers();
|
// onMinChanged: applyNiceNumbers();
|
||||||
// onMaxChanged: applyNiceNumbers();
|
// onMaxChanged: applyNiceNumbers();
|
||||||
@ -354,6 +355,8 @@ MainViewBase {
|
|||||||
SmartMeterChart {
|
SmartMeterChart {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: width * .7
|
Layout.preferredHeight: width * .7
|
||||||
|
backgroundColor: Style.tileBackgroundColor
|
||||||
|
backgroundRoundness: Style.tileRadius
|
||||||
meters: producers
|
meters: producers
|
||||||
title: qsTr("Total produced energy")
|
title: qsTr("Total produced energy")
|
||||||
visible: producers.count > 0
|
visible: producers.count > 0
|
||||||
|
|||||||
Reference in New Issue
Block a user