]> git.basschouten.com Git - qthomecontrol.git/commitdiff
Update with new content for the office thermostat and use WebSockets directly to... master
authorBas Schouten <bas@basschouten.com>
Tue, 23 Apr 2024 10:08:52 +0000 (12:08 +0200)
committerBas Schouten <bas@basschouten.com>
Tue, 23 Apr 2024 10:08:52 +0000 (12:08 +0200)
25 files changed:
.gitmodules
CMakeLists.txt
Main.qml [deleted file]
MainBedroom.qml [new file with mode: 0644]
MainOffice.qml [new file with mode: 0644]
backlightcontroller.cpp [new file with mode: 0644]
backlightcontroller.h [new file with mode: 0644]
fonts/DigitalDream.ttf [new file with mode: 0644]
fonts/digital-7.ttf [new file with mode: 0644]
images/energy.png [new file with mode: 0644]
images/frontdoor.png [new file with mode: 0644]
images/humidity.png [new file with mode: 0644]
images/light.png [new file with mode: 0644]
images/moon.png [new file with mode: 0644]
images/pressure.png [new file with mode: 0644]
images/temperature.png [new file with mode: 0644]
itemdefinitions.h [new file with mode: 0644]
main.cpp
mqttinterface.cpp [deleted file]
mqttinterface.h [deleted file]
openhabinterface.cpp [new file with mode: 0644]
openhabinterface.h [new file with mode: 0644]
paho.mqtt.c [deleted submodule]
qtquickcontrols2.conf [new file with mode: 0644]
resources.qrc [new file with mode: 0644]

index e0e40ecbf9243741d95c376eec1d9e2927fc1098..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 (file)
@@ -1,3 +0,0 @@
-[submodule "paho.mqtt.c"]
-       path = paho.mqtt.c
-       url = https://github.com/eclipse/paho.mqtt.c
index 11378e0d0dbdbe2127fe15a601f0eb2b256bf58f..ba339e481901615429760d66f261cbf3bd696edc 100644 (file)
@@ -5,26 +5,51 @@ project(qthomecontrol VERSION 0.1 LANGUAGES CXX)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
-find_package(Qt6 6.5 COMPONENTS Quick REQUIRED)
+find_package(Qt6 6.5 COMPONENTS Quick QuickControls2 WebSockets REQUIRED)
 
 qt_standard_project_setup(REQUIRES 6.5)
 
 
 qt_standard_project_setup(REQUIRES 6.5)
 
-if (UNIX)
-    add_subdirectory ("paho.mqtt.c")
-endif(UNIX)
-
 qt_add_executable(appqthomecontrol
     main.cpp
 qt_add_executable(appqthomecontrol
     main.cpp
-    mqttinterface.cpp
-    mqttinterface.h
+    openhabinterface.cpp
+    openhabinterface.h
+    backlightcontroller.h
+    backlightcontroller.cpp
 )
 
 qt_add_qml_module(appqthomecontrol
     URI qthomecontrol
     VERSION 1.0
 )
 
 qt_add_qml_module(appqthomecontrol
     URI qthomecontrol
     VERSION 1.0
-    QML_FILES Main.qml
+    QML_FILES MainBedroom.qml MainOffice.qml
     SOURCES
     SOURCES
-      mqttinterface.h mqttinterface.cpp
+      openhabinterface.h openhabinterface.cpp
+      backlightcontroller.h backlightcontroller.cpp
+      itemdefinitions.h
+)
+
+qt_add_resources(appqthomecontrol "configuration"
+    PREFIX "/"
+    FILES
+        qtquickcontrols2.conf
+)
+
+qt_add_resources(appqthomecontrol "images"
+    PREFIX "/"
+    FILES
+        images/temperature.png
+        images/humidity.png
+        images/light.png
+        images/energy.png
+        images/frontdoor.png
+        images/moon.png
+        images/pressure.png
+)
+
+qt_add_resources(appqthomecontrol "fonts"
+    PREFIX "/"
+    FILES
+      fonts/digital-7.ttf
+
 )
 
 set_target_properties(appqthomecontrol PROPERTIES
 )
 
 set_target_properties(appqthomecontrol PROPERTIES
@@ -35,17 +60,14 @@ set_target_properties(appqthomecontrol PROPERTIES
     WIN32_EXECUTABLE TRUE
 )
 
     WIN32_EXECUTABLE TRUE
 )
 
-target_include_directories (appqthomecontrol PRIVATE paho.mqtt.c/src)
-
 target_link_libraries(appqthomecontrol
     PRIVATE Qt6::Quick)
 
 target_link_libraries(appqthomecontrol
     PRIVATE Qt6::Quick)
 
-if (WIN32)
-    target_link_libraries (appqthomecontrol PRIVATE ${CMAKE_SOURCE_DIR}/paho.mqtt.c/src/Release/paho-mqtt3a.lib ${CMAKE_SOURCE_DIR}/paho.mqtt.c/src/Release/paho-mqtt3c.lib)
-endif (WIN32)
-if (UNIX)
-    target_link_libraries (appqthomecontrol PRIVATE paho-mqtt3a paho-mqtt3c)
-endif(UNIX)
+target_link_libraries (appqthomecontrol PRIVATE Qt6::QuickControls2 Qt6::WebSockets)
+
+if (USE_PWM)
+    add_compile_definitions(USE_PWM)
+endif(USE_PWM)
 
 install(TARGETS appqthomecontrol
     BUNDLE DESTINATION .
 
 install(TARGETS appqthomecontrol
     BUNDLE DESTINATION .
diff --git a/Main.qml b/Main.qml
deleted file mode 100644 (file)
index 7b52a7a..0000000
--- a/Main.qml
+++ /dev/null
@@ -1,56 +0,0 @@
-import QtQuick
-import QtQuick.Controls 6.3
-import QtQuick.Layouts 6.3
-import qthomecontrol
-
-Window {
-    width: 720
-    height: 720
-    visible: true
-    color: "#000000"
-    title: qsTr("Home Control")
-
-    MQTTInterface {
-        id: mqttinterface
-    }
-
-    Slider {
-        id: slider
-        x: 13
-        y: 534
-        width: 695
-        height: 178
-        live: true
-        antialiasing: false
-        topPadding: 0
-        orientation: Qt.Horizontal
-        snapMode: RangeSlider.SnapOnRelease
-        stepSize: 1
-        to: 100
-        value: 0
-    }
-
-    Text {
-        id: text1
-        x: 206
-        y: 114
-        width: 309
-        height: 129
-        color: "#ffffff"
-        text: mqttinterface.bedroomTemperature.toFixed(1) + " °C"
-        font.pixelSize: 92
-        horizontalAlignment: Text.AlignHCenter
-    }
-
-    Text {
-        id: text2
-        x: 206
-        y: 285
-        width: 309
-        height: 129
-        color: "#ffffff"
-        text: mqttinterface.bedroomHumidity.toFixed(0) + " %"
-        font.pixelSize: 92
-        horizontalAlignment: Text.AlignHCenter
-    }
-}
diff --git a/MainBedroom.qml b/MainBedroom.qml
new file mode 100644 (file)
index 0000000..28526c2
--- /dev/null
@@ -0,0 +1,360 @@
+import QtQuick
+import QtQuick.Controls 6.3
+import QtQuick.Layouts 6.3
+import qthomecontrol
+
+Window {
+    width: 720
+    height: 720
+    visible: true
+    title: qsTr("Home Control")
+    visibility: "FullScreen"
+    color: Material.backgroundColor
+
+    OpenHABInterface {
+        id: openHABInterface
+    }
+
+    BackLightController {
+        id: backlightController
+    }
+
+    FontLoader { id: digital; source: "qrc:/fonts/digital-7.ttf" }
+
+    Label {
+        id: textTime
+        x: 620
+        y: 10
+        width: 90
+        height: 50
+        font.pixelSize: 36
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignTop
+    }
+
+
+    Timer {
+        id: timer
+        interval: 1000
+        repeat: true
+        running: true
+
+        onTriggered:
+        {
+            textTime.text =  Qt.formatTime(new Date(),"hh:mm")
+        }
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        hoverEnabled: true
+        propagateComposedEvents: true
+        onPositionChanged: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onClicked: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onPressed: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onReleased: mouse.accepted = false;
+        onDoubleClicked: mouse.accepted = false;
+        onPressAndHold: mouse.accepted = false;
+        z: 100
+    }
+
+    GroupBox {
+        id: groupBox
+        x: 15
+        y: 10
+        width: 483
+        height: 430
+        label: Label {
+            id: bedroomLabel
+            text: "Bedroom"
+            font.pixelSize: 32
+        }
+        Slider {
+            id: slider
+            x: 245
+            y: 83
+            width: 190
+            height: 25
+            live: true
+            antialiasing: true
+            topPadding: 0
+            bottomPadding: 0
+            orientation: Qt.Horizontal
+            snapMode: RangeSlider.SnapOnRelease
+            stepSize: 1
+            to: 100
+            value: openHABInterface.bedroomDimmer
+            scale: 1.5
+            onMoved:
+            {
+                openHABInterface.bedroomDimmer = slider.value
+            }
+        }
+
+        Label {
+            id: textTemp
+            x: 50
+            y: 0
+            width: 100
+            height: 60
+            text: openHABInterface.bedroomTemperature.toFixed(1)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitTemp
+            x: 155
+            y: 0
+            width: 30
+            height: 60
+            text: "°C"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Label {
+            id: textHumid
+            x: 50
+            y: 60
+            width: 100
+            height: 60
+            text: openHABInterface.bedroomHumidity.toFixed(0)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitHumid
+            x: 155
+            y: 60
+            width: 30
+            height: 60
+            text: "%"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Label {
+            id: textLight
+            x: 250
+            y: 0
+            width: 100
+            height: 60
+            text: openHABInterface.bedroomDimmer.toFixed(0)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitDimmer
+            x: 357
+            y: 0
+            width: 30
+            height: 60
+            text: "%"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Image {
+            id: tempImage
+            x: 10
+            y: 0
+            width: 54
+            height: 60
+            source: "qrc:/images/temperature.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Image {
+            id: humidImage
+            x: 10
+            y: 60
+            width: 54
+            height: 60
+            source: "qrc:/images/humidity.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Image {
+            id: lightImage
+            x: 235
+            y: 0
+            width: 54
+            height: 60
+            source: "qrc:/images/light.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Dial {
+            id: dialAC
+            x: 35
+            y: 230
+            inputMode: Dial.Vertical
+            scale: 1.5
+
+            from: 16
+            value: openHABInterface.bedroomACSetPoint
+            to: 24
+            stepSize: 0.5
+            snapMode: Dial.SnapAlways
+
+            onMoved: {
+                openHABInterface.bedroomACSetPoint = dialAC.value
+            }
+
+            Label {
+                x: 0
+                width: dialAC.width
+                y: 0
+                height: dialAC.height
+                id: thermoSetLabel
+                text: dialAC.value.toFixed(1)
+                font.pixelSize: 32
+                font.family: digital.font.family
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+        }
+        Dial {
+            id: dialFloor
+            x: 50 + dialFloor.width * 1.5
+            y: 230
+            inputMode: Dial.Vertical
+            scale: 1.5
+
+            from: 16
+            value: openHABInterface.bedroomFloorSetPoint
+            to: 24
+            stepSize: 0.5
+            snapMode: Dial.SnapAlways
+
+            onMoved: {
+                openHABInterface.bedroomFloorSetPoint = dialFloor.value
+            }
+
+            Label {
+                x: 0
+                width: dialFloor.width
+                y: 0
+                height: dialFloor.height
+                id: thermoFloorSetLabel
+                text: dialFloor.value.toFixed(1)
+                font.pixelSize: 32
+                font.family: digital.font.family
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+        }
+
+
+        Switch {
+            id: switchAC
+            x: 35
+            width: dialAC.width
+            y: 143
+            checked: openHABInterface.bedroomACToggle
+            scale: 1.5
+            onToggled:
+            {
+                openHABInterface.bedroomACToggle = switchAC.checked
+            }
+        }
+
+    }
+
+    RoundButton {
+        id: allLightsOffButton
+        x: 610
+        y: 610
+        width: 100
+        height: 100
+        icon.source: "qrc:/images/moon.png"
+        icon.name: "night"
+        icon.width: 64
+        icon.height: 64
+        onClicked:
+        {
+            openHABInterface.signalItem("BedroomGoodnight")
+        }
+    }
+
+
+    Image {
+        id: outdoorTempImage
+        x: 10
+        y: 590
+        width: 54
+        height: 60
+        source: "qrc:/images/frontdoor.png"
+        fillMode: Image.PreserveAspectFit
+    }
+    Label {
+        id: outdoorTemp
+        x: 70
+        y: 590
+        width: 100
+        height: 60
+        text: openHABInterface.outdoorTemperature.toFixed(1)
+        font.pixelSize: 52
+        font.family: digital.font.family
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignBottom
+    }
+    Label {
+        id: unitOutdoorTemp
+        x: 175
+        y: 590
+        width: 30
+        height: 60
+        text: "°C"
+        font.pixelSize: 32
+        horizontalAlignment: Text.AlignLeft
+        verticalAlignment: Text.AlignBottom
+    }
+    Image {
+        id: powerImage
+        x: 10
+        y: 650
+        width: 54
+        height: 60
+        source: "qrc:/images/energy.png"
+        fillMode: Image.PreserveAspectFit
+    }
+    Label {
+        id: textPower
+        x: 70
+        y: 650
+        width: 100
+        height: 60
+        text: openHABInterface.mainPowerUsage < 1000 ? openHABInterface.mainPowerUsage.toFixed(0) : (openHABInterface.mainPowerUsage / 1000).toFixed(2)
+        font.pixelSize: 52
+        font.family: digital.font.family
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignBottom
+    }
+    Label {
+        id: unitPower
+        x: 175
+        y: 650
+        width: 30
+        height: 60
+        text: openHABInterface.mainPowerUsage < 1000 ? "W" : "kW"
+        font.pixelSize: 32
+        horizontalAlignment: Text.AlignLeft
+        verticalAlignment: Text.AlignBottom
+    }
+}
diff --git a/MainOffice.qml b/MainOffice.qml
new file mode 100644 (file)
index 0000000..c77b76e
--- /dev/null
@@ -0,0 +1,376 @@
+import QtQuick
+import QtQuick.Controls 6.3
+import QtQuick.Layouts 6.3
+import qthomecontrol
+
+Window {
+    width: 720
+    height: 720
+    visible: true
+    title: qsTr("Home Control")
+    visibility: "FullScreen"
+    color: Material.backgroundColor
+
+    OpenHABInterface {
+        id: openHABInterface
+    }
+
+    BackLightController {
+        id: backlightController
+    }
+
+    FontLoader { id: digital; source: "qrc:/fonts/digital-7.ttf" }
+
+    Label {
+        id: textTime
+        x: 620
+        y: 10
+        width: 90
+        height: 50
+        font.pixelSize: 36
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignTop
+    }
+
+
+    Timer {
+        id: timer
+        interval: 1000
+        repeat: true
+        running: true
+
+        onTriggered:
+        {
+            textTime.text =  Qt.formatTime(new Date(),"hh:mm")
+        }
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        hoverEnabled: true
+        propagateComposedEvents: true
+        onPositionChanged: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onClicked: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onPressed: {
+            backlightController.hadInteraction();
+            mouse.accepted = false;
+        }
+        onReleased: mouse.accepted = false;
+        onDoubleClicked: mouse.accepted = false;
+        onPressAndHold: mouse.accepted = false;
+        z: 100
+    }
+
+    GroupBox {
+        id: groupBox
+        x: 15
+        y: 10
+        width: 483
+        height: 490
+        label: Label {
+            id: officeLabel
+            text: "Office"
+            font.pixelSize: 32
+        }
+        Slider {
+            id: slider
+            x: 245
+            y: 83
+            width: 190
+            height: 25
+            live: true
+            antialiasing: true
+            topPadding: 0
+            bottomPadding: 0
+            orientation: Qt.Horizontal
+            snapMode: RangeSlider.SnapOnRelease
+            stepSize: 1
+            to: 100
+            value: openHABInterface.officeDimmer
+            scale: 1.5
+            onMoved:
+            {
+                openHABInterface.officeDimmer = slider.value
+            }
+        }
+
+        Label {
+            id: textTemp
+            x: 50
+            y: 0
+            width: 100
+            height: 60
+            text: openHABInterface.officeTemperature.toFixed(1)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitTemp
+            x: 155
+            y: 0
+            width: 30
+            height: 60
+            text: "°C"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Label {
+            id: textHumid
+            x: 50
+            y: 60
+            width: 100
+            height: 60
+            text: openHABInterface.officeHumidity.toFixed(0)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitHumid
+            x: 155
+            y: 60
+            width: 30
+            height: 60
+            text: "%"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Label {
+            id: textPressure
+            x: 50
+            y: 120
+            width: 150
+            height: 60
+            text: openHABInterface.officePressure.toFixed(1)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitPressure
+            x: 205
+            y: 120
+            width: 30
+            height: 60
+            text: "hPa"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Label {
+            id: textLight
+            x: 250
+            y: 0
+            width: 100
+            height: 60
+            text: openHABInterface.officeDimmer.toFixed(0)
+            font.pixelSize: 52
+            font.family: digital.font.family
+            horizontalAlignment: Text.AlignRight
+            verticalAlignment: Text.AlignBottom
+        }
+        Label {
+            id: unitDimmer
+            x: 357
+            y: 0
+            width: 30
+            height: 60
+            text: "%"
+            font.pixelSize: 32
+            horizontalAlignment: Text.AlignLeft
+            verticalAlignment: Text.AlignBottom
+        }
+
+        Image {
+            id: tempImage
+            x: 10
+            y: 0
+            width: 54
+            height: 60
+            source: "qrc:/images/temperature.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Image {
+            id: humidImage
+            x: 10
+            y: 60
+            width: 54
+            height: 60
+            source: "qrc:/images/humidity.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Image {
+            id: pressureImage
+            x: 10
+            y: 120
+            width: 54
+            height: 60
+            source: "qrc:/images/pressure.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Image {
+            id: lightImage
+            x: 235
+            y: 0
+            width: 54
+            height: 60
+            source: "qrc:/images/light.png"
+            fillMode: Image.PreserveAspectFit
+        }
+        Dial {
+            id: dialAC
+            x: 35
+            y: 290
+            inputMode: Dial.Vertical
+            scale: 1.5
+
+            from: 16
+            value: openHABInterface.officeACSetPoint
+            to: 26
+            stepSize: 0.5
+            snapMode: Dial.SnapAlways
+
+            onMoved: {
+                openHABInterface.officeACSetPoint = dialAC.value
+            }
+
+            Label {
+                x: 0
+                width: dialAC.width
+                y: 0
+                height: dialAC.height
+                id: thermoSetLabel
+                text: dialAC.value.toFixed(1)
+                font.pixelSize: 32
+                font.family: digital.font.family
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+        }
+        Dial {
+            id: dialFloor
+            x: 50 + dialFloor.width * 1.5
+            y: 290
+            inputMode: Dial.Vertical
+            scale: 1.5
+
+            from: 16
+            value: openHABInterface.officeFloorSetPoint
+            to: 24
+            stepSize: 0.5
+            snapMode: Dial.SnapAlways
+
+            onMoved: {
+                openHABInterface.officeFloorSetPoint = dialFloor.value
+            }
+
+            Label {
+                x: 0
+                width: dialFloor.width
+                y: 0
+                height: dialFloor.height
+                id: thermoFloorSetLabel
+                text: dialFloor.value.toFixed(1)
+                font.pixelSize: 32
+                font.family: digital.font.family
+                horizontalAlignment: Text.AlignHCenter
+                verticalAlignment: Text.AlignVCenter
+            }
+        }
+
+
+        Switch {
+            id: switchAC
+            x: 35
+            width: dialAC.width
+            y: 203
+            checked: openHABInterface.officeACToggle
+            scale: 1.5
+            onToggled:
+            {
+                openHABInterface.officeACToggle = switchAC.checked
+            }
+        }
+
+    }
+
+    Image {
+        id: outdoorTempImage
+        x: 10
+        y: 590
+        width: 54
+        height: 60
+        source: "qrc:/images/frontdoor.png"
+        fillMode: Image.PreserveAspectFit
+    }
+    Label {
+        id: outdoorTemp
+        x: 70
+        y: 590
+        width: 100
+        height: 60
+        text: openHABInterface.outdoorTemperature.toFixed(1)
+        font.pixelSize: 52
+        font.family: digital.font.family
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignBottom
+    }
+    Label {
+        id: unitOutdoorTemp
+        x: 175
+        y: 590
+        width: 30
+        height: 60
+        text: "°C"
+        font.pixelSize: 32
+        horizontalAlignment: Text.AlignLeft
+        verticalAlignment: Text.AlignBottom
+    }
+    Image {
+        id: powerImage
+        x: 10
+        y: 650
+        width: 54
+        height: 60
+        source: "qrc:/images/energy.png"
+        fillMode: Image.PreserveAspectFit
+    }
+    Label {
+        id: textPower
+        x: 70
+        y: 650
+        width: 100
+        height: 60
+        text: openHABInterface.mainPowerUsage < 1000 ? openHABInterface.mainPowerUsage.toFixed(0) : (openHABInterface.mainPowerUsage / 1000).toFixed(2)
+        font.pixelSize: 52
+        font.family: digital.font.family
+        horizontalAlignment: Text.AlignRight
+        verticalAlignment: Text.AlignBottom
+    }
+    Label {
+        id: unitPower
+        x: 175
+        y: 650
+        width: 30
+        height: 60
+        text: openHABInterface.mainPowerUsage < 1000 ? "W" : "kW"
+        font.pixelSize: 32
+        horizontalAlignment: Text.AlignLeft
+        verticalAlignment: Text.AlignBottom
+    }
+}
diff --git a/backlightcontroller.cpp b/backlightcontroller.cpp
new file mode 100644 (file)
index 0000000..3cb8f92
--- /dev/null
@@ -0,0 +1,91 @@
+#include "backlightcontroller.h"
+#ifdef USE_PWM
+#define PWM_PERIOD "500000"
+#define PWM_DUTYCYCLE_DIM "380000"
+#define PWM_DUTYCYCLE_ON "100000"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <thread>
+#endif
+
+BackLightController::BackLightController(QObject *parent)
+    : QObject{parent}
+{
+#ifdef USE_PWM
+    int fd;
+
+    fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
+    if (-1 == fd) {
+        fprintf(stderr, "Failed to open export for writing.\n");
+    }
+    write(fd, "0", 2);
+    close(fd);
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+    fd = open("/sys/class/pwm/pwmchip0/pwm0/period", O_WRONLY);
+    if (-1 == fd) {
+        fprintf(stderr, "Failed to open PWM period for writing.\n");
+    }
+    write(fd, PWM_PERIOD, strlen(PWM_PERIOD));
+    close(fd);
+
+    fd = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_WRONLY);
+    if (-1 == fd) {
+        fprintf(stderr, "Failed to open PWM duty cycle for writing.\n");
+    }
+    write(fd, PWM_DUTYCYCLE_DIM, strlen(PWM_DUTYCYCLE_DIM));
+    close(fd);
+
+    fd = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_WRONLY);
+    if (-1 == fd) {
+        fprintf(stderr, "Failed to open PWM for writing.\n");
+    }
+    write(fd, "1", 2);
+    close(fd);
+#endif
+    updateBackLight(false);
+}
+
+void
+BackLightController::hadInteraction()
+{
+    updateBackLight(true);
+    mOffTimer.reset(new QTimer(this));
+    mOffTimer->callOnTimeout(this, &BackLightController::backlightTimedOut);
+    mOffTimer->setSingleShot(true);
+    mOffTimer->start(10000);
+}
+
+void
+BackLightController::backlightTimedOut()
+{
+    updateBackLight(false);
+}
+
+void
+BackLightController::updateBackLight(bool aState)
+{
+    if (mBackLightIsHigh == aState) {
+        return;
+    }
+
+#ifdef USE_PWM
+    int fd;
+    fd = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_WRONLY);
+    if (-1 == fd) {
+        fprintf(stderr, "Failed to open PWM duty cycle for writing.\n");
+    }
+    write(fd, aState ? PWM_DUTYCYCLE_ON : PWM_DUTYCYCLE_DIM, aState ? strlen(PWM_DUTYCYCLE_ON) : strlen(PWM_DUTYCYCLE_DIM));
+    close(fd);
+#endif
+    if (aState) {
+        // turn on backlight
+        mBackLightIsHigh = true;
+    } else {
+        mBackLightIsHigh = false;
+    }
+}
diff --git a/backlightcontroller.h b/backlightcontroller.h
new file mode 100644 (file)
index 0000000..19b1788
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef BACKLIGHTCONTROLLER_H
+#define BACKLIGHTCONTROLLER_H
+
+#include <QObject>
+#include <QQmlEngine>
+#include <QScopedPointer>
+#include <QTimer>
+
+class BackLightController : public QObject
+{
+    Q_OBJECT
+    QML_ELEMENT
+public:
+    explicit BackLightController(QObject *parent = nullptr);
+
+public slots:
+    void hadInteraction();
+    void backlightTimedOut();
+
+private:
+    void updateBackLight(bool aState);
+
+    bool mBackLightIsHigh = false;
+    QScopedPointer<QTimer> mOffTimer;
+};
+
+#endif // BACKLIGHTCONTROLLER_H
diff --git a/fonts/DigitalDream.ttf b/fonts/DigitalDream.ttf
new file mode 100644 (file)
index 0000000..25ab5de
Binary files /dev/null and b/fonts/DigitalDream.ttf differ
diff --git a/fonts/digital-7.ttf b/fonts/digital-7.ttf
new file mode 100644 (file)
index 0000000..5dbe6f9
Binary files /dev/null and b/fonts/digital-7.ttf differ
diff --git a/images/energy.png b/images/energy.png
new file mode 100644 (file)
index 0000000..07f0773
Binary files /dev/null and b/images/energy.png differ
diff --git a/images/frontdoor.png b/images/frontdoor.png
new file mode 100644 (file)
index 0000000..d0378b6
Binary files /dev/null and b/images/frontdoor.png differ
diff --git a/images/humidity.png b/images/humidity.png
new file mode 100644 (file)
index 0000000..00f58df
Binary files /dev/null and b/images/humidity.png differ
diff --git a/images/light.png b/images/light.png
new file mode 100644 (file)
index 0000000..2e5b762
Binary files /dev/null and b/images/light.png differ
diff --git a/images/moon.png b/images/moon.png
new file mode 100644 (file)
index 0000000..bbe7893
Binary files /dev/null and b/images/moon.png differ
diff --git a/images/pressure.png b/images/pressure.png
new file mode 100644 (file)
index 0000000..d91d298
Binary files /dev/null and b/images/pressure.png differ
diff --git a/images/temperature.png b/images/temperature.png
new file mode 100644 (file)
index 0000000..2fddbbe
Binary files /dev/null and b/images/temperature.png differ
diff --git a/itemdefinitions.h b/itemdefinitions.h
new file mode 100644 (file)
index 0000000..756bae7
--- /dev/null
@@ -0,0 +1,15 @@
+DEFINE_ITEM(bedroomTemperature, Bedroom_Thermostat_Temperature, float, temperature)
+DEFINE_ITEM(bedroomHumidity, Bedroom_Thermostat_Humidity, float, humidity)
+DEFINE_ITEM(bedroomDimmer, BedroomLight_Dimmer, float, dimmer)
+DEFINE_ITEM(bedroomACToggle, ACDeviceSlaapkamer_Power, bool, toggle)
+DEFINE_ITEM(bedroomACSetPoint, AC_Device__Slaapkamer_Set_Temperature, float, temperatureWithUnit)
+DEFINE_ITEM(bedroomFloorSetPoint, Bedroom_Thermostat_Setpoint, float, temperature)
+DEFINE_ITEM(officeTemperature, Office_Thermostat_Temperature, float, temperature)
+DEFINE_ITEM(officeHumidity, Office_Thermostat_Humidity, float, humidityWithUnit)
+DEFINE_ITEM(officePressure, Office_Thermostat_Pressure, float, pressure)
+DEFINE_ITEM(officeDimmer, OfficeLight_Dimmer, float, dimmer)
+DEFINE_ITEM(officeACToggle, ACDeviceOffice_Power, bool, toggle)
+DEFINE_ITEM(officeACSetPoint, ACDeviceOffice_SetTemperature, float, temperatureWithUnit)
+DEFINE_ITEM(officeFloorSetPoint, Office_Thermostat_Setpoint, float, temperature)
+DEFINE_ITEM(mainPowerUsage, MainElectricityMeter_ActualPowerDelivery, float, power)
+DEFINE_ITEM(outdoorTemperature, Nibe_BT1_Outdoor_Temperature_Sensor_Nibe_BT1_Outdoor_Temperature, float, temperature)
index 6086143fa16f00a085cc6e2ab7626852203b0222..099898f7ac278d037099c1fdb0677679873dd679 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -1,16 +1,31 @@
 #include <QGuiApplication>
 #include <QQmlApplicationEngine>
 #include <QGuiApplication>
 #include <QQmlApplicationEngine>
-
+#include <QQuickStyle>
+#include <QStyleHints>
+#include <QCursor>
 
 int main(int argc, char *argv[])
 {
     QGuiApplication app(argc, argv);
 
 
 int main(int argc, char *argv[])
 {
     QGuiApplication app(argc, argv);
 
+    //app.setOverrideCursor(QCursor(Qt::BlankCursor));
+
+    QString panelString("MainBedroom");
+    if (argc >= 2) {
+        for (int i = 0; i < argc; i++) {
+            if (!strncasecmp(argv[i], "-p", 2)) {
+                if (!strncasecmp(argv[++i], "office", 6)) {
+                    panelString = "MainOffice";
+                }
+            }
+        }
+    }
+
     QQmlApplicationEngine engine;
     QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
         &app, []() { QCoreApplication::exit(-1); },
         Qt::QueuedConnection);
     QQmlApplicationEngine engine;
     QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
         &app, []() { QCoreApplication::exit(-1); },
         Qt::QueuedConnection);
-    engine.loadFromModule("qthomecontrol", "Main");
+    engine.loadFromModule("qthomecontrol", panelString);
 
     return app.exec();
 }
 
     return app.exec();
 }
diff --git a/mqttinterface.cpp b/mqttinterface.cpp
deleted file mode 100644 (file)
index 2958895..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#include "mqttinterface.h"
-
-using namespace std;
-
-void delivered(void* context, MQTTClient_deliveryToken dt)
-{
-  MQTTInterface* thermostat = static_cast<MQTTInterface*>(context);
-  //thermostat->DeliverToken(dt);
-}
-
-int msgarrvd(void* context, char* topicName, int topicLen, MQTTClient_message* message)
-{
-  MQTTInterface* thermostat = static_cast<MQTTInterface*>(context);
-
-  if (string(topicName) == "bedroom/thermostat/temperature/raw") {
-      float temperature = stof(string((char*)message->payload));
-      thermostat->updateBedroomTemperature(temperature);
-  } else if (string(topicName) == "bedroom/thermostat/humidity/raw") {
-      float humidity = stof(string((char*)message->payload));
-      thermostat->updateBedroomHumidity(humidity);
-  }
-
-  MQTTClient_freeMessage(&message);
-  MQTTClient_free(topicName);
-
-
-  return 1;
-}
-
-void connlost(void* context, char* cause)
-{
-  MQTTInterface* thermostat = static_cast<MQTTInterface*>(context);
-
-  printf("\nConnection lost\n");
-  printf("     cause: %s\n", cause);
-
-  //thermostat->ShouldReconnect();
-}
-
-#define QOS 1
-
-MQTTInterface::MQTTInterface(QObject *parent)
-    : QObject{parent}
-{
-    MQTTClient_message pubmsg = MQTTClient_message_initializer;
-    MQTTClient_deliveryToken token;
-
-    int rc;
-    MQTTClient_create(&mClient, "tcp://10.0.1.225:1883", "bedroom-thermostat-fe",
-      MQTTCLIENT_PERSISTENCE_NONE, NULL);
-
-    if ((rc = MQTTClient_setCallbacks(mClient, this, connlost, msgarrvd, delivered)) != MQTTCLIENT_SUCCESS)
-    {
-      printf("Failed to set callbacks, return code %d\n", rc);
-      return;
-    }
-
-    connectToServer();
-
-    char cbuf[256];
-    sprintf(cbuf, "%.1f", 15.3);
-    pubmsg.payload = (void*)cbuf;
-    pubmsg.payloadlen = strlen(cbuf);
-    pubmsg.qos = QOS;
-    pubmsg.retained = 0;
-    MQTTClient_publishMessage(mClient, "newtest/test", &pubmsg, &token);
-}
-
-void
-MQTTInterface::updateBedroomTemperature(float aTemperature)
-{
-    {
-        unique_lock<mutex> lk(mDataMutex);
-        mBedroomTemperature = aTemperature;
-    }
-
-    emit bedroomTemperatureChanged();
-}
-
-void
-MQTTInterface::updateBedroomHumidity(float aHumidity)
-{
-    {
-        unique_lock<mutex> lk(mDataMutex);
-        mBedroomHumidity = aHumidity;
-    }
-
-    emit bedroomHumidityChanged();
-}
-
-void
-MQTTInterface::connectToServer()
-{
-  int rc = 0;
-  MQTTClient_disconnect(mClient, 10000);
-
-  MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
-  conn_opts.keepAliveInterval = 20;
-  conn_opts.cleansession = 1;
-
-  if ((rc = MQTTClient_connect(mClient, &conn_opts)) != MQTTCLIENT_SUCCESS)
-  {
-    printf("Failed to connect, return code %d\n", rc);
-    return;
-  }
-
-  if ((rc = MQTTClient_subscribe(mClient, "bedroom/thermostat/temperature/raw", QOS)) != MQTTCLIENT_SUCCESS)
-  {
-    printf("Failed to subscribe, return code %d\n", rc);
-  }
-  if ((rc = MQTTClient_subscribe(mClient, "bedroom/thermostat/humidity/raw", QOS)) != MQTTCLIENT_SUCCESS)
-  {
-    printf("Failed to subscribe, return code %d\n", rc);
-  }
-}
diff --git a/mqttinterface.h b/mqttinterface.h
deleted file mode 100644 (file)
index 1b54a9a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef MQTTINTERFACE_H
-#define MQTTINTERFACE_H
-
-#include <QObject>
-#include <QtQml/qqmlregistration.h>
-#include <mutex>
-
-#include "MQTTClient.h"
-
-class MQTTInterface : public QObject
-{
-    Q_OBJECT
-    Q_PROPERTY(qreal bedroomTemperature READ bedroomTemperature NOTIFY bedroomTemperatureChanged);
-    Q_PROPERTY(qreal bedroomHumidity READ bedroomHumidity NOTIFY bedroomHumidityChanged);
-    QML_ELEMENT
-
-public:
-    explicit MQTTInterface(QObject *parent = nullptr);
-
-    qreal bedroomTemperature() {
-        std::unique_lock<std::mutex> lk(mDataMutex);
-        return mBedroomTemperature;
-    }
-    qreal bedroomHumidity() {
-        std::unique_lock<std::mutex> lk(mDataMutex);
-        return mBedroomHumidity;
-    }
-
-    void updateBedroomTemperature(float aTemperature);
-    void updateBedroomHumidity(float aHumidity);
-
-signals:
-    void bedroomTemperatureChanged();
-    void bedroomHumidityChanged();
-
-private:
-    void connectToServer();
-
-    qreal mBedroomTemperature = 10;
-    qreal mBedroomHumidity = 50;
-    MQTTClient mClient;
-    std::mutex mDataMutex;
-};
-
-#endif // MQTTINTERFACE_H
diff --git a/openhabinterface.cpp b/openhabinterface.cpp
new file mode 100644 (file)
index 0000000..c09cf03
--- /dev/null
@@ -0,0 +1,131 @@
+#include "openhabinterface.h"
+
+#include <QJsonDocument>
+#include <QJsonObject>
+
+using namespace std;
+
+QJsonObject createCommandMessage(const char* aItemName) {
+    QJsonObject jsonObject;
+    jsonObject["type"] = "ItemCommandEvent";
+    jsonObject["topic"] = QString("openhab/items/") + aItemName + QString("/command");
+    jsonObject["source"] = "BedroomHomeControl";
+    return jsonObject;
+}
+
+OpenHABInterface::OpenHABInterface(QObject *parent)
+    : QObject{parent}
+{
+#define DEFINE_ITEM(name, itemName, ctype, type) \
+    mItems.push_back(ItemDescription{ &m_##name, "openhab/items/"#itemName"/state", #itemName, std::bind(&OpenHABInterface::name##Changed, this), ItemType::type });
+#include "itemdefinitions.h"
+#undef DEFINE_ITEM
+
+    connect(&mOpenHABSocket, &QWebSocket::errorOccurred, this, &OpenHABInterface::socketError);
+    connect(&mOpenHABSocket, &QWebSocket::textMessageReceived, this, &OpenHABInterface::openHABMessageReceived);
+    connectToServer();
+
+    for (const ItemDescription& item : mItems) {
+        if (item.mType == ItemType::toggle) {
+            *reinterpret_cast<bool*>(item.mValue) = false;
+        } else {
+            *reinterpret_cast<float*>(item.mValue) = 0;
+        }
+    }
+}
+
+void
+OpenHABInterface::socketError(QAbstractSocket::SocketError aError)
+{
+}
+
+void
+OpenHABInterface::openHABMessageReceived(const QString& aMessage)
+{
+    QJsonDocument receivedMessage = QJsonDocument::fromJson(aMessage.toUtf8().data());
+
+    if (!receivedMessage["topic"].isString()) {
+        return;
+    }
+
+    const QString& topic = receivedMessage["topic"].toString();
+
+    for (const ItemDescription& item : mItems) {
+        if (topic == item.mOpenHABState) {
+            if (item.mType == ItemType::dimmer || item.mType == ItemType::temperature || item.mType == ItemType::humidity || item.mType == ItemType::pressure) {
+                QJsonDocument payload = QJsonDocument::fromJson(receivedMessage["payload"].toString().toUtf8().data());
+                float value = payload["value"].toString().toFloat();
+                *reinterpret_cast<float*>(item.mValue) = value;
+                emit item.mSignal();
+            } else if (item.mType == ItemType::humidityWithUnit) {
+                QJsonDocument payload = QJsonDocument::fromJson(receivedMessage["payload"].toString().toUtf8().data());
+                QString valueString = payload["value"].toString();
+                valueString.chop(2);
+                float value = valueString.toFloat();
+                *reinterpret_cast<float*>(item.mValue) = value;
+                emit item.mSignal();
+            } else if (item.mType == ItemType::temperatureWithUnit) {
+                QJsonDocument payload = QJsonDocument::fromJson(receivedMessage["payload"].toString().toUtf8().data());
+                QString valueString = payload["value"].toString();
+                valueString.chop(3);
+                float value = valueString.toFloat();
+                *reinterpret_cast<float*>(item.mValue) = value;
+                emit item.mSignal();
+            } else if (item.mType == ItemType::power) {
+                QJsonDocument payload = QJsonDocument::fromJson(receivedMessage["payload"].toString().toUtf8().data());
+                QString valueString = payload["value"].toString();
+                valueString.chop(3);
+                float value = valueString.toFloat() * 1000;
+                *reinterpret_cast<float*>(item.mValue) = value;
+                emit item.mSignal();
+            } else if (item.mType == ItemType::toggle) {
+                QJsonDocument payload = QJsonDocument::fromJson(receivedMessage["payload"].toString().toUtf8().data());
+                *reinterpret_cast<bool*>(item.mValue) = payload["value"].toString() == "ON";
+                emit item.mSignal();
+            }
+        }
+    }
+}
+
+void
+OpenHABInterface::signalItem(const QString& aItem)
+{
+    QJsonObject commandObject = createCommandMessage(aItem.toStdString().c_str());
+    commandObject["payload"] = "{\"type\":\"OnOff\",\"value\":\"OFF\"}";
+    QJsonDocument commandDocument;
+    commandDocument.setObject(commandObject);
+    mOpenHABSocket.sendTextMessage(QString::fromUtf8(commandDocument.toJson()));
+}
+
+void
+OpenHABInterface::writeValue(const char* aItemName, ItemType aType, float aValue)
+{
+    QJsonObject commandObject = createCommandMessage(aItemName);
+
+    if (aType == ItemType::dimmer) {
+        commandObject["payload"] = "{\"type\":\"Percent\",\"value\":\"" + QString::number(aValue, 'f', 0) + "\"}";
+    } else if (aType == ItemType::temperature) {
+        commandObject["payload"] = "{\"type\":\"Decimal\",\"value\":\"" + QString::number(aValue, 'f', 1) + "\"}";
+    } else if (aType == ItemType::temperatureWithUnit) {
+        commandObject["payload"] = "{\"type\":\"Quantity\",\"value\":\"" + QString::number(aValue, 'f', 1) + " °C\"}";
+    }
+    QJsonDocument commandDocument;
+    commandDocument.setObject(commandObject);
+    mOpenHABSocket.sendTextMessage(QString::fromUtf8(commandDocument.toJson()));
+}
+
+void
+OpenHABInterface::writeValue(const char* aItemName, ItemType aType, bool aValue)
+{
+    QJsonObject commandObject = createCommandMessage(aItemName);
+    commandObject["payload"] = "{\"type\":\"OnOff\",\"value\":\"" + QString(aValue ? "ON" : "OFF") + "\"}";
+    QJsonDocument commandDocument;
+    commandDocument.setObject(commandObject);
+    mOpenHABSocket.sendTextMessage(QString::fromUtf8(commandDocument.toJson()));
+}
+
+void
+OpenHABInterface::connectToServer()
+{
+    mOpenHABSocket.open(QUrl("ws://10.0.1.225:8080/ws"));
+}
diff --git a/openhabinterface.h b/openhabinterface.h
new file mode 100644 (file)
index 0000000..d3c0b75
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef OPENHABINTERFACE_H
+#define OPENHABINTERFACE_H
+
+#include <QObject>
+#include <QtQml/qqmlregistration.h>
+#include <QWebSocket>
+#include <mutex>
+#include <vector>
+
+class OpenHABInterface : public QObject
+{
+    Q_OBJECT
+#define DEFINE_ITEM(name, itemName, ctype, type) \
+    Q_PROPERTY(ctype name READ name WRITE set##name NOTIFY name##Changed);
+#include "itemdefinitions.h"
+#undef DEFINE_ITEM
+    QML_ELEMENT
+
+    enum class ItemType {
+        temperature,
+        temperatureWithUnit,
+        humidity,
+        humidityWithUnit,
+        dimmer,
+        toggle,
+        power,
+        pressure
+    };
+
+public:
+    explicit OpenHABInterface(QObject *parent = nullptr);
+
+#define DEFINE_ITEM(name, itemName, ctype, type) \
+    ctype name() { \
+        std::unique_lock<std::mutex> lk(mDataMutex); \
+        return m_##name; \
+    } \
+    void set##name(ctype aValue) { \
+      { \
+        std::unique_lock<std::mutex> lk(mDataMutex); \
+        m_##name = aValue; \
+      } \
+\
+      writeValue(#itemName, ItemType::type, aValue); \
+      emit name##Changed(); \
+    }
+#include "itemdefinitions.h"
+#undef DEFINE_ITEM
+
+public slots:
+    void socketError(QAbstractSocket::SocketError aError);
+    void openHABMessageReceived(const QString& message);
+    void signalItem(const QString& item);
+
+signals:
+// Ugh, Qt doesn't understand macros inside here.
+//#define DEFINE_ITEM(name, itemName, type) \
+//    void name##Changed();
+//#include "itemdefinitions.h"
+//#undef DEFINE_ITEM
+    void bedroomTemperatureChanged();
+    void bedroomHumidityChanged();
+    void bedroomDimmerChanged();
+    void bedroomACToggleChanged();
+    void bedroomACSetPointChanged();
+    void bedroomFloorSetPointChanged();
+    void officeTemperatureChanged();
+    void officeHumidityChanged();
+    void officePressureChanged();
+    void officeDimmerChanged();
+    void officeACToggleChanged();
+    void officeACSetPointChanged();
+    void officeFloorSetPointChanged();
+    void mainPowerUsageChanged();
+    void outdoorTemperatureChanged();
+
+private:
+    void connectToServer();
+
+    void writeValue(const char* aItemName, ItemType aItemType, float aValue);
+    void writeValue(const char* aItemName, ItemType aItemType, bool aValue);
+
+
+#define DEFINE_ITEM(name, itemName, ctype, type) \
+    ctype m_##name;
+#include "itemdefinitions.h"
+#undef DEFINE_ITEM
+
+    struct ItemDescription {
+        void* mValue;
+        const char* mOpenHABState;
+        const char* mOpenHABCommand;
+        std::function<void()> mSignal;
+        ItemType mType;
+    };
+
+    std::mutex mDataMutex;
+    QWebSocket mOpenHABSocket;
+    std::vector<ItemDescription> mItems;
+};
+
+#endif // OPENHABINTERFACE_H
diff --git a/paho.mqtt.c b/paho.mqtt.c
deleted file mode 160000 (submodule)
index f7799da..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f7799da95e347bbc930b201b52a1173ebbad45a7
diff --git a/qtquickcontrols2.conf b/qtquickcontrols2.conf
new file mode 100644 (file)
index 0000000..e1c0add
--- /dev/null
@@ -0,0 +1,5 @@
+[Controls]
+Style=Material
+
+[Material]
+Theme=Dark
diff --git a/resources.qrc b/resources.qrc
new file mode 100644 (file)
index 0000000..4fbf17b
--- /dev/null
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/">
+        <file>qtquickcontrols2.conf</file>
+    </qresource>
+</RCC>