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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+