diff --git a/mea/mea.pro b/mea/mea.pro index f859f739..5bf0bb8e 100644 --- a/mea/mea.pro +++ b/mea/mea.pro @@ -52,5 +52,9 @@ BR=$$BRANDING win32:RCC_ICONS += ../packaging/windows/packages/io.guh.mea/meta/logo.ico } +withavahi: { + LIBS += -lavahi-client -lavahi-common +} + target.path = /usr/bin INSTALLS += target diff --git a/mea/resources.qrc b/mea/resources.qrc index e6527835..cf6292c1 100644 --- a/mea/resources.qrc +++ b/mea/resources.qrc @@ -167,5 +167,23 @@ ui/images/network-secure.svg ui/images/lock-broken.svg ui/AboutPage.qml + ui/images/sort-listitem.svg + ui/devicepages/ShutterDevicePage.qml + ui/images/shutter-1.svg + ui/images/shutter-2.svg + ui/images/shutter-3.svg + ui/images/shutter-4.svg + ui/images/shutter-5.svg + ui/images/shutter-6.svg + ui/images/shutter-7.svg + ui/images/shutter-8.svg + ui/images/shutter-9.svg + ui/images/shutter-10.svg + ui/images/down.svg + ui/images/up.svg + ui/devicepages/GarageGateDevicePage.qml + ui/images/remove.svg + ui/images/shutter-0.svg + ui/components/ShutterControls.qml diff --git a/mea/ui/DevicesPage.qml b/mea/ui/DevicesPage.qml index 97bd2b79..61a3d715 100644 --- a/mea/ui/DevicesPage.qml +++ b/mea/ui/DevicesPage.qml @@ -105,6 +105,9 @@ Item { case "light": case "media": + case "garagegate": + case "shutter": + case "blind": return buttonComponent } } @@ -163,6 +166,16 @@ Item { print("executing", device, device.id, actionTypeId, actionName, deviceClass.actionTypes) Engine.deviceManager.executeAction(device.id, actionTypeId) + case "garagegate": + case "shutter": + case "blind": + for (var i = 0; i < devicesProxy.count; i++) { + var device = devicesProxy.get(i); + var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + var actionType = deviceClass.actionTypes.findByName("close"); + Engine.deviceManager.executeAction(device.id, actionType.id) + } + } } @@ -187,7 +200,19 @@ Item { } } return count === 0 ? qsTr("All off") : qsTr("%1 on").arg(count) + case "garagegate": + var count = 0; + for (var i = 0; i < devicesProxy.count; i++) { + var device = devicesProxy.get(i); + var deviceClass = Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId); + var stateType = deviceClass.stateTypes.findByName("state"); + if (device.states.getState(stateType.id).value !== "closed") { + count++; + } + } + return count === 0 ? qsTr("All closed") : qsTr("%1 open").arg(count) } + console.warn("Unhandled interface", model.name) } font.pixelSize: app.smallFont elide: Text.ElideRight @@ -210,6 +235,10 @@ Item { "" case "light": return "../images/system-shutdown.svg" + case "garagegate": + case "shutter": + case "blind": + return "../images/down.svg" } } } diff --git a/mea/ui/MainPage.qml b/mea/ui/MainPage.qml index 1744679a..f54bc28c 100644 --- a/mea/ui/MainPage.qml +++ b/mea/ui/MainPage.qml @@ -72,7 +72,7 @@ Page { InterfacesModel { id: page1Model devices: Engine.deviceManager.devices - shownInterfaces: ["light", "weather", "sensor", "media", "garagegate"] + shownInterfaces: ["light", "weather", "sensor", "media", "garagegate", "shutter", "garagegate"] property var view: null onCountChanged: buildView() } diff --git a/mea/ui/Mea.qml b/mea/ui/Mea.qml index dace6dd8..2b82c117 100644 --- a/mea/ui/Mea.qml +++ b/mea/ui/Mea.qml @@ -159,6 +159,12 @@ ApplicationWindow { return qsTr("Incoming Events"); case "outputtrigger": return qsTr("Events"); + case "shutter": + return qsTr("Shutters"); + case "blind": + return qsTr("Blinds"); + case "garagegate": + return qsTr("Garage gates"); } } @@ -206,6 +212,11 @@ ApplicationWindow { return Qt.resolvedUrl("images/mail-mark-important.svg") case "outputtrigger": return Qt.resolvedUrl("images/send.svg") + case "shutter": + case "blind": + return Qt.resolvedUrl("images/sort-listitem.svg") + case "garagegate": + return Qt.resolvedUrl("images/shutter-10.svg") } return ""; } diff --git a/mea/ui/components/ShutterControls.qml b/mea/ui/components/ShutterControls.qml new file mode 100644 index 00000000..bd98f39d --- /dev/null +++ b/mea/ui/components/ShutterControls.qml @@ -0,0 +1,65 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.2 +import QtQuick.Controls.Material 2.2 +import QtQuick.Layouts 1.3 +import Mea 1.0 + +RowLayout { + id: root + spacing: (parent.width - app.iconSize*2*children.length) / 4 + + property var device: null + readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null + readonly property var openState: device ? device.states.getState(deviceClass.stateTypes.findByName("state").id) : null + + Rectangle { + Layout.preferredWidth: app.iconSize * 2 + Layout.preferredHeight: width + color: root.openState && root.openState.value === "opening" ? Material.accent : Material.foreground + radius: height / 2 + + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/up.svg" + } + MouseArea { + anchors.fill: parent + onClicked: Engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("open").id) + } + } + + Rectangle { + Layout.preferredWidth: app.iconSize * 2 + Layout.preferredHeight: width + color: Material.foreground + radius: height / 2 + + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/remove.svg" + } + MouseArea { + anchors.fill: parent + onClicked: Engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("stop").id) + } + } + + Rectangle { + Layout.preferredWidth: app.iconSize * 2 + Layout.preferredHeight: width + color: root.openState && root.openState.value === "closing" ? Material.accent : Material.foreground + radius: height / 2 + + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/down.svg" + } + MouseArea { + anchors.fill: parent + onClicked: Engine.deviceManager.executeAction(root.device.id, root.deviceClass.actionTypes.findByName("close").id) + } + } +} diff --git a/mea/ui/devicelistpages/GenericDeviceListPage.qml b/mea/ui/devicelistpages/GenericDeviceListPage.qml index 7e2e78b2..b5f42ef7 100644 --- a/mea/ui/devicelistpages/GenericDeviceListPage.qml +++ b/mea/ui/devicelistpages/GenericDeviceListPage.qml @@ -42,6 +42,10 @@ Page { page = "SensorDevicePage.qml"; } else if (deviceClass.interfaces.indexOf("inputtrigger") >= 0) { page = "InputTriggerDevicePage.qml"; + } else if (deviceClass.interfaces.indexOf("shutter") >= 0 ) { + page = "ShutterDevicePage.qml"; + } else if (deviceClass.interfaces.indexOf("garagegate") >= 0 ) { + page = "GarageGateDevicePage.qml"; } else { page = "GenericDevicePage.qml"; } diff --git a/mea/ui/devicepages/GarageGateDevicePage.qml b/mea/ui/devicepages/GarageGateDevicePage.qml new file mode 100644 index 00000000..e4034623 --- /dev/null +++ b/mea/ui/devicepages/GarageGateDevicePage.qml @@ -0,0 +1,113 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Controls.Material 2.2 +import QtQuick.Layouts 1.1 +import Mea 1.0 +import "../components" +import "../customviews" + +DevicePageBase { + id: root + + readonly property bool landscape: width > height + readonly property var openState: device.states.getState(deviceClass.stateTypes.findByName("state").id) + readonly property var intermediatePositionState: device.states.getState(deviceClass.stateTypes.findByName("intermediatePosition").id) + readonly property var lightStateType: deviceClass.stateTypes.findByName("power") + readonly property var lightState: lightStateType ? device.states.getState(lightStateType.id) : null + + GridLayout { + anchors.fill: parent + columns: root.landscape ? 2 : 1 + + ColorIcon { + id: shutterImage + Layout.preferredWidth: root.landscape ? height : parent.width + Layout.preferredHeight: root.landscape ? parent.height : width + property int currentImage: 0 + name: "../images/shutter-" + currentImage + ".svg" + Component.onCompleted: update() + + function update() { + switch (root.openState.value) { + case "open": + if (root.intermediatePositionState.value === true) { + shutterImage.currentImage = 5; + } else { + shutterImage.currentImage = 0; + } + break; + case "closed": + if (root.intermediatePositionState.value === true) { + shutterImage.currentImage = 5; + } else { + shutterImage.currentImage = 10; + } + } + print("shutter is now:", shutterImage.currentImage, root.intermediatePositionState.value) + } + + Connections { + target: root.openState + onValueChanged: shutterImage.update(); + } + Connections { + target: root.intermediatePositionState + onValueChanged: shutterImage.update(); + } + + Timer { + running: root.openState.value === "closing" || root.openState.value === "opening" + interval: 500 + repeat: true + onTriggered: { + var value = shutterImage.currentImage; + if (root.openState.value === "opening") { + value--; + } else if (root.openState.value === "closing") { + value++; + } + if (value > 10) value = 0; + if (value < 0) value = 10; + shutterImage.currentImage = value; + } + } + } + + Item { + Layout.preferredWidth: root.landscape ? parent.width / 2 : parent.width + Layout.fillHeight: true + Layout.minimumHeight: app.iconSize * 2.5 + + ShutterControls { + device: root.device + anchors.centerIn: parent + + Rectangle { + Layout.preferredWidth: app.iconSize * 2 + Layout.preferredHeight: width + color: root.lightState && root.lightState.value === true ? Material.accent : Material.foreground + radius: height / 2 + visible: root.lightStateType !== null + + ColorIcon { + anchors.fill: parent + anchors.margins: app.margins + name: "../images/torch-" + (root.lightState && root.lightState.value === true ? "on" : "off") + ".svg" + } + MouseArea { + anchors.fill: parent + onClicked: { + print("blabla", root.lightState, root.lightState.value, root.lightStateType.name, root.lightState.stateTypeId, root.lightStateType.id) + var params = []; + var param = {}; + param["paramTypeId"] = root.lightStateType.id; + param["value"] = !root.lightState.value; + params.push(param) + Engine.deviceManager.executeAction(root.device.id, root.lightStateType.id, params) + } + } + } + } + } + } +} diff --git a/mea/ui/devicepages/ShutterDevicePage.qml b/mea/ui/devicepages/ShutterDevicePage.qml new file mode 100644 index 00000000..06a35201 --- /dev/null +++ b/mea/ui/devicepages/ShutterDevicePage.qml @@ -0,0 +1,20 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.1 +import QtQuick.Layouts 1.1 +import Mea 1.0 +import "../components" +import "../customviews" + +DevicePageBase { + id: root + + + ShutterControls { + anchors { + top: parent.top + topMargin: app.iconSize + horizontalCenter: parent.horizontalCenter + } + device: root.device + } +} diff --git a/mea/ui/images/down.svg b/mea/ui/images/down.svg new file mode 100644 index 00000000..d4931a09 --- /dev/null +++ b/mea/ui/images/down.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/magic.svg.2018_05_29_14_21_27.0.svg b/mea/ui/images/magic.svg.2018_05_29_14_21_27.0.svg new file mode 100644 index 00000000..d8ce6570 --- /dev/null +++ b/mea/ui/images/magic.svg.2018_05_29_14_21_27.0.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/remove.svg b/mea/ui/images/remove.svg new file mode 100644 index 00000000..e3013d2e --- /dev/null +++ b/mea/ui/images/remove.svg @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-0.svg b/mea/ui/images/shutter-0.svg new file mode 100644 index 00000000..8341cfcc --- /dev/null +++ b/mea/ui/images/shutter-0.svg @@ -0,0 +1,66 @@ + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/mea/ui/images/shutter-1.svg b/mea/ui/images/shutter-1.svg new file mode 100644 index 00000000..bbaeae84 --- /dev/null +++ b/mea/ui/images/shutter-1.svg @@ -0,0 +1,72 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/mea/ui/images/shutter-10.svg b/mea/ui/images/shutter-10.svg new file mode 100644 index 00000000..e021fba4 --- /dev/null +++ b/mea/ui/images/shutter-10.svg @@ -0,0 +1,126 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-2.svg b/mea/ui/images/shutter-2.svg new file mode 100644 index 00000000..9eeea0d3 --- /dev/null +++ b/mea/ui/images/shutter-2.svg @@ -0,0 +1,78 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/mea/ui/images/shutter-3.svg b/mea/ui/images/shutter-3.svg new file mode 100644 index 00000000..64252b84 --- /dev/null +++ b/mea/ui/images/shutter-3.svg @@ -0,0 +1,84 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/mea/ui/images/shutter-4.svg b/mea/ui/images/shutter-4.svg new file mode 100644 index 00000000..e4151323 --- /dev/null +++ b/mea/ui/images/shutter-4.svg @@ -0,0 +1,90 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-5.svg b/mea/ui/images/shutter-5.svg new file mode 100644 index 00000000..a5666c43 --- /dev/null +++ b/mea/ui/images/shutter-5.svg @@ -0,0 +1,96 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-6.svg b/mea/ui/images/shutter-6.svg new file mode 100644 index 00000000..cdca2cd1 --- /dev/null +++ b/mea/ui/images/shutter-6.svg @@ -0,0 +1,102 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-7.svg b/mea/ui/images/shutter-7.svg new file mode 100644 index 00000000..4411d606 --- /dev/null +++ b/mea/ui/images/shutter-7.svg @@ -0,0 +1,108 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-8.svg b/mea/ui/images/shutter-8.svg new file mode 100644 index 00000000..9aac397a --- /dev/null +++ b/mea/ui/images/shutter-8.svg @@ -0,0 +1,114 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/shutter-9.svg b/mea/ui/images/shutter-9.svg new file mode 100644 index 00000000..ecdae2ba --- /dev/null +++ b/mea/ui/images/shutter-9.svg @@ -0,0 +1,120 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/sort-listitem.svg b/mea/ui/images/sort-listitem.svg new file mode 100644 index 00000000..afef27d1 --- /dev/null +++ b/mea/ui/images/sort-listitem.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/mea/ui/images/up.svg b/mea/ui/images/up.svg new file mode 100644 index 00000000..f7d995cb --- /dev/null +++ b/mea/ui/images/up.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + +