diff --git a/libnymea-app-core/models/logsmodelng.cpp b/libnymea-app-core/models/logsmodelng.cpp
index 11b821eb..71b8bdc1 100644
--- a/libnymea-app-core/models/logsmodelng.cpp
+++ b/libnymea-app-core/models/logsmodelng.cpp
@@ -163,13 +163,13 @@ void LogsModelNg::setViewStartTime(const QDateTime &viewStartTime)
QVariant LogsModelNg::minValue() const
{
- qDebug() << "returning min value" << m_minValue;
+// qDebug() << "returning min value" << m_minValue;
return m_minValue;
}
QVariant LogsModelNg::maxValue() const
{
- qDebug() << "returning max value" << m_maxValue;
+// qDebug() << "returning max value" << m_maxValue;
return m_maxValue;
}
@@ -177,8 +177,6 @@ void LogsModelNg::logsReply(const QVariantMap &data)
{
// qDebug() << "logs reply" << data;
- m_busy = false;
- emit busyChanged();
int offset = data.value("params").toMap().value("offset").toInt();
int count = data.value("params").toMap().value("count").toInt();
@@ -221,20 +219,20 @@ void LogsModelNg::logsReply(const QVariantMap &data)
if (i > 0) {
LogEntry *newerEntry = newBlock.at(i - 1);
if (newerEntry->value().toBool() != entry->value().toBool()) {
- qDebug() << "Adding bool line series point:" << (newerEntry->timestamp().addSecs(-1)) << newerEntry->timestamp().addSecs(-1).toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0) << "(correction)";
+// qDebug() << "Adding bool line series point:" << (newerEntry->timestamp().addSecs(-1)) << newerEntry->timestamp().addSecs(-1).toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0) << "(correction)";
m_graphSeries->append(QPointF(newerEntry->timestamp().addSecs(-1).toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
}
}
if (m_graphSeries->count() == 0) {
// If it's the first one, make sure we add an ending point at 1
- qDebug() << "Adding bool line series point:" << QDateTime::currentDateTime() << QDateTime::currentDateTime().toMSecsSinceEpoch() - 1 << (entry->value().toBool() ? 1 : 0) << "(beginning)";
+// qDebug() << "Adding bool line series point:" << QDateTime::currentDateTime() << QDateTime::currentDateTime().toMSecsSinceEpoch() - 1 << (entry->value().toBool() ? 1 : 0) << "(beginning)";
m_graphSeries->append(QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), 1));
m_graphSeries->append(QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
} else if (i == 0) {
// Adding a new batch... remove the last appended 1 from the previous batch
m_graphSeries->remove(m_graphSeries->count() - 1);
}
- qDebug() << "Adding bool line series point:" << entry->timestamp() << entry->timestamp().toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0);
+// qDebug() << "Adding bool line series point:" << entry->timestamp() << entry->timestamp().toMSecsSinceEpoch() << (entry->value().toBool() ? 1 : 0);
m_graphSeries->append(QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toBool() ? 1 : 0));
if (i == newBlock.count() - 1) {
// End the batch at 1 again
@@ -248,8 +246,10 @@ void LogsModelNg::logsReply(const QVariantMap &data)
// m_graphSeries->append(QPointF(newerEntry->timestamp().toMSecsSinceEpoch() - 1, entry->value().toReal()));
// }
// }
+
if (m_graphSeries->count() == 0) {
- m_graphSeries->insert(0, QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), entry->value().toReal()));
+ qDebug() << "Adding 1st line series point:" << (offset + i) << QDateTime::currentDateTime().toMSecsSinceEpoch() << entry->value().toReal();
+ m_graphSeries->append(QPointF(QDateTime::currentDateTime().toMSecsSinceEpoch(), entry->value().toReal()));
}
qDebug() << "Adding line series point:" << (offset + i) << entry->timestamp().toMSecsSinceEpoch() << (entry->value().toReal());
m_graphSeries->append(QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toReal()));
@@ -264,7 +264,7 @@ void LogsModelNg::logsReply(const QVariantMap &data)
}
endInsertRows();
emit countChanged();
- qDebug() << "min" << m_minValue << "max" << m_maxValue << "newMin" << newMin << "newMax" << newMax;
+// qDebug() << "min" << m_minValue << "max" << m_maxValue << "newMin" << newMin << "newMax" << newMax;
if (m_minValue != newMin) {
m_minValue = newMin;
emit minValueChanged();
@@ -274,6 +274,9 @@ void LogsModelNg::logsReply(const QVariantMap &data)
emit maxValueChanged();
}
+ m_busy = false;
+ emit busyChanged();
+
if (m_viewStartTime.isValid() && m_list.count() > 0 && m_list.last()->timestamp() > m_viewStartTime && canFetchMore()) {
fetchMore();
}
@@ -282,7 +285,7 @@ void LogsModelNg::logsReply(const QVariantMap &data)
void LogsModelNg::fetchMore(const QModelIndex &parent)
{
Q_UNUSED(parent)
- qDebug() << "fetchMore called";
+// qDebug() << "fetchMore called";
if (!m_engine) {
qWarning() << "Cannot update. Engine not set";
@@ -326,13 +329,13 @@ void LogsModelNg::fetchMore(const QModelIndex &parent)
params.insert("offset", m_list.count());
m_engine->jsonRpcClient()->sendCommand("Logging.GetLogEntries", params, this, "logsReply");
- qDebug() << "GetLogEntries called";
+// qDebug() << "GetLogEntries called";
}
bool LogsModelNg::canFetchMore(const QModelIndex &parent) const
{
Q_UNUSED(parent)
- qDebug() << "canFetchMore" << (m_engine && m_canFetchMore);
+// qDebug() << "canFetchMore" << (m_engine && m_canFetchMore);
return m_engine && m_canFetchMore;
}
@@ -364,6 +367,15 @@ void LogsModelNg::newLogEntryReceived(const QVariantMap &data)
m_list.prepend(entry);
if (m_graphSeries) {
m_graphSeries->insert(0, QPointF(entry->timestamp().toMSecsSinceEpoch(), entry->value().toReal()));
+ if (m_minValue > entry->value().toReal()) {
+ m_minValue = entry->value().toReal();
+ emit minValueChanged();
+ }
+ if (m_maxValue < entry->value().toReal()) {
+ m_maxValue = entry->value().toReal();
+ emit maxValueChanged();
+ }
+
}
endInsertRows();
emit countChanged();
diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc
index 337433fe..37ca322f 100644
--- a/nymea-app/images.qrc
+++ b/nymea-app/images.qrc
@@ -150,5 +150,6 @@
ui/images/weather-app-symbolic.svg
ui/images/zoom-out.svg
ui/images/zoom-in.svg
+ ui/images/smartmeter.svg
diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc
index ee60f6c4..21499768 100644
--- a/nymea-app/resources.qrc
+++ b/nymea-app/resources.qrc
@@ -57,6 +57,7 @@
ui/customviews/MediaControllerView.qml
ui/customviews/SensorView.qml
ui/customviews/NotificationsView.qml
+ ui/customviews/ExtendedVolumeController.qml
ui/devicepages/MediaDevicePage.qml
ui/devicepages/ButtonDevicePage.qml
ui/devicepages/GenericDeviceStateDetailsPage.qml
@@ -133,6 +134,6 @@
../LICENSE
ui/customviews/GenericTypeGraphPre110.qml
ui/customviews/GenericTypeGraph.qml
- ui/customviews/SensorChart.qml
+ ui/devicepages/SmartMeterDevicePage.qml
diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml
index dd88c856..65116fc8 100644
--- a/nymea-app/ui/Nymea.qml
+++ b/nymea-app/ui/Nymea.qml
@@ -53,7 +53,7 @@ ApplicationWindow {
rootItem.handleCloseEvent(close)
}
- property var supportedInterfaces: ["light", "weather", "sensor", "media", "garagegate", "awning", "shutter", "blind", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
+ property var supportedInterfaces: ["light", "weather", "sensor", "media", "garagegate", "awning", "shutter", "blind", "smartmeter", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
function interfaceToString(name) {
switch(name) {
case "light":
@@ -93,6 +93,8 @@ ApplicationWindow {
return qsTr("Garage gates");
case "accesscontrol":
return qsTr("Access control");
+ case "smartmeter":
+ return qsTr("Smart meter");
case "uncategorized":
return qsTr("Uncategorized")
default:
@@ -149,8 +151,6 @@ ApplicationWindow {
return Qt.resolvedUrl("images/network-wired-symbolic.svg")
case "notifications":
return Qt.resolvedUrl("images/notification.svg")
- case "connectable":
- return Qt.resolvedUrl("images/stock_link.svg")
case "inputtrigger":
return Qt.resolvedUrl("images/attention.svg")
case "outputtrigger":
@@ -175,6 +175,14 @@ ApplicationWindow {
return Qt.resolvedUrl("images/fingerprint.svg")
case "accesscontrol":
return Qt.resolvedUrl("images/network-secure.svg");
+ case "smartmeter":
+ case "smartmeterconsumer":
+ case "smartmeterproducer":
+ case "extendedsmartmeterconsumer":
+ case "extendedsmartmeterproducer":
+ return Qt.resolvedUrl("images/smartmeter.svg")
+ case "connectable":
+ return Qt.resolvedUrl("images/stock_link.svg")
default:
console.warn("InterfaceToIcon: Unhandled interface", name)
}
@@ -187,7 +195,11 @@ ApplicationWindow {
"moisturesensor":"blue",
"lightsensor": "orange",
"conductivitysensor": "green",
- "pressuresensor": "grey"
+ "pressuresensor": "grey",
+ "smartmeterproducer": "lightgreen",
+ "smartmeterconsumer": "orange",
+ "extendedsmartmeterproducer": "blue",
+ "extendedsmartmeterconsumer": "blue"
}
function interfaceToColor(name) {
@@ -244,6 +256,8 @@ ApplicationWindow {
page = "NotificationsDevicePage.qml";
} else if (interfaceList.indexOf("fingerprintreader") >= 0) {
page = "FingerprintReaderDevicePage.qml";
+ } else if (interfaceList.indexOf("smartmeter") >= 0) {
+ page = "SmartMeterDevicePage.qml"
} else {
page = "GenericDevicePage.qml";
}
diff --git a/nymea-app/ui/customviews/GenericTypeGraph.qml b/nymea-app/ui/customviews/GenericTypeGraph.qml
index 4b8c3a21..964b8827 100644
--- a/nymea-app/ui/customviews/GenericTypeGraph.qml
+++ b/nymea-app/ui/customviews/GenericTypeGraph.qml
@@ -9,10 +9,11 @@ import QtCharts 2.2
Item {
id: root
+ implicitHeight: width * .6
property var device: null
property var stateType: null
- 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 bool hasConnectable: deviceClass.interfaces.indexOf("connectable") >= 0
readonly property var connectedStateType: hasConnectable ? deviceClass.stateTypes.findByName("connected") : null
@@ -94,8 +95,8 @@ Item {
ValueAxis {
id: yAxis
- min: logsModelNg.minValue - logsModelNg.minValue * .05
- max: logsModelNg.maxValue + logsModelNg.maxValue * .05
+ max: logsModelNg.maxValue + Math.abs(logsModelNg.maxValue * .05)
+ min: logsModelNg.minValue - Math.abs(logsModelNg.minValue * .05)
labelsFont.pixelSize: app.smallFont
labelsColor: app.foregroundColor
tickCount: chartView.height / 40
@@ -179,10 +180,14 @@ Item {
min: {
var date = new Date();
- date.setHours(date.getHours() - 6);
+ date.setTime(date.getTime() - (1000 * 60 * 60 * 6) + 2000);
+ return date;
+ }
+ max: {
+ var date = new Date();
+ date.setTime(date.getTime() + 2000)
return date;
}
- max: new Date()
}
AreaSeries {
@@ -209,8 +214,38 @@ Item {
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 }
+ }
+
upperSeries: LineSeries {
id: lineSeries1
+ onPointAdded: {
+ var newPoint = lineSeries1.at(index)
+
+ 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)
+ }
+
+ if (newPoint.x <= xAxis.max.getTime() || logsModelNg.busy) {
+ return;
+ }
+
+ var diffMaxToNew = newPoint.x - xAxis.max.getTime();
+ print("diffToNew is", diffMaxToNew)
+ 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
+ }
+ }
}
color: Qt.rgba(root.color.r, root.color.g, root.color.b, .3)
onHovered: {
@@ -268,9 +303,13 @@ Item {
MouseArea {
- anchors.fill: parent
+ x: chartView.plotArea.x
+ y: chartView.plotArea.y
+ width: chartView.plotArea.width
+ height: chartView.plotArea.height
property int lastX: 0
property int lastY: 0
+ preventStealing: false
function scrollRightLimited(dx) {
chartView.animationOptions = ChartView.NoAnimation
@@ -303,7 +342,7 @@ Item {
lastY = mouse.y
}
onClicked: {
- var pt = chartView.mapToValue(Qt.point(mouse.x, mouse.y), mainSeries)
+ var pt = chartView.mapToValue(Qt.point(mouse.x + chartView.plotArea.x, mouse.y + chartView.plotArea.y), mainSeries)
mainSeries.markClosestPoint(pt)
}
diff --git a/nymea-app/ui/customviews/SensorChart.qml b/nymea-app/ui/customviews/SensorChart.qml
deleted file mode 100644
index d2cadaf8..00000000
--- a/nymea-app/ui/customviews/SensorChart.qml
+++ /dev/null
@@ -1,28 +0,0 @@
-import QtQuick 2.5
-import QtQuick.Controls 2.1
-import QtQuick.Controls.Material 2.1
-import QtQuick.Layouts 1.3
-import "../components"
-import Nymea 1.0
-
-CustomViewBase {
- id: root
- implicitHeight: width * .6
- property string interfaceName
-
- readonly property string stateTypeName: {
- switch (interfaceName) {
- case "lightsensor":
- return "lightIntensity";
- default:
- return interfaceName.replace("sensor", "");
- }
- }
- GenericTypeGraph {
- anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.bottom }
- device: root.device
- stateType: root.deviceClass.stateTypes.findByName(root.stateTypeName)
- color: app.interfaceToColor(root.interfaceName)
- iconSource: app.interfaceToIcon(root.interfaceName)
- }
-}
diff --git a/nymea-app/ui/devicepages/SensorDevicePagePost110.qml b/nymea-app/ui/devicepages/SensorDevicePagePost110.qml
index 135bef73..bd4330df 100644
--- a/nymea-app/ui/devicepages/SensorDevicePagePost110.qml
+++ b/nymea-app/ui/devicepages/SensorDevicePagePost110.qml
@@ -18,10 +18,21 @@ ListView {
}
}
}
- delegate: SensorChart {
+ delegate: GenericTypeGraph {
width: parent.width
- interfaceName: modelData
device: root.device
- deviceClass: root.deviceClass
+ stateType: root.deviceClass.stateTypes.findByName(stateTypeName)
+ color: app.interfaceToColor(modelData)
+ iconSource: app.interfaceToIcon(modelData)
+
+ implicitHeight: width * .6
+ property string stateTypeName: {
+ switch (modelData) {
+ case "lightsensor":
+ return "lightIntensity";
+ default:
+ return modelData.replace("sensor", "");
+ }
+ }
}
}
diff --git a/nymea-app/ui/devicepages/SmartMeterDevicePage.qml b/nymea-app/ui/devicepages/SmartMeterDevicePage.qml
new file mode 100644
index 00000000..961f7dee
--- /dev/null
+++ b/nymea-app/ui/devicepages/SmartMeterDevicePage.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.5
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.1
+import Nymea 1.0
+import "../components"
+import "../customviews"
+
+DevicePageBase {
+ id: root
+
+ ListView {
+ anchors { fill: parent }
+ model: ListModel {
+ Component.onCompleted: {
+ if (root.deviceClass.interfaces.indexOf("extendedsmartmeterproducer") >= 0
+ || root.deviceClass.interfaces.indexOf("extendedsmartmeterconsumer") >= 0) {
+ append( {interface: "extendedsmartmeterproducer", stateTypeName: "currentPower" })
+ }
+ if (root.deviceClass.interfaces.indexOf("smartmeterproducer") >= 0) {
+ append( {interface: "smartmeterproducer", stateTypeName: "totalEnergyProduced" })
+ }
+ if (root.deviceClass.interfaces.indexOf("smartmeterconsumer") >= 0) {
+ append( {interface: "smartmeterconsumer", stateTypeName: "totalEnergyConsumed" })
+ }
+ print("shown graphs are", count)
+ }
+ }
+ delegate: ColumnLayout {
+ width: parent.width
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.topMargin: app.margins; Layout.rightMargin: app.rightMargins;
+ text: root.deviceClass.stateTypes.findByName(model.stateTypeName).displayName
+ }
+ GenericTypeGraph {
+ Layout.fillWidth: true
+ device: root.device
+ stateType: root.deviceClass.stateTypes.findByName(model.stateTypeName)
+ color: app.interfaceToColor(model.interface)
+ iconSource: app.interfaceToIcon(model.interface)
+ }
+ }
+ }
+}
diff --git a/nymea-app/ui/images/smartmeter.svg b/nymea-app/ui/images/smartmeter.svg
new file mode 100644
index 00000000..4bd777f8
--- /dev/null
+++ b/nymea-app/ui/images/smartmeter.svg
@@ -0,0 +1,202 @@
+
+