From 0e89d62db800bad291ae30dca668d9113bc2870d Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 2 Jan 2021 13:04:16 +0100 Subject: [PATCH] Improve thermostat views --- nymea-app/images.qrc | 2 + nymea-app/resources.qrc | 2 + nymea-app/ui/Nymea.qml | 9 +- nymea-app/ui/components/Dial.qml | 23 +- .../ui/customviews/ThermostatController.qml | 237 ++++++++++++++++++ nymea-app/ui/delegates/InterfaceTile.qml | 1 + .../ui/devicepages/HeatingDevicePage.qml | 87 +++---- .../ui/devicepages/ThermostatDevicePage.qml | 106 ++++++++ nymea-app/ui/images/thermostat/cooling.svg | 231 +++++++++++++++++ nymea-app/ui/images/thermostat/heating.svg | 193 ++++++++++++++ nymea-app/ui/utils/NymeaUtils.qml | 4 +- 11 files changed, 826 insertions(+), 69 deletions(-) create mode 100644 nymea-app/ui/customviews/ThermostatController.qml create mode 100644 nymea-app/ui/devicepages/ThermostatDevicePage.qml create mode 100644 nymea-app/ui/images/thermostat/cooling.svg create mode 100644 nymea-app/ui/images/thermostat/heating.svg diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc index 91925329..9ee9ca9c 100644 --- a/nymea-app/images.qrc +++ b/nymea-app/images.qrc @@ -251,5 +251,7 @@ ui/images/discord.svg ui/images/media/equalizer.svg ui/images/media/ambeo.svg + ui/images/thermostat/cooling.svg + ui/images/thermostat/heating.svg diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc index 5e21b685..740daa7d 100644 --- a/nymea-app/resources.qrc +++ b/nymea-app/resources.qrc @@ -230,5 +230,7 @@ ui/components/ColorTemperaturePicker.qml ui/components/ThingContextMenu.qml ui/StyleBase.qml + ui/customviews/ThermostatController.qml + ui/devicepages/ThermostatDevicePage.qml diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml index 2d500aad..11982c8e 100644 --- a/nymea-app/ui/Nymea.qml +++ b/nymea-app/ui/Nymea.qml @@ -69,6 +69,7 @@ ApplicationWindow { property int smallFont: 13 property int mediumFont: 16 property int largeFont: 20 + property int hugeFont: 40 property int smallIconSize: 16 property int iconSize: 24 @@ -145,6 +146,7 @@ ApplicationWindow { "blind", "garagedoor", "powersocket", + "thermostat", "heating", "smartlock", "doorbell", @@ -218,6 +220,8 @@ ApplicationWindow { return qsTr("Smart meters"); case "heating": return qsTr("Heating"); + case "thermostat": + return qsTr("Thermostats"); case "evcharger": return qsTr("EV-chargers"); case "powersocket": @@ -341,8 +345,9 @@ ApplicationWindow { case "extendedsmartmeterproducer": return Qt.resolvedUrl("images/smartmeter.svg") case "heating": - case "extendedheating": - return Qt.resolvedUrl("images/radiator.svg") + return Qt.resolvedUrl("images/thermostat/heating.svg") + case "cooling": + return Qt.resolvedUrl("images/thermostat/cooling.svg") case "thermostat": return Qt.resolvedUrl("images/dial.svg") case "evcharger": diff --git a/nymea-app/ui/components/Dial.qml b/nymea-app/ui/components/Dial.qml index ea29109a..3d51079f 100644 --- a/nymea-app/ui/components/Dial.qml +++ b/nymea-app/ui/components/Dial.qml @@ -37,7 +37,8 @@ import QtQuick.Controls.Material 2.2 ColumnLayout { id: dial - property Device device: null + property Thing thing: null + property alias device: dial.thing property StateType stateType: null property bool showValueLabel: true @@ -53,14 +54,14 @@ ColumnLayout { return (to - from) * angle / maxAngle + from } - readonly property State deviceState: device && stateType ? device.states.getState(stateType.id) : null + readonly property State deviceState: thing && stateType ? thing.states.getState(stateType.id) : null readonly property double from: dial.stateType ? dial.stateType.minValue : 0 readonly property double to: dial.stateType ? dial.stateType.maxValue : 100 readonly property double anglePerStep: maxAngle / dial.steps readonly property double startAngle: -(dial.steps * dial.anglePerStep) / 2 - readonly property StateType powerStateType: dial.device.deviceClass.stateTypes.findByName("power") - readonly property State powerState: powerStateType ? dial.device.states.getState(powerStateType.id) : null + readonly property StateType powerStateType: dial.thing.thingClass.stateTypes.findByName("power") + readonly property State powerState: powerStateType ? dial.thing.states.getState(powerStateType.id) : null QtObject { id: d @@ -93,11 +94,11 @@ ColumnLayout { param["paramName"] = dial.stateType.name param["value"] = value params.push(param) - d.pendingActionId = dial.device.executeAction(dial.stateType.name, params) + d.pendingActionId = dial.thing.executeAction(dial.stateType.name, params) } } Connections { - target: engine.deviceManager + target: engine.thingManager onExecuteActionReply: { if (d.pendingActionId == commandId) { d.pendingActionId = -1 @@ -109,7 +110,7 @@ ColumnLayout { } } Connections { - target: dial.device + target: dial.thing onActionExecutionFinished: { if (id == d.pendingActionId) { d.pendingActionId = -1; @@ -121,12 +122,12 @@ ColumnLayout { } } - Component.onCompleted: rotationButton.rotation = dial.valueToAngle(dial.deviceState.value) + Component.onCompleted: rotationButton.rotation = dial.valueToAngle(dial.thingState.value) Connections { - target: dial.deviceState + target: dial.thingState onValueChanged: { if (!d.busy) { - rotationButton.rotation = dial.valueToAngle(dial.deviceState.value) + rotationButton.rotation = dial.valueToAngle(dial.thingState.value) } } } @@ -285,7 +286,7 @@ ColumnLayout { param["paramName"] = "power" param["value"] = !dial.powerState.value params.push(param) - dial.device.executeAction("power", params) + dial.thing.executeAction("power", params) } dragging = false; } diff --git a/nymea-app/ui/customviews/ThermostatController.qml b/nymea-app/ui/customviews/ThermostatController.qml new file mode 100644 index 00000000..73a990ae --- /dev/null +++ b/nymea-app/ui/customviews/ThermostatController.qml @@ -0,0 +1,237 @@ +import QtQuick 2.9 +import Nymea 1.0 +import "../utils" +import "../components" + +Item { + id: root + + property Thing thing: null + + property double precision: 0.5 + + readonly property StateType targetTemperatureStateType: thing.thingClass.stateTypes.findByName("targetTemperature") + readonly property State targetTemperatureState: thing.stateByName("targetTemperature") + readonly property StateType temperatureStateType: thing.thingClass.stateTypes.findByName("temperature") + readonly property State temperatureState: thing.stateByName("temperature") + readonly property State heatingOnState: thing.stateByName("heatingOn") + readonly property State coolingOnState: thing.stateByName("coolingOn") + + Connections { + target: targetTemperatureState + onValueChanged: canvas.requestPaint() + } + Connections { + target: temperatureState + onValueChanged: canvas.requestPaint() + } + ActionQueue { + id: actionQueue + thing: root.thing + stateType: targetTemperatureStateType + onPendingValueChanged: canvas.requestPaint(); + } + + Canvas { + id: canvas + width: Math.min(parent.width, parent.height) + height: width + anchors.centerIn: parent + + property int startAngle: 135 + property int maxAngle: 270 + property int steps: roundToPrecision(root.targetTemperatureStateType.maxValue - root.targetTemperatureStateType.minValue) * (1/root.precision) + property double stepSize: (root.targetTemperatureStateType.maxValue - root.targetTemperatureStateType.minValue) / steps + property double anglePerStep: maxAngle / steps + + + function angleToValue(angle) { + var from = root.targetTemperatureStateType.minValue + var to = root.targetTemperatureStateType.maxValue + return (to - from) * angle / maxAngle + from + } + + onPaint: { + var ctx = canvas.getContext('2d'); + ctx.save(); + ctx.reset() + + + var center = { x: canvas.width / 2, y: canvas.height / 2 }; + var rotation = 135; + + // Background arc + ctx.beginPath() +// ctx.strokeStyle = Style.tileBackgroundColor; + ctx.lineWidth = 0; + ctx.fillStyle = Style.tileBackgroundColor + var innerRadius = canvas.width * 0.4 + var outerRadius = canvas.width * 0.5 + var endAngle = (maxAngle + startAngle) % 360 + var radStart = startAngle * Math.PI/180; + var radEnd = endAngle * Math.PI/180; + ctx.arc(center.x, center.y, outerRadius, radStart, radEnd) + ctx.arc(center.x, center.y, innerRadius, radEnd, radStart, true) + ctx.fill(); + ctx.closePath(); + + // Step lines + var currentValue = actionQueue.pendingValue || root.targetTemperatureState.value + var targetTempStep = roundToPrecision(currentValue - root.targetTemperatureStateType.minValue) * (1/root.precision) + var currentTempStep; + if (root.temperatureState) { + currentTempStep = roundToPrecision(root.temperatureState.value - root.targetTemperatureStateType.minValue) * (1/root.precision) + } + + for(var step = 0; step < steps; step += root.precision) { + var angle = step * anglePerStep + startAngle; + var innerRadius = canvas.width * 0.4 + var outerRadius = canvas.width * 0.5 + + if (targetTempStep === step) { + if (currentTempStep && currentTempStep < targetTempStep) { + ctx.strokeStyle = "red"; + } else if (currentTempStep && currentTempStep > targetTempStep) { + ctx.strokeStyle = "dodgerblue"; + } else { + ctx.strokeStyle = Style.accentColor; + } + innerRadius = canvas.width * 0.38 + ctx.lineWidth = 4; + } else if (currentTempStep && currentTempStep === step) { + if (currentTempStep < targetTempStep) { + ctx.strokeStyle = "red"; + } else { + ctx.strokeStyle = "dodgerblue"; + } + ctx.lineWidth = 3; + } else if (currentTempStep && currentTempStep < step && step < targetTempStep) { + ctx.strokeStyle = "red"; + ctx.lineWidth = 2; + } else if (currentTempStep && currentTempStep > step && step > targetTempStep) { + ctx.strokeStyle = "dodgerblue"; + ctx.lineWidth = 2; + } else { + ctx.strokeStyle = Style.tileOverlayColor; + ctx.lineWidth = 1; + } + + ctx.beginPath(); + // rotate + //convert to radians + var rad = angle * Math.PI/180; + var c = Math.cos(rad); + var s = Math.sin(rad); + var innerPointX = center.x + (innerRadius * c); + var innerPointY = center.y + (innerRadius * s); + var outerPointX = center.x + (outerRadius * c); + var outerPointY = center.x + (outerRadius * s); + + context.moveTo(innerPointX, innerPointY); + context.lineTo(outerPointX, outerPointY); + ctx.stroke(); + ctx.closePath(); + } + + ctx.beginPath(); + ctx.font = "" + app.hugeFont + "px " + Style.fontFamily; + ctx.fillStyle = Style.foregroundColor; + var roundedTargetTemp = Types.toUiValue(root.targetTemperatureState.value, root.targetTemperatureStateType.unit) + roundedTargetTemp = roundToPrecision(roundedTargetTemp).toFixed(1) + "°" + var size = ctx.measureText(roundedTargetTemp) + ctx.text(roundedTargetTemp, center.x - size.width / 2, center.y + app.hugeFont / 2); + ctx.fill(); + ctx.closePath(); + + if (root.temperatureState) { + ctx.beginPath(); + ctx.font = "" + app.largeFont + "px " + Style.fontFamily; + var roundedTemp = Types.toUiValue(root.temperatureState.value, root.temperatureStateType.unit) + roundedTemp = roundToPrecision(roundedTemp) + "°" + size = ctx.measureText(roundedTemp) + ctx.text(roundedTemp, center.x - size.width / 2, center.y + app.hugeFont + app.margins); + ctx.fill(); + ctx.closePath(); + } + + ctx.restore(); + } + + function roundToPrecision(value) { + var tmp = Math.round(value / root.precision) * root.precision; + return tmp; + } + } + + ColorIcon { + width: app.largeIconSize + height: width + anchors { bottom: canvas.bottom; horizontalCenter: canvas.horizontalCenter } + name: root.heatingOnState && root.heatingOnState.value === true + ? "../images/thermostat/heating.svg" + : root.coolingOnState && root.coolingOnState.value === true + ? "../images/thermostat/cooling.svg" + : "" + color: root.heatingOnState && root.heatingOnState.value === true + ? "red" + : root.coolingOnState && root.coolingOnState.value === true + ? "dodgerblue" + : Style.iconColor + } + + MouseArea { + anchors.fill: canvas + + property bool dragging: false + property double lastAngle + property double angleDiff + + onPressed: { + lastAngle = calculateAngle(mouseX, mouseY) + } + + onPositionChanged: { + var angle = calculateAngle(mouseX, mouseY) + var tmpDiff = angle - lastAngle + if (tmpDiff > 300) { + tmpDiff -= 360 + } + if (tmpDiff < -300) { + tmpDiff += 360 + } + + lastAngle = angle; + + angleDiff += tmpDiff + + var valueDiff = angleDiff / canvas.anglePerStep * canvas.stepSize + valueDiff = canvas.roundToPrecision(valueDiff) + if (Math.abs(valueDiff) > 0) { + var currentValue = actionQueue.pendingValue || root.targetTemperatureState.value + var newValue = currentValue + valueDiff + newValue = Math.min(root.targetTemperatureStateType.maxValue, Math.max(root.targetTemperatureStateType.minValue, newValue)) + if (currentValue !== newValue) { + actionQueue.sendValue(newValue) + } + var steps = Math.floor(valueDiff / canvas.stepSize) + angleDiff -= steps * canvas.anglePerStep + } + } + + function calculateAngle(mouseX, mouseY) { + // transform coords to center of dial + mouseX -= canvas.width / 2 + mouseY -= canvas.height / 2 + + var rad = Math.atan(mouseY / mouseX); + var angle = rad * 180 / Math.PI + + angle += 90; + + if (mouseX < 0 && mouseY >= 0) angle = 180 + angle; + if (mouseX < 0 && mouseY < 0) angle = 180 + angle; + + return angle; + } + } +} diff --git a/nymea-app/ui/delegates/InterfaceTile.qml b/nymea-app/ui/delegates/InterfaceTile.qml index 7b2c2e6d..ee04f920 100644 --- a/nymea-app/ui/delegates/InterfaceTile.qml +++ b/nymea-app/ui/delegates/InterfaceTile.qml @@ -167,6 +167,7 @@ MainPageTile { case "extendedsmartmeterconsumer": case "extendedsmartmeterproducer": case "heating": + case "thermostat": return sensorComponent; // return labelComponent; diff --git a/nymea-app/ui/devicepages/HeatingDevicePage.qml b/nymea-app/ui/devicepages/HeatingDevicePage.qml index 6bd0d36d..8fdca878 100644 --- a/nymea-app/ui/devicepages/HeatingDevicePage.qml +++ b/nymea-app/ui/devicepages/HeatingDevicePage.qml @@ -30,84 +30,61 @@ import QtQuick 2.5 import QtQuick.Controls 2.1 -import QtQuick.Controls.Material 2.2 import QtQuick.Layouts 1.1 +import QtQuick.Controls.Material 2.1 import Nymea 1.0 import "../components" -import "../customviews" DevicePageBase { id: root - readonly property bool landscape: width > height - - readonly property StateType targetTemperatureStateType: device.deviceClass.stateTypes.findByName("targetTemperature") - readonly property State targetTemperatureState: targetTemperatureStateType ? device.states.getState(targetTemperatureStateType.id) : null - readonly property StateType powerStateType: deviceClass.stateTypes.findByName("power") - readonly property State powerState: powerStateType ? device.states.getState(powerStateType.id) : null - readonly property StateType temperatureStateType: device.deviceClass.stateTypes.findByName("temperature") - readonly property State temperatureState: temperatureStateType ? device.states.getState(temperatureStateType.id) : null - readonly property StateType percentageStateType: device.deviceClass.stateTypes.findByName("percentage") - readonly property State percentageState: percentageStateType ? device.states.getState(percentageStateType.id) : null - // TODO: should this be an interface? e.g. extendedthermostat - readonly property StateType boostStateType: device.deviceClass.stateTypes.findByName("boost") - readonly property State boostState: boostStateType ? device.states.getState(boostStateType.id) : null - - Component.onCompleted: { - print("d:", root.device, root.targetTemperatureStateType, root.percentageStateType) - } + readonly property var powerStateType: deviceClass.stateTypes.findByName("power") + readonly property var powerState: device.states.getState(powerStateType.id) + readonly property var powerActionType: deviceClass.actionTypes.findByName("power"); GridLayout { anchors.fill: parent anchors.margins: app.margins columns: app.landscape ? 2 : 1 + rowSpacing: app.margins + columnSpacing: app.margins + Layout.alignment: Qt.AlignCenter - Dial { - id: dial - Layout.fillWidth: true + Item { + Layout.preferredWidth: Math.max(app.iconSize * 6, parent.width / 5) + Layout.preferredHeight: width + Layout.topMargin: app.margins + Layout.bottomMargin: app.landscape ? app.margins : 0 + Layout.alignment: Qt.AlignCenter + Layout.rowSpan: app.landscape ? 4 : 1 Layout.fillHeight: true -// visible: root.targetTemperatureStateType || root.percentageStateType - device: root.device - stateType: root.targetTemperatureStateType ? root.targetTemperatureStateType : root.percentageStateType - - } - - Rectangle { - Layout.preferredWidth: app.landscape ? parent.width / 2 : parent.width - Layout.preferredHeight: 50 - visible: root.boostStateType - border.color: boostMouseArea.pressed || root.boostStateType && root.boostState.value === true ? Style.accentColor : Style.foregroundColor - border.width: 1 - radius: height / 2 - color: root.boostStateType && root.boostState.value === true ? Style.accentColor : "transparent" - - Row { + AbstractButton { + height: Math.min(parent.height, parent.width) + width: height anchors.centerIn: parent - spacing: app.margins / 2 - ColorIcon { - height: app.iconSize - width: app.iconSize - name: "../images/sensors/temperature.svg" - color: root.boostStateType && root.boostState.value === true ? "red" : Style.iconColor + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: root.powerState.value === true ? Style.accentColor : Style.iconColor + border.width: 4 + radius: width / 2 } - Label { - text: qsTr("Boost") - anchors.verticalCenter: parent.verticalCenter + ColorIcon { + id: bulbIcon + anchors.fill: parent + anchors.margins: app.margins * 1.5 + name: "../images/thermostat/heating.svg" + color: root.powerState.value === true ? Style.accentColor : Style.iconColor } - } - MouseArea { - id: boostMouseArea - anchors.fill: parent - onPressedChanged: PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackImpact) onClicked: { var params = [] var param = {} - param["paramTypeId"] = root.boostStateType.id - param["value"] = !root.boostState.value + param["paramTypeId"] = root.powerActionType.paramTypes.get(0).id; + param["value"] = !root.powerState.value; params.push(param) - engine.deviceManager.executeAction(root.device.id, root.boostStateType.id, params); + engine.deviceManager.executeAction(root.device.id, root.powerStateType.id, params); } } } diff --git a/nymea-app/ui/devicepages/ThermostatDevicePage.qml b/nymea-app/ui/devicepages/ThermostatDevicePage.qml new file mode 100644 index 00000000..5ad700f1 --- /dev/null +++ b/nymea-app/ui/devicepages/ThermostatDevicePage.qml @@ -0,0 +1,106 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2020, nymea GmbH +* Contact: contact@nymea.io +* +* This file is part of nymea. +* This project including source code and documentation is protected by +* copyright law, and remains the property of nymea GmbH. All rights, including +* reproduction, publication, editing and translation, are reserved. The use of +* this project is subject to the terms of a license agreement to be concluded +* with nymea GmbH in accordance with the terms of use of nymea GmbH, available +* under https://nymea.io/license +* +* GNU General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU General Public License as published by the Free Software +* Foundation, GNU version 3. This project is distributed in the hope that it +* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +* Public License for more details. +* +* You should have received a copy of the GNU General Public License along with +* this project. If not, see . +* +* For any further details and any questions please contact us under +* contact@nymea.io or see our FAQ/Licensing Information on +* https://nymea.io/license/faq +* +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.2 +import QtQuick.Layouts 1.1 +import Nymea 1.0 +import "../components" +import "../customviews" + +DevicePageBase { + id: root + + readonly property bool landscape: width > height + + readonly property StateType targetTemperatureStateType: thing.thingClass.stateTypes.findByName("targetTemperature") + readonly property State targetTemperatureState: targetTemperatureStateType ? thing.states.getState(targetTemperatureStateType.id) : null + readonly property StateType powerStateType: thingClass.stateTypes.findByName("power") + readonly property State powerState: powerStateType ? thing.states.getState(powerStateType.id) : null + readonly property StateType temperatureStateType: thing.thingClass.stateTypes.findByName("temperature") + readonly property State temperatureState: temperatureStateType ? thing.states.getState(temperatureStateType.id) : null + readonly property StateType percentageStateType: thing.thingClass.stateTypes.findByName("percentage") + readonly property State percentageState: percentageStateType ? thing.states.getState(percentageStateType.id) : null + // TODO: should this be an interface? e.g. extendedthermostat + readonly property StateType boostStateType: thing.thingClass.stateTypes.findByName("boost") + readonly property State boostState: boostStateType ? thing.states.getState(boostStateType.id) : null + + GridLayout { + anchors.fill: parent + anchors.margins: app.margins + columns: app.landscape ? 2 : 1 + + ThermostatController { + Layout.fillWidth: true + Layout.fillHeight: true + thing: root.thing + } + + Rectangle { + Layout.preferredWidth: app.landscape ? parent.width / 2 : parent.width + Layout.preferredHeight: 50 + visible: root.boostStateType + border.color: boostMouseArea.pressed || root.boostStateType && root.boostState.value === true ? Style.accentColor : Style.foregroundColor + border.width: 1 + radius: height / 2 + color: root.boostStateType && root.boostState.value === true ? Style.accentColor : "transparent" + + Row { + anchors.centerIn: parent + spacing: app.margins / 2 + ColorIcon { + height: app.iconSize + width: app.iconSize + name: "../images/sensors/temperature.svg" + color: root.boostStateType && root.boostState.value === true ? "red" : Style.iconColor + } + + Label { + text: qsTr("Boost") + anchors.verticalCenter: parent.verticalCenter + } + } + MouseArea { + id: boostMouseArea + anchors.fill: parent + onPressedChanged: PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackImpact) + onClicked: { + var params = [] + var param = {} + param["paramTypeId"] = root.boostStateType.id + param["value"] = !root.boostState.value + params.push(param) + engine.thingManager.executeAction(root.thing.id, root.boostStateType.id, params); + } + } + } + } +} diff --git a/nymea-app/ui/images/thermostat/cooling.svg b/nymea-app/ui/images/thermostat/cooling.svg new file mode 100644 index 00000000..b189f755 --- /dev/null +++ b/nymea-app/ui/images/thermostat/cooling.svg @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/images/thermostat/heating.svg b/nymea-app/ui/images/thermostat/heating.svg new file mode 100644 index 00000000..bff79b13 --- /dev/null +++ b/nymea-app/ui/images/thermostat/heating.svg @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/nymea-app/ui/utils/NymeaUtils.qml b/nymea-app/ui/utils/NymeaUtils.qml index 0d17436e..c08bccf7 100644 --- a/nymea-app/ui/utils/NymeaUtils.qml +++ b/nymea-app/ui/utils/NymeaUtils.qml @@ -27,8 +27,10 @@ Item { page = "ButtonDevicePage.qml"; } else if (interfaceList.indexOf("weather") >= 0) { page = "WeatherDevicePage.qml"; - } else if (interfaceList.indexOf("heating") >= 0 || interfaceList.indexOf("thermostat") >= 0) { + } else if (interfaceList.indexOf("heating") >= 0) { page = "HeatingDevicePage.qml"; + } else if (interfaceList.indexOf("thermostat") >= 0) { + page = "ThermostatDevicePage.qml"; } else if (interfaceList.indexOf("sensor") >= 0) { page = "SensorDevicePage.qml"; } else if (interfaceList.indexOf("inputtrigger") >= 0) {