diff --git a/libnymea-app-core/devices.cpp b/libnymea-app-core/devices.cpp
index 2b41170a..1b231155 100644
--- a/libnymea-app-core/devices.cpp
+++ b/libnymea-app-core/devices.cpp
@@ -127,6 +127,9 @@ QVariant Devices::data(const QModelIndex &index, int role) const
if (interfaces.contains("evcharger")) {
return "evcharger";
}
+ if (interfaces.contains("powersocket")) {
+ return "powersocket";
+ }
return "uncategorized";
}
diff --git a/nymea-app/images.qrc b/nymea-app/images.qrc
index bf1b791c..e83d1940 100644
--- a/nymea-app/images.qrc
+++ b/nymea-app/images.qrc
@@ -168,5 +168,6 @@
ui/images/stock_music.svg
ui/images/stock_video.svg
ui/images/sensors/presence.svg
+ ui/images/powersocket.svg
diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc
index 01200294..276d5240 100644
--- a/nymea-app/resources.qrc
+++ b/nymea-app/resources.qrc
@@ -145,5 +145,7 @@
ui/system/ServerConfigurationDialog.qml
ui/system/MqttPolicyPage.qml
ui/devicepages/BoolSensorDevicePage.qml
+ ui/devicepages/PowersocketDevicePage.qml
+ ui/devicelistpages/PowerSocketsDeviceListPage.qml
diff --git a/nymea-app/ui/Nymea.qml b/nymea-app/ui/Nymea.qml
index 2239f8e1..456764d4 100644
--- a/nymea-app/ui/Nymea.qml
+++ b/nymea-app/ui/Nymea.qml
@@ -52,7 +52,7 @@ ApplicationWindow {
rootItem.handleCloseEvent(close)
}
- property var supportedInterfaces: ["light", "weather", "sensor", "media", "garagegate", "awning", "shutter", "blind", "heating", "smartmeter", "evcharger", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
+ property var supportedInterfaces: ["light", "weather", "media", "garagegate", "awning", "shutter", "blind", "heating", "powersocket", "sensor", "smartmeter", "evcharger", "accesscontrol", "button", "notifications", "inputtrigger", "outputtrigger", "gateway"]
function interfaceToString(name) {
switch(name) {
case "light":
@@ -106,6 +106,8 @@ ApplicationWindow {
return qsTr("Heatings");
case "evcharger":
return qsTr("EV-chargers");
+ case "powersocket":
+ return qsTr("Power sockets")
case "uncategorized":
return qsTr("Uncategorized")
default:
@@ -155,6 +157,8 @@ ApplicationWindow {
case "media":
case "mediacontroller":
return Qt.resolvedUrl("images/mediaplayer-app-symbolic.svg")
+ case "powersocket":
+ return Qt.resolvedUrl("images/powersocket.svg")
case "button":
case "longpressbutton":
case "simplemultibutton":
@@ -284,6 +288,8 @@ ApplicationWindow {
page = "FingerprintReaderDevicePage.qml";
} else if (interfaceList.indexOf("smartmeter") >= 0) {
page = "SmartMeterDevicePage.qml"
+ } else if (interfaceList.indexOf("powersocket") >= 0) {
+ page = "PowersocketDevicePage.qml";
} else {
page = "GenericDevicePage.qml";
}
diff --git a/nymea-app/ui/devicelistpages/PowerSocketsDeviceListPage.qml b/nymea-app/ui/devicelistpages/PowerSocketsDeviceListPage.qml
new file mode 100644
index 00000000..6de2cab5
--- /dev/null
+++ b/nymea-app/ui/devicelistpages/PowerSocketsDeviceListPage.qml
@@ -0,0 +1,98 @@
+import QtQuick 2.5
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.1
+import Nymea 1.0
+import "../components"
+import "../delegates"
+import QtQuick.Controls.Material 2.1
+
+DeviceListPageBase {
+ id: root
+
+ header: GuhHeader {
+ text: qsTr("My %1").arg(app.interfaceToString("powersocket"))
+
+ onBackPressed: {
+ pageStack.pop()
+ }
+ }
+
+ ListView {
+ anchors.fill: parent
+ model: devicesProxy
+ spacing: app.margins
+
+ delegate: Pane {
+ id: itemDelegate
+ width: parent.width
+
+ property var device: devicesProxy.get(index);
+ property var deviceClass: engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);
+
+ property var connectedStateType: deviceClass.stateTypes.findByName("connected");
+ property var connectedState: connectedStateType ? device.states.getState(connectedStateType.id) : null
+
+ property var powerStateType: deviceClass.stateTypes.findByName("power");
+ property var powerActionType: deviceClass.actionTypes.findByName("power");
+ property var powerState: device.states.getState(powerStateType.id)
+
+ Material.elevation: 1
+ topPadding: 0
+ bottomPadding: 0
+ leftPadding: 0
+ rightPadding: 0
+ contentItem: ItemDelegate {
+ id: contentItem
+ implicitHeight: nameRow.implicitHeight
+ topPadding: 0
+
+ contentItem: ColumnLayout {
+ spacing: 0
+ RowLayout {
+ enabled: itemDelegate.connectedState === null || itemDelegate.connectedState.value === true
+ id: nameRow
+ z: 2 // make sure the switch in here is on top of the slider, given we cheated a bit and made them overlap
+ spacing: app.margins
+ Item {
+ Layout.preferredHeight: app.iconSize
+ Layout.preferredWidth: height
+ Layout.alignment: Qt.AlignVCenter
+
+ ColorIcon {
+ id: icon
+ anchors.fill: parent
+ color: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false
+ ? "red"
+ : itemDelegate.powerState.value === true ? app.accentColor : keyColor
+ name: itemDelegate.connectedState !== null && itemDelegate.connectedState.value === false ?
+ "../images/dialog-warning-symbolic.svg"
+ : app.interfaceToIcon("powersocket")
+ }
+ }
+
+ Label {
+ Layout.fillWidth: true
+ text: model.name
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ Switch {
+ checked: itemDelegate.powerState.value === true
+ onClicked: {
+ var params = [];
+ var param1 = {};
+ param1["paramTypeId"] = itemDelegate.powerActionType.paramTypes.get(0).id;
+ param1["value"] = checked;
+ params.push(param1)
+ engine.deviceManager.executeAction(device.id, itemDelegate.powerActionType.id, params)
+ }
+ }
+ }
+ }
+ onClicked: {
+ enterPage(index, false)
+ }
+ }
+ }
+ }
+}
diff --git a/nymea-app/ui/devicepages/PowersocketDevicePage.qml b/nymea-app/ui/devicepages/PowersocketDevicePage.qml
new file mode 100644
index 00000000..ebb8e9a2
--- /dev/null
+++ b/nymea-app/ui/devicepages/PowersocketDevicePage.qml
@@ -0,0 +1,62 @@
+import QtQuick 2.5
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls.Material 2.1
+import Nymea 1.0
+import "../components"
+
+DevicePageBase {
+ id: root
+
+ 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
+
+ Item {
+ Layout.preferredWidth: Math.max(app.iconSize * 4, 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
+
+ AbstractButton {
+ height: Math.min(parent.height, parent.width)
+ width: height
+ anchors.centerIn: parent
+ Rectangle {
+ anchors.fill: parent
+ color: "white"
+ border.color: root.powerState.value === true ? app.accentColor : bulbIcon.keyColor
+ border.width: 4
+ radius: width / 2
+ }
+
+ ColorIcon {
+ id: bulbIcon
+ anchors.fill: parent
+ anchors.margins: app.margins * 1.5
+ name: "../images/powersocket.svg"
+ color: root.powerState.value === true ? app.accentColor : keyColor
+ }
+ onClicked: {
+ var params = []
+ var param = {}
+ param["paramTypeId"] = root.powerActionType.paramTypes.get(0).id;
+ param["value"] = !root.powerState.value;
+ params.push(param)
+ engine.deviceManager.executeAction(root.device.id, root.powerStateType.id, params);
+ }
+ }
+ }
+ }
+}
diff --git a/nymea-app/ui/images/powersocket.svg b/nymea-app/ui/images/powersocket.svg
new file mode 100644
index 00000000..4a4da53a
--- /dev/null
+++ b/nymea-app/ui/images/powersocket.svg
@@ -0,0 +1,120 @@
+
+
diff --git a/nymea-app/ui/mainviews/DevicesPageDelegate.qml b/nymea-app/ui/mainviews/DevicesPageDelegate.qml
index a5f94f49..a92e3a0b 100644
--- a/nymea-app/ui/mainviews/DevicesPageDelegate.qml
+++ b/nymea-app/ui/mainviews/DevicesPageDelegate.qml
@@ -43,6 +43,9 @@ MainPageTile {
case "extendedShutter":
page = "ShutterDeviceListPage.qml";
break;
+ case "powersocket":
+ page = "PowerSocketsDeviceListPage.qml";
+ break;
default:
page = "GenericDeviceListPage.qml"
}
@@ -98,6 +101,7 @@ MainPageTile {
case "extendedshutter":
case "awning":
case "extendedawning":
+ case "powersocket":
return buttonComponent
default:
console.warn("DevicesPageDelegate, inlineControl: Unhandled interface", model.name)
@@ -119,6 +123,7 @@ MainPageTile {
case "media":
return devicesProxy.get(0).name;
case "light":
+ case "powersocket":
var count = 0;
for (var i = 0; i < devicesProxy.count; i++) {
var device = devicesProxy.get(i);
@@ -289,6 +294,7 @@ MainPageTile {
state.value === "Paused" ? "../images/media-playback-start.svg" :
""
case "light":
+ case "powersocket":
return "../images/system-shutdown.svg"
case "garagegate":
case "blind":
@@ -307,6 +313,7 @@ MainPageTile {
onClicked: {
switch (model.name) {
case "light":
+ case "powersocket":
if (devicesProxy.count == 1) {
var device = devicesProxy.get(0);
var deviceClass = engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId);