diff options
author | Andrew O'Doherty <andrew.odoherty@qt.io> | 2018-04-27 12:37:48 +0200 |
---|---|---|
committer | Andrew O'Doherty <andrew.odoherty@qt.io> | 2018-05-31 13:25:24 +0000 |
commit | 22cdfdd27aaa885ac5b7b450c8fb82b87853250d (patch) | |
tree | 7ffcc3e15d66824386cbd78397f55cbc5d618018 /tradeshow | |
parent | efba3d85875b20bd40e93bc6d94aca1531f25aae (diff) |
add 3d alexa knx demo
The knx-demo directory needs to be divided into two sub-directories
containing the alexa 3D demo and the 2d demo. Very large files used by
the 3d demo are stored in
https://git-lfs.qt.io/Gerrit/boot2qt-demos.git
Change-Id: I55e4210e93fc9e017d85e163f13c0b04de96cff0
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
Diffstat (limited to 'tradeshow')
136 files changed, 5494 insertions, 0 deletions
diff --git a/tradeshow/knx-demo/demo.pro b/tradeshow/knx-demo/2d-knx-demo/demo.pro index f5473de..f5473de 100644 --- a/tradeshow/knx-demo/demo.pro +++ b/tradeshow/knx-demo/2d-knx-demo/demo.pro diff --git a/tradeshow/knx-demo/demodatapoint.cpp b/tradeshow/knx-demo/2d-knx-demo/demodatapoint.cpp index 710a6e0..710a6e0 100644 --- a/tradeshow/knx-demo/demodatapoint.cpp +++ b/tradeshow/knx-demo/2d-knx-demo/demodatapoint.cpp diff --git a/tradeshow/knx-demo/demodatapoint.h b/tradeshow/knx-demo/2d-knx-demo/demodatapoint.h index 1810203..1810203 100644 --- a/tradeshow/knx-demo/demodatapoint.h +++ b/tradeshow/knx-demo/2d-knx-demo/demodatapoint.h diff --git a/tradeshow/knx-demo/etsdevelopmentboard.cpp b/tradeshow/knx-demo/2d-knx-demo/etsdevelopmentboard.cpp index c8a3ccb..c8a3ccb 100644 --- a/tradeshow/knx-demo/etsdevelopmentboard.cpp +++ b/tradeshow/knx-demo/2d-knx-demo/etsdevelopmentboard.cpp diff --git a/tradeshow/knx-demo/etsdevelopmentboard.h b/tradeshow/knx-demo/2d-knx-demo/etsdevelopmentboard.h index e95c701..e95c701 100644 --- a/tradeshow/knx-demo/etsdevelopmentboard.h +++ b/tradeshow/knx-demo/2d-knx-demo/etsdevelopmentboard.h diff --git a/tradeshow/knx-demo/images/ArrowDown.png b/tradeshow/knx-demo/2d-knx-demo/images/ArrowDown.png Binary files differindex 0606ccc..0606ccc 100644 --- a/tradeshow/knx-demo/images/ArrowDown.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/ArrowDown.png diff --git a/tradeshow/knx-demo/images/ArrowUp.png b/tradeshow/knx-demo/2d-knx-demo/images/ArrowUp.png Binary files differindex ad4fb59..ad4fb59 100644 --- a/tradeshow/knx-demo/images/ArrowUp.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/ArrowUp.png diff --git a/tradeshow/knx-demo/images/Qt-logo-medium.png b/tradeshow/knx-demo/2d-knx-demo/images/Qt-logo-medium.png Binary files differindex 7d42da6..7d42da6 100644 --- a/tradeshow/knx-demo/images/Qt-logo-medium.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/Qt-logo-medium.png diff --git a/tradeshow/knx-demo/images/blind.png b/tradeshow/knx-demo/2d-knx-demo/images/blind.png Binary files differindex fc78346..fc78346 100644 --- a/tradeshow/knx-demo/images/blind.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/blind.png diff --git a/tradeshow/knx-demo/images/blindCover.png b/tradeshow/knx-demo/2d-knx-demo/images/blindCover.png Binary files differindex ae7c752..ae7c752 100644 --- a/tradeshow/knx-demo/images/blindCover.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/blindCover.png diff --git a/tradeshow/knx-demo/images/clock.png b/tradeshow/knx-demo/2d-knx-demo/images/clock.png Binary files differindex f5fb2af..f5fb2af 100644 --- a/tradeshow/knx-demo/images/clock.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/clock.png diff --git a/tradeshow/knx-demo/images/e10View.png b/tradeshow/knx-demo/2d-knx-demo/images/e10View.png Binary files differindex b3df098..b3df098 100644 --- a/tradeshow/knx-demo/images/e10View.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/e10View.png diff --git a/tradeshow/knx-demo/images/e1View.png b/tradeshow/knx-demo/2d-knx-demo/images/e1View.png Binary files differindex 99b8804..99b8804 100644 --- a/tradeshow/knx-demo/images/e1View.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/e1View.png diff --git a/tradeshow/knx-demo/images/e2View.png b/tradeshow/knx-demo/2d-knx-demo/images/e2View.png Binary files differindex 578a2a1..578a2a1 100644 --- a/tradeshow/knx-demo/images/e2View.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/e2View.png diff --git a/tradeshow/knx-demo/images/e3e4View.png b/tradeshow/knx-demo/2d-knx-demo/images/e3e4View.png Binary files differindex d8e97b9..d8e97b9 100644 --- a/tradeshow/knx-demo/images/e3e4View.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/e3e4View.png diff --git a/tradeshow/knx-demo/images/e5e6View.png b/tradeshow/knx-demo/2d-knx-demo/images/e5e6View.png Binary files differindex e2e81fd..e2e81fd 100644 --- a/tradeshow/knx-demo/images/e5e6View.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/e5e6View.png diff --git a/tradeshow/knx-demo/images/icon_light.png b/tradeshow/knx-demo/2d-knx-demo/images/icon_light.png Binary files differindex e59ef79..e59ef79 100644 --- a/tradeshow/knx-demo/images/icon_light.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/icon_light.png diff --git a/tradeshow/knx-demo/images/off.png b/tradeshow/knx-demo/2d-knx-demo/images/off.png Binary files differindex ee01cf7..ee01cf7 100644 --- a/tradeshow/knx-demo/images/off.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/off.png diff --git a/tradeshow/knx-demo/images/on_green.png b/tradeshow/knx-demo/2d-knx-demo/images/on_green.png Binary files differindex 3b7e47e..3b7e47e 100644 --- a/tradeshow/knx-demo/images/on_green.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/on_green.png diff --git a/tradeshow/knx-demo/images/on_orange.png b/tradeshow/knx-demo/2d-knx-demo/images/on_orange.png Binary files differindex ebc0044..ebc0044 100644 --- a/tradeshow/knx-demo/images/on_orange.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/on_orange.png diff --git a/tradeshow/knx-demo/images/quit_icon.png b/tradeshow/knx-demo/2d-knx-demo/images/quit_icon.png Binary files differindex 7b022a3..7b022a3 100644 --- a/tradeshow/knx-demo/images/quit_icon.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/quit_icon.png diff --git a/tradeshow/knx-demo/images/rainbow.png b/tradeshow/knx-demo/2d-knx-demo/images/rainbow.png Binary files differindex b426d37..b426d37 100644 --- a/tradeshow/knx-demo/images/rainbow.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/rainbow.png diff --git a/tradeshow/knx-demo/images/settings_icon.png b/tradeshow/knx-demo/2d-knx-demo/images/settings_icon.png Binary files differindex c0ccb48..c0ccb48 100644 --- a/tradeshow/knx-demo/images/settings_icon.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/settings_icon.png diff --git a/tradeshow/knx-demo/images/stop_orange.png b/tradeshow/knx-demo/2d-knx-demo/images/stop_orange.png Binary files differindex aea256b..aea256b 100644 --- a/tradeshow/knx-demo/images/stop_orange.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/stop_orange.png diff --git a/tradeshow/knx-demo/images/temperature_symbol.png b/tradeshow/knx-demo/2d-knx-demo/images/temperature_symbol.png Binary files differindex cad112f..cad112f 100644 --- a/tradeshow/knx-demo/images/temperature_symbol.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/temperature_symbol.png diff --git a/tradeshow/knx-demo/images/topBar.png b/tradeshow/knx-demo/2d-knx-demo/images/topBar.png Binary files differindex ba4cb1c..ba4cb1c 100644 --- a/tradeshow/knx-demo/images/topBar.png +++ b/tradeshow/knx-demo/2d-knx-demo/images/topBar.png diff --git a/tradeshow/knx-demo/main.cpp b/tradeshow/knx-demo/2d-knx-demo/main.cpp index f1c5fc5..f1c5fc5 100644 --- a/tradeshow/knx-demo/main.cpp +++ b/tradeshow/knx-demo/2d-knx-demo/main.cpp diff --git a/tradeshow/knx-demo/qml.qrc b/tradeshow/knx-demo/2d-knx-demo/qml.qrc index 850bc0d..850bc0d 100644 --- a/tradeshow/knx-demo/qml.qrc +++ b/tradeshow/knx-demo/2d-knx-demo/qml.qrc diff --git a/tradeshow/knx-demo/qmlknxdemo.cpp b/tradeshow/knx-demo/2d-knx-demo/qmlknxdemo.cpp index 4215246..4215246 100644 --- a/tradeshow/knx-demo/qmlknxdemo.cpp +++ b/tradeshow/knx-demo/2d-knx-demo/qmlknxdemo.cpp diff --git a/tradeshow/knx-demo/qmlknxdemo.h b/tradeshow/knx-demo/2d-knx-demo/qmlknxdemo.h index dd9b037..dd9b037 100644 --- a/tradeshow/knx-demo/qmlknxdemo.h +++ b/tradeshow/knx-demo/2d-knx-demo/qmlknxdemo.h diff --git a/tradeshow/knx-demo/qtquickcontrols2.conf b/tradeshow/knx-demo/2d-knx-demo/qtquickcontrols2.conf index 1764b16..1764b16 100644 --- a/tradeshow/knx-demo/qtquickcontrols2.conf +++ b/tradeshow/knx-demo/2d-knx-demo/qtquickcontrols2.conf diff --git a/tradeshow/knx-demo/ui/KnxBoardLayout.qml b/tradeshow/knx-demo/2d-knx-demo/ui/KnxBoardLayout.qml index 5fd5d3a..5fd5d3a 100644 --- a/tradeshow/knx-demo/ui/KnxBoardLayout.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/KnxBoardLayout.qml diff --git a/tradeshow/knx-demo/ui/components/BlindSimulationView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/BlindSimulationView.qml index 11a0fbd..11a0fbd 100644 --- a/tradeshow/knx-demo/ui/components/BlindSimulationView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/BlindSimulationView.qml diff --git a/tradeshow/knx-demo/ui/components/ColorSlider.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/ColorSlider.qml index cf507c7..cf507c7 100644 --- a/tradeshow/knx-demo/ui/components/ColorSlider.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/ColorSlider.qml diff --git a/tradeshow/knx-demo/ui/components/E10LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E10LedView.qml index 79345df..79345df 100644 --- a/tradeshow/knx-demo/ui/components/E10LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E10LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E11LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E11LedView.qml index fd0eee7..fd0eee7 100644 --- a/tradeshow/knx-demo/ui/components/E11LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E11LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E12LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E12LedView.qml index 4b91eab..4b91eab 100644 --- a/tradeshow/knx-demo/ui/components/E12LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E12LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E13LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E13LedView.qml index 9d0e937..9d0e937 100644 --- a/tradeshow/knx-demo/ui/components/E13LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E13LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E14LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E14LedView.qml index 85987d8..85987d8 100644 --- a/tradeshow/knx-demo/ui/components/E14LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E14LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E1LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E1LedView.qml index 6b676c2..6b676c2 100644 --- a/tradeshow/knx-demo/ui/components/E1LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E1LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E2LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E2LedView.qml index f844141..f844141 100644 --- a/tradeshow/knx-demo/ui/components/E2LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E2LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E3E4LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E3E4LedView.qml index cc0f4f8..cc0f4f8 100644 --- a/tradeshow/knx-demo/ui/components/E3E4LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E3E4LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E5E6LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E5E6LedView.qml index 564c050..564c050 100644 --- a/tradeshow/knx-demo/ui/components/E5E6LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E5E6LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E7E8LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E7E8LedView.qml index 92be92f..92be92f 100644 --- a/tradeshow/knx-demo/ui/components/E7E8LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E7E8LedView.qml diff --git a/tradeshow/knx-demo/ui/components/E9LedView.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/E9LedView.qml index e384ea7..e384ea7 100644 --- a/tradeshow/knx-demo/ui/components/E9LedView.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/E9LedView.qml diff --git a/tradeshow/knx-demo/ui/components/KnxSwitch.qml b/tradeshow/knx-demo/2d-knx-demo/ui/components/KnxSwitch.qml index f56bec8..f56bec8 100644 --- a/tradeshow/knx-demo/ui/components/KnxSwitch.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/components/KnxSwitch.qml diff --git a/tradeshow/knx-demo/ui/main.qml b/tradeshow/knx-demo/2d-knx-demo/ui/main.qml index 92399a8..92399a8 100644 --- a/tradeshow/knx-demo/ui/main.qml +++ b/tradeshow/knx-demo/2d-knx-demo/ui/main.qml diff --git a/tradeshow/knx-demo/utils.h b/tradeshow/knx-demo/2d-knx-demo/utils.h index 16c0877..16c0877 100644 --- a/tradeshow/knx-demo/utils.h +++ b/tradeshow/knx-demo/2d-knx-demo/utils.h diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.ico b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.ico new file mode 100644 index 0000000..41756e8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.ico @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5585eea1337687eaefa2223edded680963f45bee56a971c94d11603ee4aaf696 +size 108337 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.pro b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.pro new file mode 100644 index 0000000..e70f4e4 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.pro @@ -0,0 +1,73 @@ +TEMPLATE = app + +# Control KNX board with the demo +CONFIG += KNX_BOARD ALEXA_WEMO +#CONFIG += ALEXA_WEMO + +KNX_BOARD { + requires(qtHaveModule(knx)) + requires(qtHaveModule(network)) + DEFINES += KNX_BACKEND + + QT += knx + CONFIG += c++11 +} + +QT += qml quick + +target.path = $$[QT_INSTALL_EXAMPLES]/studio3d/$$TARGET +INSTALLS += target + +SOURCES += main.cpp \ + housemodel.cpp + +HEADERS += \ + housemodel.h + +RESOURCES += HomeAutom.qrc + +OTHER_FILES += qml/HomeAutom/* + +RC_ICONS += HomeAutom.ico + +KNX_BOARD { + SOURCES += \ + qmlknxdemo.cpp \ + etsdevelopmentboard.cpp \ + demodatapoint.cpp + + HEADERS += \ + qmlknxdemo.h \ + demodatapoint.h \ + utils.h \ + etsdevelopmentboard.h +} + +ALEXA_WEMO { + SOURCES += \ + qupnpservice.cpp \ + qupnprootdevice.cpp \ + qvirtualbelkinwemo.cpp \ + qminimalhttpserver.cpp + + HEADERS += \ + qupnpservice.h \ + qupnprootdevice.h \ + qvirtualbelkinwemo.h \ + qminimalhttpserver.h + + QT += xml +} + +QML_IMPORT_PATH = $$PWD/qml/imports + +DISTFILES += \ + android/AndroidManifest.xml \ + android/gradle/wrapper/gradle-wrapper.jar \ + android/gradlew \ + android/res/values/libs.xml \ + android/build.gradle \ + android/gradle/wrapper/gradle-wrapper.properties \ + android/gradlew.bat + +#ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.qrc b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.qrc new file mode 100644 index 0000000..ca9c557 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/HomeAutom.qrc @@ -0,0 +1,54 @@ +<RCC> + <qresource prefix="/"> + <file>qml/images/QtSymbol.png</file> + <file alias="main.qml">qml/HomeAutom/main.qml</file> + <file alias="HomeView.qml">qml/HomeAutom/HomeView.qml</file> + <file alias="SplashScreen.qml">qml/HomeAutom/SplashScreen.qml</file> + <file alias="MainMenu.qml">qml/HomeAutom/MainMenu.qml</file> + <file alias="TempSlider.qml">qml/HomeAutom/TempSlider.qml</file> + <file alias="SliderControl.qml">qml/HomeAutom/SliderControl.qml</file> + <file alias="LightSlider.qml">qml/HomeAutom/LightSlider.qml</file> + <file alias="RoomLabel.qml">qml/HomeAutom/RoomLabel.qml</file> + <file alias="LightSwitch.qml">qml/HomeAutom/LightSwitch.qml</file> + <file>uip/houseStudio.uip</file> + <file>uip/maps/Ground.png</file> + <file>uip/maps/HouseGroundOpacitymap.png</file> + <file>uip/maps/HouseTexture.png</file> + <file>uip/maps/OpenfootageNET_Pinzgau-512.hdr</file> + <file>uip/maps/Roof.png</file> + <file>uip/models/HeatAreas/meshes/Heat_Entrance HeatAreas.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_BathRoom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_BedRoom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_DressRoom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_LivingRoom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_MasterBedroom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_Sauna.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_StoreRoom.mesh</file> + <file>uip/models/HeatAreas/meshes/HeatAreas Heat_Toilet.mesh</file> + <file>uip/models/HeatAreas/HeatAreas.import</file> + <file>uip/models/House/meshes/Ground.mesh</file> + <file>uip/models/House/meshes/House.mesh</file> + <file>uip/models/House/meshes/Roof.mesh</file> + <file>uip/models/House/meshes/Windows.mesh</file> + <file>uip/models/House/House.import</file> + <file>uip/models/Light/Light.import</file> + <file>uip/House/meshes/house1.mesh</file> + <file>uip/House/meshes/roof1.mesh</file> + <file>uip/maps/BathroomLightmap.png</file> + <file>uip/maps/BedRoomLightmap.png</file> + <file>uip/maps/EntranceLightmap.png</file> + <file>uip/maps/LivingRoomLightMap.png</file> + <file>uip/maps/MasterBedroomLightmap.png</file> + <file>uip/models/RoomLights/RoomLights.import</file> + <file>uip/models/RoomLights/meshes/BathroomLightmap.mesh</file> + <file>uip/models/RoomLights/meshes/BedroomLightmap.mesh</file> + <file>uip/models/RoomLights/meshes/EntranceLightmap.mesh</file> + <file>uip/models/RoomLights/meshes/LivingroomLightMap.mesh</file> + <file>uip/models/RoomLights/meshes/MasterbedroomLightmap.mesh</file> + <file>qml/images/icon_light.png</file> + <file>qml/images/icon_temp.png</file> + <file>uip/maps/HouseTexture.jpg</file> + <file>qml/imports/Style/qmldir</file> + <file>qml/imports/Style/Style.qml</file> + </qresource> +</RCC> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.cpp new file mode 100644 index 0000000..95c82a8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "demodatapoint.h" + +#include <QtCore/QTimer> +#include <QtGui/QColor> +#include <QtKnx/QKnx1Bit> +#include <QtKnx/QKnxNpdu> +#include <QtKnx/QKnxNpduFactory> +#include <QtKnx/QKnxTunnelFrame> + +const QByteArray DemoDataPoint::BytesOn = QByteArray::fromHex("0x1"); +const QByteArray DemoDataPoint::BytesOff = QByteArray::fromHex("0x0"); + +bool DemoSwitchDataPoint::updateDataPointState(const QKnxTunnelFrame &frame) +{ + auto str = frame.serviceInformation().bytes().toHex(); + m_state = (str[str.size() - 1] == '1'); + return true; +} + +void DemoSwitchDataPoint::uiToggle() +{ + m_state = !m_state; +} + +bool DemoSwitchDataPoint::isOn() const +{ + return m_state; +} + +QByteArray DemoSwitchDataPoint::bytes() const +{ + if (m_state) + return DemoDataPoint::BytesOn; + return DemoDataPoint::BytesOff; +} + +bool DemoColorLed::updateDataPointState(const QKnxTunnelFrame &frame) +{ + bool notifyUI = false; + numMsgConfirmation++; + if (frame.messageCode() == QKnxCemiFrame::MessageCode::DataConfirmation) { + // response to request from UI + // wait for three color confirmation to signal UI + if (numMsgConfirmation == 3) + notifyUI = true; + } else if (frame.messageCode() == QKnxCemiFrame::MessageCode::DataIndication) { + // response to request from Board + notifyUI = true; + } + + QKnxSwitch dpt; + dpt.setBytes(frame.npdu().data(), 0, 1); + int value = (dpt.value() == QKnxSwitch::State::On ? 255 : 0); + + auto dstAddress = frame.destinationAddress(); + if (dstAddress == QKnxAddress::createGroup(0, 0, 12)) + m_stateColor.setRed(value); + + else if (dstAddress == QKnxAddress::createGroup(0, 0, 13)) + m_stateColor.setGreen(value); + + else if (dstAddress == QKnxAddress::createGroup(0, 0, 14)) + m_stateColor.setBlue(value); + + if (notifyUI) { + numMsgConfirmation = 0; + emit colorChange(m_stateColor); + } + return false; +} + +QByteArray DemoColorLed::redBytes() const +{ + if (m_stateColor.red() > 0) + return DemoDataPoint::BytesOn; + return DemoDataPoint::BytesOff; +} + +QByteArray DemoColorLed::greenBytes() const +{ + if (m_stateColor.green() > 0) + return DemoDataPoint::BytesOn; + return DemoDataPoint::BytesOff; +} + +QByteArray DemoColorLed::blueBytes() const +{ + if (m_stateColor.blue() > 0) + return DemoDataPoint::BytesOn; + return DemoDataPoint::BytesOff; +} + +QColor DemoColorLed::currentColor() const +{ + return m_stateColor; +} + +void DemoColorLed::setCurrentColor(QColor color) +{ + m_stateColor = color; +} + +bool DemoColorLed::isOn() const +{ + return (m_stateColor != Qt::black); +} + +bool DemoRockerDataPoint::updateDataPointState(const QKnxTunnelFrame &frame) +{ + auto str = frame.serviceInformation().bytes().toHex(); + QString s = str.mid(20, 4); + bool ok; + setPosition(s.toInt(&ok, 16)); + emit rockerChange(m_position); + return false; +} + +void DemoBlindDataPoint::chooseTimeoutHandle(bool blindUp) +{ + if (blindUp) { + disconnect(&m_timer, &QTimer::timeout, this, &DemoBlindDataPoint::moveBlindDown); + connect(&m_timer, &QTimer::timeout, this, &DemoBlindDataPoint::moveBlindUp); + } else { + disconnect(&m_timer, &QTimer::timeout, this, &DemoBlindDataPoint::moveBlindUp); + connect(&m_timer, &QTimer::timeout, this, &DemoBlindDataPoint::moveBlindDown); + } +} + +bool DemoBlindDataPoint::updateDataPointState(const QKnxTunnelFrame &frame) +{ + auto npdu = frame.npdu(); + if (frame.destinationAddress().toString() == "1/0/0") { + stopBlind(); + + QKnx1Bit dpt; + dpt.setBytes(frame.npdu().data(), 0, 1); + + chooseTimeoutHandle(dpt.bit()); + reenableTimer(); + } else if (frame.destinationAddress().toString() == "1/1/0") { + stopBlind(); + } + return false; +} + +void DemoBlindDataPoint::reenableTimer() +{ + if (!m_timer.isActive()) + m_timer.start(50); +} + +void DemoBlindDataPoint::moveBlindUp() +{ + if (m_position == 70) { + stopBlind(); + emit blindFullyUp(); + return; + } + ++m_position; + emit blindChange(m_position); +} + +void DemoBlindDataPoint::moveBlindDown() +{ + if (m_position > 0) { + --m_position; + emit blindChange(m_position); + return; + } + stopBlind(); + emit blindFullyDown(); +} + +void DemoBlindDataPoint::stopBlind() +{ + if (m_timer.isActive()) + m_timer.stop(); +} + +QByteArray DemoBlindDataPoint::moveUpBytes() const +{ + // send a 0 to move up + return DemoDataPoint::BytesOff; +} + +QByteArray DemoBlindDataPoint::moveDownBytes() const +{ + // send a 1 to move down + return DemoDataPoint::BytesOn; +} + +QByteArray DemoBlindDataPoint::stopBytes() const +{ + // send a 1 to stop + return DemoDataPoint::BytesOn; +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.h new file mode 100644 index 0000000..5c465a2 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/demodatapoint.h @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEMODATAPOINT_H +#define DEMODATAPOINT_H + +#include <QtCore/QTimer> +#include <QtGui/QColor> +#include <QtKnx/QKnxTunnelFrame> + +class DemoDataPoint +{ +public: + virtual ~DemoDataPoint() = default; + + virtual QByteArray bytes() const { return QByteArray(); } + virtual bool updateDataPointState(const QKnxTunnelFrame &frame) = 0; + + int position() const { return m_position; } + void setPosition(int pos) { m_position = pos; } + +protected: + int m_position { 0 }; + + static const QByteArray BytesOn; + static const QByteArray BytesOff; +}; + +class DemoSwitchDataPoint : public DemoDataPoint +{ +public: + DemoSwitchDataPoint() = default; + ~DemoSwitchDataPoint() override = default; + + QByteArray bytes() const override; + bool updateDataPointState(const QKnxTunnelFrame &frame) override; + + void uiToggle(); + bool isOn() const; + +private: + bool m_state; +}; + +class DemoColorLed : public QObject, public DemoDataPoint +{ + Q_OBJECT + +public: + DemoColorLed() = default; + ~DemoColorLed() override = default; + + bool updateDataPointState(const QKnxTunnelFrame &frame) override; + + QColor currentColor() const; + void setCurrentColor(QColor color); + + QByteArray redBytes() const; + QByteArray greenBytes() const; + QByteArray blueBytes() const; + + bool isOn() const; + +Q_SIGNALS: + void colorChange(QColor color); + +private: + QColor m_stateColor; + quint8 numMsgConfirmation { 0 }; +}; + +class DemoRockerDataPoint : public QObject, public DemoDataPoint +{ + Q_OBJECT +public: + DemoRockerDataPoint() = default; + virtual ~DemoRockerDataPoint() override = default; + + bool updateDataPointState(const QKnxTunnelFrame &frame) override; + +Q_SIGNALS: + void rockerChange(int position); +}; + +class DemoBlindDataPoint : public QObject, public DemoDataPoint +{ + Q_OBJECT +public: + DemoBlindDataPoint() = default; + ~DemoBlindDataPoint() override = default; + + bool updateDataPointState(const QKnxTunnelFrame &frame) override; + + QByteArray moveUpBytes() const; + QByteArray moveDownBytes() const; + QByteArray stopBytes() const; + +public slots: + void moveBlindUp(); + void moveBlindDown(); + void stopBlind(); + +Q_SIGNALS: + void blindChange(int position); + void blindFullyUp(); + void blindFullyDown(); + +private: + void chooseTimeoutHandle(bool blindUp); + void reenableTimer(); + QTimer m_timer; +}; + +#endif // DEMODATAPOINT_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.cpp new file mode 100644 index 0000000..b963fec --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "etsdevelopmentboard.h" +#include "demodatapoint.h" + +EtsDevelopmentBoard::EtsDevelopmentBoard() +{ + //e1-e6 + quint8 indexMapKey = 1; + for (quint8 i = 1; i < 7 ; ++i) // small white leds + addDevice(indexMapKey++, 0, 0, i, QSharedPointer<DemoSwitchDataPoint>::create()); + //e7-e8 + auto blindDataPoint = QSharedPointer<DemoBlindDataPoint>::create(); + addDevice(7, 1, 0, 0, blindDataPoint); // blind up/down + //skip e8 (because e7 and e8 are the same) + addDevice(8, 1, 0, 0, blindDataPoint); // blind up/down + //indexMapKey++; + //e9 red led + addDevice(9, 0, 0, 7, QSharedPointer<DemoSwitchDataPoint>::create()); + //e10 red led + addDevice(10, 0, 0, 8, QSharedPointer<DemoSwitchDataPoint>::create()); + //e11 red led + addDevice(11, 0, 0, 9, QSharedPointer<DemoSwitchDataPoint>::create()); + //e12 red led + addDevice(12, 0, 0, 10, QSharedPointer<DemoSwitchDataPoint>::create()); + // e13 + auto colorLed = QSharedPointer<DemoColorLed>::create(); + addDevice(13, 0, 0, 12, colorLed); // left Red + addDevice(13, 0, 0, 13, colorLed); // left Green + addDevice(13, 0, 0, 14, colorLed); // left Blue + // e14 + addDevice(14, 0, 0, 11, QSharedPointer<DemoSwitchDataPoint>::create()); // right white + addDevice(15, 2, 0, 0, QSharedPointer<DemoRockerDataPoint>::create()); // Rocker + // e16 turn off blind up/down + addDevice(16, 1, 1, 0, blindDataPoint); +} + +DemoDataPoint *EtsDevelopmentBoard::getGroupObject(int idx) const +{ + return m_dataPoints.value(idx).dpt.data(); +} + +DemoDataPoint *EtsDevelopmentBoard::getGroupObject(const QKnxAddress &address) const +{ + return getGroupObject(getIndex(address)); +} + +int EtsDevelopmentBoard::getIndex(const QKnxAddress &address) const +{ + return m_addressToDataPoints.value(address); +} + +QKnxAddress EtsDevelopmentBoard::getAddress(int idx) const +{ + return m_dataPoints.value(idx).address; +} + +bool EtsDevelopmentBoard::exists(const QKnxAddress &address) const +{ + return m_addressToDataPoints.contains(address); +} + +DemoRockerDataPoint *EtsDevelopmentBoard::getRocker() const +{ + return static_cast<DemoRockerDataPoint *>(getGroupObject(DeviceNumbers::ROCKER)); +} + +DemoBlindDataPoint *EtsDevelopmentBoard::getBlind() const +{ + return static_cast<DemoBlindDataPoint *>(getGroupObject(DeviceNumbers::E7)); +} + +DemoColorLed *EtsDevelopmentBoard::getColorLed() const +{ + return static_cast<DemoColorLed *>(getGroupObject(DeviceNumbers::COLORLED)); +} + +void EtsDevelopmentBoard::addDevice(quint8 key, quint8 mainGroup, quint16 middleGroup, + quint8 subGroup, const QSharedPointer<DemoDataPoint> &dpt) +{ + auto address = QKnxAddress::createGroup(mainGroup, middleGroup, subGroup); + + if (!m_dataPoints.contains(key)) + m_dataPoints.insert(key, { address, dpt }); + + if (!m_addressToDataPoints.contains(address)) + m_addressToDataPoints.insert(address, key); +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.h new file mode 100644 index 0000000..7f6fbaa --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/etsdevelopmentboard.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ETSDEVELOPMENTBOARD_H +#define ETSDEVELOPMENTBOARD_H + +#include "demodatapoint.h" + +#include <QtCore/QHash> +#include <QtCore/QSharedPointer> +#include <QtKnx/QKnxAddress> + +QT_BEGIN_NAMESPACE +inline uint qHash(const QKnxAddress &key, uint seed) +{ + return qHash(key.toString(), seed); +}; +QT_END_NAMESPACE + +class EtsDevelopmentBoard +{ +public: + enum DeviceNumbers + { + E7 = 7, // blind control up + E8 = 8, // blind control down + COLORLED = 13, + MIDDLE_RIGHT = 14, + ROCKER = 15, + E16 = 16, // blind control down + }; + EtsDevelopmentBoard(); + + DemoDataPoint *getGroupObject(int idx) const; + DemoDataPoint *getGroupObject(const QKnxAddress &address) const; + + int getIndex(const QKnxAddress &address) const; + QKnxAddress getAddress(int idx) const; + + bool exists(const QKnxAddress &address) const; + + inline int size() const { return m_dataPoints.size(); }; + + DemoRockerDataPoint *getRocker() const; + DemoBlindDataPoint *getBlind() const; + DemoColorLed *getColorLed() const; + +private: + void addDevice(quint8 key, quint8 mainGroup, quint16 middleGroup, quint8 subGroup, + const QSharedPointer<DemoDataPoint> &dpt); + + struct HashNode { + QKnxAddress address; + QSharedPointer<DemoDataPoint> dpt; + }; + QHash<int, HashNode> m_dataPoints; + QHash<QKnxAddress, int> m_addressToDataPoints; +}; + +#endif diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.cpp new file mode 100644 index 0000000..a768217 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "housemodel.h" + +HouseModel::HouseModel(QObject *parent) : QAbstractListModel(parent) +{ + generateRooms(); +} + +QHash<int, QByteArray> HouseModel::roleNames() const +{ + QHash<int, QByteArray> roles; + roles[NameRole] = "name"; + roles[ItemRole] = "item"; + roles[TemperatureRole] = "temperature"; + roles[LightRole] = "light"; + roles[XPosRole] = "xPos"; + roles[YPosRole] = "yPos"; + + return roles; +} + +QVariant HouseModel::data(const QModelIndex &index, int role) const +{ + if (role == NameRole) + return m_rooms.at(index.row()).getName(); + else if (role == ItemRole) + return m_rooms.at(index.row()).getItem(); + else if (role == TemperatureRole) + return m_rooms.at(index.row()).getTemperature(); + else if (role == LightRole) + return m_rooms.at(index.row()).getLight(); + else if (role == XPosRole) + return m_rooms.at(index.row()).getXPos(); + else if (role == YPosRole) + return m_rooms.at(index.row()).getYPos(); + else return QVariant(); +} + +bool HouseModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (index.isValid()) { + if (role == TemperatureRole) { + m_rooms[index.row()].setTemperature(value.toInt()); + emit dataChanged(index, index); + return true; + } else if (role == LightRole) { + m_rooms[index.row()].setLight(value.toDouble()); + emit dataChanged(index, index); + return true; + } + } + return false; +} + +int HouseModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + return m_rooms.length(); +} + +bool HouseModel::removeRows(int row, int count, const QModelIndex &parent) +{ + Q_UNUSED(row) + Q_UNUSED(count) + Q_UNUSED(parent) + beginResetModel(); + m_rooms.clear(); + endResetModel(); + + return true; +} + +void HouseModel::addRoom(const QString &name, const QString &item, + int temperature, double light, int xPos, int yPos) +{ + int row = m_rooms.size(); + beginInsertRows(QModelIndex(), row, row); + m_rooms.insert(row, Room(name, item, temperature, light, xPos, yPos)); + endInsertRows(); +} + +void HouseModel::generateRooms() +{ + removeRows(0, m_rooms.length()); + // Position of labels is defined from the center point of window + addRoom(QStringLiteral("Living Room"), QStringLiteral("Livingroom"), 21, 0.8, 120, 200); + addRoom(QStringLiteral("Master Bedroom"), QStringLiteral("Masterbedroom"), 18, 0.8, -380, -290); + addRoom(QStringLiteral("Bedroom"), QStringLiteral("Bedroom"), 15, 0.0, -405, 170); + addRoom(QStringLiteral("Bath Room"), QStringLiteral("Bathroom"), 30, 1.0, -20, -320); +#if !defined(KNX_BACKEND) + addRoom(QStringLiteral("Entrance"), QStringLiteral("Entrance"), 20, 0.6, -450, -70); +#endif +} + diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.h new file mode 100644 index 0000000..2ab134b --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/housemodel.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HOUSEMODEL_H +#define HOUSEMODEL_H + +#include <QAbstractListModel> +#include <QUrl> +#include <QRect> + +class Room +{ +public: + Room(const QString &name, const QString &item, + int temperature, double light, int x, int y) + : m_name(name) + , m_item(item) + , m_temperature(temperature) + , m_light(light) + , m_xPos(x) + , m_yPos(y) {} + + QString getName() const { return m_name; } + QString getItem() const { return m_item; } + int getTemperature() const { return m_temperature; } + int getXPos() const { return m_xPos; } + int getYPos() const { return m_yPos; } + void setTemperature(int temperature) { m_temperature = temperature; } + double getLight() const { return m_light; } + void setLight(double light) { m_light = light; } + void setXPos(int x) { m_xPos = x; } + void setYPos(int y) { m_xPos = y; } + +private: + QString m_name; + QString m_item; + int m_temperature; + double m_light; + int m_xPos; + int m_yPos; +}; + +class HouseModel : public QAbstractListModel +{ + Q_OBJECT +public: + enum RoomRoles { + NameRole = 0, + ItemRole, + TemperatureRole, + LightRole, + XPosRole, + YPosRole + }; + + HouseModel(QObject *parent = 0); + virtual QHash<int, QByteArray> roleNames() const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + void addRoom(const QString &name, const QString &item, + int temperature, double light, int xPos, int yPos); + +private: + void generateRooms(); + + QList<Room> m_rooms; +}; + +#endif // HOUSEMODEL_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/images/home-automation-demo.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/images/home-automation-demo.png new file mode 100644 index 0000000..f6de49c --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/images/home-automation-demo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0d9ac8b11e7dc4ed02a3199671477bc9d094be805d454b518a7594534613b41f +size 3526749 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/main.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/main.cpp new file mode 100644 index 0000000..a6239a6 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/main.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/QGuiApplication> +#include <QtCore/QDir> +#include <QtCore/QVector> +#include <QtQuick/QQuickView> +#include <QtQml/QQmlEngine> +#include <QtQml/QQmlContext> +#include <QtGui/QScreen> +#include <QtQml/QQmlPropertyMap> +#include "housemodel.h" +#if defined(KNX_BACKEND) +#include "qmlknxdemo.h" +#endif +#define ALEXA_WEMO +#if defined(ALEXA_WEMO) +#include "qvirtualbelkinwemo.h" +#endif + +// Uncomment for 1280x900 window +//#define FIXEDWINDOW + +int applyFontRatio(const int value, const int ratioFont) +{ + return int(value * ratioFont); +} + +int applyRatio(const int value, const int ratio) +{ + return qMax(2, int(value * ratio)); +} + +void setupWemoToKnx(QmlKnxDemo *m_knxBackend) +{ +#if defined(ALEXA_WEMO) + static quint16 nextPort = 52000; + static QVector<QVirtualBelkinWeMo*> devices; + static QObject parent; + static QVirtualBelkinWeMo livingRoom(nullptr, "Livingroom"); + static QVirtualBelkinWeMo masterbedroom(nullptr, "Master bedroom"); + static QVirtualBelkinWeMo bedroom(nullptr, "Bedroom"); + static QVirtualBelkinWeMo bathroom(nullptr, "Bathroom"); + static QVirtualBelkinWeMo all(nullptr, "all"); + + devices.push_back(&livingRoom); + devices.push_back(&masterbedroom); + devices.push_back(&bedroom); + devices.push_back(&bathroom); + devices.push_back(&all); + + livingRoom.startListening(nextPort++); + masterbedroom.startListening(nextPort++); + bedroom.startListening(nextPort++); + bathroom.startListening(nextPort++); + all.startListening(nextPort++); + + qDebug () << "11111 Connecting services!"; + for (int lightNum = 0; lightNum < devices.size(); ++lightNum) { + if (lightNum == (devices.size()-1)) + { + QObject::connect(dynamic_cast<QUPnPBooleanService*>(devices[lightNum]->getService("")), &QUPnPBooleanService::stateChanged, [m_knxBackend](bool state){ + for (int i = 1; i <= 4; ++i) { + if (m_knxBackend->getLightState(i) != state) + m_knxBackend->toggleLight(i); + } + m_knxBackend->changeRoom(0); + }); + + break; + } + QObject::connect(dynamic_cast<QUPnPBooleanService*>(devices[lightNum]->getService("")), &QUPnPBooleanService::stateChanged, [lightNum, m_knxBackend](bool state){ + if (m_knxBackend->getLightState(lightNum+1) != state) + m_knxBackend->toggleLight(lightNum+1); + m_knxBackend->changeRoom(lightNum+1); + qDebug () << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Switching light! "<< lightNum+1 <<"state "<< (state ? "true":"false") << " light_state:" << m_knxBackend->getLightState(lightNum+1); + }); + QObject::connect(dynamic_cast<QUPnPBooleanService*>(devices[lightNum]->getService("")), &QUPnPBooleanService::stateChangeFailed, [lightNum](){ + qDebug () << ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Switching light FAILEDDD! "<< lightNum+1; + }); + } + +// QUPnPRootDevice rootdev(nullptr, "Qt UPnP to KNX Bridge"); +// QUPnPBooleanService *service = new QUPnPBooleanServiceProxy(&rootdev, dynamic_cast<QUPnPBooleanService*>(devices[0]->getService("")), "SwitchPower"); +// rootdev.addService(service); +// rootdev.startListening(nextPort++); +#else + Q_UNUSED(m_knxBackend) +#endif + return; +} + + +int main(int argc, char *argv[]) +{ +////#if defined(Q_OS_MACOS) +// QSurfaceFormat openGLFormat; +// openGLFormat.setRenderableType(QSurfaceFormat::OpenGL); +// openGLFormat.setProfile(QSurfaceFormat::CoreProfile); +// openGLFormat.setMajorVersion(3); +// openGLFormat.setMinorVersion(0); + +// //openGLFormat.setStencilBufferSize(8); +// QSurfaceFormat::setDefaultFormat(openGLFormat); +////#endif + + QGuiApplication app(argc, argv); + + // Define size variants for scaling + qreal refDpi = 96.; + qreal refWidth = 1280.; + qreal refHeight = 900.; + QRect rect = QGuiApplication::primaryScreen()->geometry(); + qreal width = rect.width(); + qreal height = rect.height(); + qreal dpi = QGuiApplication::primaryScreen()->logicalDotsPerInch(); + qreal widthRatio = width / refWidth; + qreal heightRatio = height / refHeight; + qreal ratioFont = qMin(height * dpi / (refDpi * refHeight), width * dpi / (refDpi * refWidth)); + if (widthRatio < 1.) + widthRatio = 1; + if (heightRatio < 1.) + heightRatio = 1; + if (ratioFont < 1.) + ratioFont = 1; + +#ifdef FIXEDWINDOW + width = refWidth; + height = refHeight; + widthRatio = 1; + heightRatio = 1; + ratioFont = 1; +#endif + + QQmlPropertyMap sizesMap; + sizesMap.insert(QStringLiteral("screenHeight"), QVariant(height)); + sizesMap.insert(QStringLiteral("screenWidth"), QVariant(width)); + sizesMap.insert(QStringLiteral("fontSize"), QVariant(applyFontRatio(26, ratioFont))); + sizesMap.insert(QStringLiteral("controlHeight"), QVariant(applyFontRatio(64, ratioFont))); + sizesMap.insert(QStringLiteral("labelMouseMargin"), QVariant(applyRatio(20, widthRatio))); + sizesMap.insert(QStringLiteral("controlMargin"), QVariant(applyRatio(20, widthRatio))); + sizesMap.insert(QStringLiteral("controlBorderWidth"), QVariant(applyRatio(3, widthRatio))); + sizesMap.insert(QStringLiteral("sliderMaxWidth"), QVariant(applyRatio(300, widthRatio))); + + QQuickView viewer; + + viewer.engine()->addImportPath(QStringLiteral(":/qml/imports")); + +#ifndef Q_OS_ANDROID + // Hack to get self build working. + // Also needs the Qt3DStudio\bin directory in run environment path. + viewer.engine()->addImportPath(QStringLiteral("C:/Qt/Tools/Qt3DStudio/qml")); +#endif + +#if defined(KNX_BACKEND) + qmlRegisterUncreatableType<QmlKnxDemo>("QmlKnxDemo", 1, 0, "QmlKnxDemo", "Not instantiated from QML"); + QmlKnxDemo *m_knxBackend = new QmlKnxDemo; + viewer.engine()->rootContext()->setContextProperty(QStringLiteral("knxBackend"), m_knxBackend); + setupWemoToKnx(m_knxBackend); +#else + viewer.engine()->rootContext()->setContextProperty(QStringLiteral("knxBackend"), nullptr); +#endif + + HouseModel *m_houseModel = new HouseModel; + viewer.engine()->rootContext()->setContextProperty(QStringLiteral("houseModel"), m_houseModel); + + viewer.engine()->rootContext()->setContextProperty(QStringLiteral("sizesMap"), &sizesMap); + viewer.engine()->rootContext()->setContextProperty(QStringLiteral("heightRatio"), heightRatio); + + viewer.setSource(QUrl(QStringLiteral("qrc:/main.qml"))); + + viewer.setTitle(QStringLiteral("Qt 3D Studio Home Automation Demo")); + viewer.setResizeMode(QQuickView::SizeViewToRootObject); +#ifdef FIXEDWINDOW + viewer.setMinimumSize(QSize(width, height)); + viewer.setMaximumSize(QSize(width, height)); + viewer.show(); +#else + viewer.showFullScreen(); +#endif + + return app.exec(); +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.cpp new file mode 100644 index 0000000..629c8c7 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qalexatoknx.h" +#include "mainwindow.h" + +QAlexaToKnx::QAlexaToKnx(MainWindow *target, QString name) + : QUPnPBooleanService(target) +{ + this->m_target = target; + this->identifier = name; +} + +bool QAlexaToKnx::doSetState(bool state) +{ + m_target->append(identifier + " changed state to " + (state?"TRUE":"FALSE")); + return true; +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.h new file mode 100644 index 0000000..2b3c9d1 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qalexatoknx.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QALEXATOKNX_H +#define QALEXATOKNX_H + +#include "qupnpservice.h" + +class MainWindow; + +class QAlexaToKnx : public QUPnPBooleanService //QVirtualBelkinWeMo +{ + Q_OBJECT + MainWindow *m_target; +public: + QAlexaToKnx(MainWindow *target, QString name); +protected: + bool doSetState(bool state) override; +}; + +#endif // QALEXATOKNX_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.cpp new file mode 100644 index 0000000..bef2161 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qminimalhttpserver.h" + +QMinimalHttpServer::QMinimalHttpServer(QObject *parent) + : QObject(parent) +{ + connect(&tcpServer, &QTcpServer::newConnection, this, &QMinimalHttpServer::onNewTcpConnection); +} + +QMinimalHttpServer::~QMinimalHttpServer() +{ +} + +void QMinimalHttpServer::addFile(QString filename, QByteArray &data, QString mimetype) +{ + filename = filename.toUpper(); // ensure case insensitivity + if (!filename.startsWith("/")) + filename = QStringLiteral("/") + filename; + + httpFiles[filename] = data; + if (mimetype == "") { + QMimeDatabase db; + QList<QMimeType> types = db.mimeTypesForFileName(filename); + if (types.size() > 0) + mimetype = types[0].name(); + } + httpFileMimeTypes[filename] = mimetype; +} + +void QMinimalHttpServer::onNewTcpConnection() +{ + for (QTcpSocket* socket = tcpServer.nextPendingConnection(); socket; socket = tcpServer.nextPendingConnection()) { + #ifdef QT_DEBUG + qDebug() << "QMinimalHttpServer::connected " << socket->peerAddress().toString() << ":" << socket->peerPort(); + #endif + + connect(socket, &QTcpSocket::readyRead, [this, socket](){ + this->onTcpDataReceived(socket); + }); + connect(socket, &QTcpSocket::disconnected, [this, socket](){ + #ifdef QT_DEBUG + qDebug() << "QMinimalHttpServer::disconnected " << socket->peerAddress().toString() << ":" << socket->peerPort(); + #endif + //emit this->disconnected(socket); + }); + } +} + +void QMinimalHttpServer::onTcpDataReceived(QTcpSocket *socket) +{ + QByteArray data = socket->readAll(); + #ifdef QT_DEBUG + qDebug() << "QMinimalHttpServer::onTcpDataReceived " << data; + #endif + this->processTcpData(data, socket); +} + +void QMinimalHttpServer::processTcpData(const QByteArray &data, QTcpSocket *socket) +{ + QStringList lines = QString::fromUtf8(data).split("\r\n"); + QStringList request = lines[0].split(" ", QString::SkipEmptyParts); + QString responseHead = QStringLiteral("HTTP/1.1 200 OK\r\n"); + QByteArray responseBody; + int status = 200; + + QString filename = request[1].toUpper(); + if (!filename.startsWith("/")) + filename = QStringLiteral("/") + filename; + filename = filename.replace("%20", " "); + + if (request[0].toUpper() == "GET") { + if (httpFiles.contains(filename)) { + responseBody = httpFiles[filename]; + responseHead += QStringLiteral("content-type: ") + httpFileMimeTypes[filename] + "\r\n"; + } else if (this->processHttpGetRequest(filename, responseHead, responseBody)) { + // in this case, everything must be done inside processGetRequest + } else { + responseHead = "HTTP/1.0 404 Not Found\r\n"; + status = 404; + } + + } else if (request[0].toUpper() == "POST") { + + // find and validate "Content-Length:" header + int contentLength = -1; + int i = 0; + for (; i < lines.size(); i++) { + if (lines[i].startsWith("Content-Length:", Qt::CaseInsensitive)) + contentLength = lines[i].mid(15).trimmed().toInt(); + if (lines[i].trimmed()=="") + break; + } + if (contentLength < 0) { + responseHead = "HTTP/1.0 411 Length Required\r\n"; + status = 411; + } else if (contentLength > maxPostRequestContentLength) { + responseHead = "HTTP/1.0 413 Payload Too Large\r\n"; + status = 413; + } + + // get the requests body + int postBodyOffset = -1; + for (int i = 0; postBodyOffset < 0 && i < data.size()-4; i++) + if (data[i] == '\r' && data[i+1] == '\n' && data[i+2] == '\r' && data[i+3] == '\n') + postBodyOffset = i+4; + QByteArray postBody; + if (0 <= postBodyOffset && postBodyOffset < data.size()) + postBody = data.mid(postBodyOffset); + + // multi-part message, wait for more packets + while (status == 200 && postBody.size() < contentLength) { + if (socket->waitForReadyRead(2000)) { + QByteArray moreData = socket->readAll(); + #ifdef QT_DEBUG + qDebug() << "QMinimalHttpServer::processTcpData MORE DATA:" << moreData; + #endif + postBody.append(moreData); + } else { + responseHead = "HTTP/1.0 408 Request Timeout\r\n"; + status = 408; + } + } + + // call the handler + if (status == 200) + status = this->processHttpPostRequest(filename, postBody, responseHead, responseBody); + + } else if (request[0].toUpper() == "SUBSCRIBE") { + this->processHttpSubscribeRequest(filename, lines, responseHead, responseBody); + } else if (request[0].toUpper() == "UNSUBSCRIBE") { + this->processHttpUnsubscribeRequest(filename, lines, responseHead, responseBody); + } + + + responseHead += QStringLiteral( + "content-length: ") + QString::number(responseBody.size()) + "\r\n" + "last-modified: Tue, 23 Jan 2018 15:54:00 GMT\r\n" + "date: " + DateRfc7231() + "\r\n" + "connection: close\r\n"; + + #ifdef QT_DEBUG + qDebug() << "QMinimalHttpServer::processTcpData" << responseHead << responseBody; + #endif + + socket->write((responseHead+"\r\n").toUtf8()); + socket->write(responseBody); +} + +/***************************************************************************\ + * Overrides of this method may add headers and set the responseBody. * + * returning true means that the request has successfully been processed * + * returning false means that the (overridden) method could not deliver * + * a response, so then a 404 will be sent. * +\***************************************************************************/ +bool QMinimalHttpServer::processHttpGetRequest(QString urlUpper, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(urlUpper); + Q_UNUSED(responseHead); + Q_UNUSED(responseBody); + return false; +} + +/***************************************************************************\ + * Overrides of this method may add headers and set the responseBody. * + * return value should be an HTTP status code corresponding to the * + * status that is set in the responseHead. * + * Since the method is only invoked if the status was 200 before, * + * returning 200 is valid in cases where responseHead is not changed * +\***************************************************************************/ +int QMinimalHttpServer::processHttpPostRequest(QString urlUpper, QByteArray &postBody, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(urlUpper); + Q_UNUSED(postBody); + Q_UNUSED(responseBody); + responseHead = "HTTP/1.0 403 Forbidden\r\n"; + return 403; +} + +int QMinimalHttpServer::processHttpSubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(urlUpper); + Q_UNUSED(requestLines); + Q_UNUSED(responseBody); + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; +} + +int QMinimalHttpServer::processHttpUnsubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(urlUpper); + Q_UNUSED(requestLines); + Q_UNUSED(responseBody); + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; +} + + + +void QMinimalHttpServer::startListening(quint16 port) +{ + if (isListening()) + return; + tcpServer.listen(QHostAddress::Any, port); +} + +void QMinimalHttpServer::stopListening() +{ + if (!isListening()) + return; + tcpServer.close(); +} + +bool QMinimalHttpServer::isListening() +{ + return tcpServer.isListening(); +} + +QString QMinimalHttpServer::DateRfc7231(const QDateTime &date) +{ + static const QString daysEn[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + static const QString monthsEn[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + QString sDate = daysEn[ date.date().dayOfWeek() - 1 ] + + date.toString(", dd ") + + monthsEn[ date.date().month() - 1 ] + + date.toString(" yyyy HH:mm::ss") + + " GMT"; + return std::move(sDate); +} +QString QMinimalHttpServer::DateRfc7231() +{ + return std::move(DateRfc7231(QDateTime::currentDateTimeUtc())); +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.h new file mode 100644 index 0000000..5b573e9 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qminimalhttpserver.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMINIMALHTTPSERVER_H +#define QMINIMALHTTPSERVER_H + +#include <QObject> +#include <QMap> +#include <QDateTime> +#include <QMimeDatabase> +#include <QTcpServer> +#include <QTcpSocket> + +class QMinimalHttpServer : public QObject +{ + Q_OBJECT +protected: + QTcpServer tcpServer; + QMap<QString, QByteArray> httpFiles; + QMap<QString, QString> httpFileMimeTypes; + int maxPostRequestContentLength = INT_MAX; + + void onNewTcpConnection(); + void onTcpDataReceived(QTcpSocket *socket); + virtual void processTcpData(const QByteArray &data, QTcpSocket *socket); + virtual bool processHttpGetRequest(QString urlUpper, QString &responseHead, QByteArray &responseBody); + virtual int processHttpPostRequest(QString urlUpper, QByteArray &postBody, QString &responseHead, QByteArray &responseBody); + virtual int processHttpSubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody); + virtual int processHttpUnsubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody); + + static QString DateRfc7231(const QDateTime &date); + static QString DateRfc7231(); + +public: + explicit QMinimalHttpServer(QObject *parent = nullptr); + virtual ~QMinimalHttpServer(); + Q_DISABLE_COPY(QMinimalHttpServer) + + void addFile(QString filename, QByteArray &data, QString mimetype = QString()); + void startListening(quint16 port = 0); + void stopListening(); + bool isListening(); +}; + +#endif // QMINIMALHTTPSERVER_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/HomeView.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/HomeView.qml new file mode 100644 index 0000000..2dd9dd7 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/HomeView.qml @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.3 +import QtStudio3D 1.0 + +Item { + id: home + + property real red: 0 + property real blue: 255 + property real green: 0 + property real light: 0 + + property string currentTempAttribute: "" + property string currentLightAttribute: "" + + Timer { + id: goToHomeTimer + interval: 30000 + running: false + repeat: false + + onTriggered: presentation.goToSlide("Scene", "BackToInitialView") + } + + Timer { + id: showMenuTimer + interval: 1000 + running: false + repeat: false + + onTriggered: mainMenu.visible = true + } + + signal studio3DPresentationReady() + + function getRoomName(index) { + var name; + if (index === 0) + name = "BackToInitialView" + else if (index === 1) + name = "Livingroom" + else if (index === 2) + name = "Masterbedroom" + else if (index === 3) + name = "Bedroom" + else if (index === 4) + name = "Bathroom" + return name + } + + // + // Qt 3D Studio presentation + // + Studio3D { + anchors.fill: parent + + ViewerSettings { + scaleMode: ViewerSettings.ScaleModeFill + } + + Presentation { + id: presentation + source: "qrc:/uip/houseStudio.uip" + + SceneElement { + id: scene + elementPath: "Scene" + onCurrentSlideNameChanged: { + var lightNum = 0 + var startTimer = false; + if (currentSlideName === "Livingroom") { + currentTempAttribute = "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_LivingRoom.HeatAreas_Heat_LivingRoom.Heat_LivingRoomSG" + currentLightAttribute = "Scene.3D.RoomLights.LivingroomLightMap.House" + livingRoomHeat.goToTime(2) + masterBedroomHeat.goToTime(0) + bedroomHeat.goToTime(0) + bathRoomHeat.goToTime(0) + entranceHeat.goToTime(0) + sliderToolbar.visible = true + lightNum = 1 + } else if (currentSlideName === "Masterbedroom") { + currentTempAttribute = "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_MasterBedroom.HeatAreas_Heat_MasterBedroom.Heat_MasterBedroomSG" + currentLightAttribute = "Scene.3D.RoomLights.MasterbedroomLightmap.House" + livingRoomHeat.goToTime(0) + masterBedroomHeat.goToTime(2) + bedroomHeat.goToTime(0) + bathRoomHeat.goToTime(0) + entranceHeat.goToTime(0) + sliderToolbar.visible = true + lightNum = 2 + } else if (currentSlideName === "Bedroom") { + currentTempAttribute = "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_BedRoom.HeatAreas_Heat_BedRoom.Heat_BedRoomSG" + currentLightAttribute = "Scene.3D.RoomLights.BedroomLightmap.House" + livingRoomHeat.goToTime(0) + masterBedroomHeat.goToTime(0) + bedroomHeat.goToTime(2) + bathRoomHeat.goToTime(0) + entranceHeat.goToTime(0) + sliderToolbar.visible = true + lightNum = 3 + } else if (currentSlideName === "Bathroom") { + currentTempAttribute = "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_BathRoom.HeatAreas_Heat_BathRoom.Heat_BathRoomSG" + currentLightAttribute = "Scene.3D.RoomLights.BathroomLightmap.House" + livingRoomHeat.goToTime(0) + masterBedroomHeat.goToTime(0) + bedroomHeat.goToTime(0) + bathRoomHeat.goToTime(2) + entranceHeat.goToTime(0) + sliderToolbar.visible = true + lightNum = 4 + } else if (currentSlideName === "Entrance") { + currentTempAttribute = "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_Entrance.Heat_Entrance_HeatAreas.Heat_EntranceSG" + currentLightAttribute = "Scene.3D.RoomLights.EntranceLightmap.House" + livingRoomHeat.goToTime(0) + masterBedroomHeat.goToTime(0) + bedroomHeat.goToTime(0) + bathRoomHeat.goToTime(0) + entranceHeat.goToTime(2) + sliderToolbar.visible = true + } else if (currentSlideName === "FloorPlan") { + livingRoomHeat.goToTime(0) + masterBedroomHeat.goToTime(0) + bedroomHeat.goToTime(0) + bathRoomHeat.goToTime(0) + entranceHeat.goToTime(0) + startTimer = true; + sliderToolbar.visible = false + } else { + sliderToolbar.visible = false + } + + if (currentSlideName === "FloorPlan") { + if (previousSlideName === "InitialView") + mainMenu.visible = true + else + showMenuTimer.start() + } else { + if (showMenuTimer.running) + showMenuTimer.stop() + mainMenu.visible = false + } + + if (startTimer) + goToHomeTimer.start() + else if (goToHomeTimer.running) + goToHomeTimer.stop() + + presentation.setAttribute(currentTempAttribute, "diffuse.r", red) + presentation.setAttribute(currentTempAttribute, "diffuse.g", green) + presentation.setAttribute(currentTempAttribute, "diffuse.b", blue) + presentation.setAttribute(currentLightAttribute, "opacity", light) + + if (knxBackend) { + lightControlLoader.item.lightNum = lightNum + lightControlLoader.item.updateLight(knxBackend.getLightState(lightNum)) + tempSlider.setPositionByColor(knxBackend.getColor()) + console.log("<<<<<<<<<<<<<<<<<<<1") + } + } + } + + SceneElement { + id: livingRoomHeat + elementPath: "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_LivingRoom" + } + SceneElement { + id: masterBedroomHeat + elementPath: "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_MasterBedroom" + } + SceneElement { + id: bedroomHeat + elementPath: "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_BedRoom" + } + SceneElement { + id: bathRoomHeat + elementPath: "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_BathRoom" + } + SceneElement { + id: entranceHeat + elementPath: "Scene.3D.HeatAreas.Group_HeatAreas.HeatAreas_Heat_Entrance" + } + } + + // Once https://bugreports.qt.io/browse/QT3DS-414 is solved uncomment the following lines. +// onPresentationReady: { +// if (presentationReady) +// home.studio3DPresentationReady() +// } + + } + + Connections { + target: knxBackend + onRoomChanged: presentation.goToSlide("Scene", getRoomName(roomId)) + onBoardUpdate: { + console.log("signal onBoardUpdate lightNum: " + lightNum) + if (lightNum > 0 + && lightNum < 5 + && lightControlLoader.item.lightNum == lightNum + && knxBackend.getLightState(lightNum) != lightControlLoader.item.checked) { + var oldValue = houseModel.data(houseModel.index(lightNum - 1, 0), 3) + houseModel.setData(houseModel.index(lightNum - 1, 0), !oldValue, 3) + lightControlLoader.item.value = houseModel.data(houseModel.index(lightNum - 1, 0), 3) + lightControlLoader.item.updateLight(knxBackend.getLightState(lightNum)) + console.log("lightControlLoader: " + lightControlLoader.item.value) + } + } + onColorLedChange: { + var sliderColor = Qt.rgba(tempSlider.redColor, tempSlider.greenColor, tempSlider.blueColor, 1) + if (!Qt.colorEqual(sliderColor, color)) + tempSlider.setPositionByColor(color) + } +// knxBoard.changeColorLeftLed(color) +// onRockerChange: { +// logo.rotation = (position - 1000) * 360 / 1000; +// } + } + + MouseArea { + id: mouseArea + property bool disableMouseEvents: false + anchors.fill: parent + onClicked: { + if (!disableMouseEvents) { + if (scene.currentSlideName === "BackToInitialView") { + presentation.goToSlide("Scene", "InitialView") + disableMouse(2200) + } else if (scene.currentSlideName === "FloorPlan") { + presentation.goToSlide("Scene", "BackToInitialView") + disableMouse(2100) + } else if (scene.currentSlideName !== "InitialView") { + presentation.goToSlide("Scene", "FloorPlan") + disableMouse(1000) + } + } + } + + function disableMouse(animationDuration) { + disableMouseEvents = true + mouseTimer.interval = animationDuration + mouseTimer.start() + } + + Timer { + id: mouseTimer + interval: 1000 + running: false + repeat: false + + onTriggered: mouseArea.disableMouseEvents = false + } + } + + // + // Room label items + // + MainMenu { + id: mainMenu + + property int currentIndex: -1 + + visible: false + anchors.fill: parent + + onCurrentMenuItemChanged: { + presentation.goToSlide("Scene", currentItem) + + // Store temperature and light to model before changing the slider value + if (currentIndex != -1) { + houseModel.setData(houseModel.index(currentIndex, 0), tempSlider.currentValue, 2) + houseModel.setData(houseModel.index(currentIndex, 0), lightControlLoader.item.currentValue, 3) + } + currentIndex = index + var temp = houseModel.data(houseModel.index(index, 0), 2) + tempSlider.value = (temp - 15) / 15 + lightControlLoader.item.value = houseModel.data(houseModel.index(index, 0), 3) + } + } + + // + // Toolbar for Sliders + // + Item { + id: sliderToolbar + anchors.bottom: parent.bottom + height: tempSlider.height + anchors.horizontalCenter: parent.horizontalCenter + width: lightControlLoader.width + sizesMap.controlMargin + tempSlider.width + + visible: false + + Loader { + id: lightControlLoader + source: knxBackend ? "LightSwitch.qml" : "LightSlider.qml" + asynchronous: true + anchors.bottom: parent.bottom + anchors.bottomMargin: sizesMap.controlMargin + anchors.left: parent.left + width: knxBackend ? (sizesMap.controlHeight * 2) : (mainMenu.width / 3) + } + + Connections { + target: lightControlLoader.item + onLightValueChanged: { + var newLightValue = lightControlLoader.item.lightValue * 100 + home.light = newLightValue + presentation.setAttribute(currentLightAttribute, "opacity", newLightValue) + + } + } + + TempSlider { + id: tempSlider + anchors.bottom: parent.bottom + anchors.bottomMargin: sizesMap.controlMargin + anchors.right: parent.right + width: mainMenu.width / 3 + + onRedColorChanged: { + home.red = redColor + presentation.setAttribute(currentTempAttribute, "diffuse.r", redColor) + } + onBlueColorChanged: { + home.blue = blueColor + presentation.setAttribute(currentTempAttribute, "diffuse.b", blueColor) + } + + onGreenColorChanged: { + home.green = greenColor + presentation.setAttribute(currentTempAttribute, "diffuse.g", greenColor) + } + + onEconomyChanged: { + if (knxBackend) { + // Toggle red light based on temperature changes + // The initial state of red lights on the board needs to be based on the default temperatures + var lightNum = 0 + if (scene.currentSlideName === "Livingroom") + lightNum = 9 + else if (scene.currentSlideName === "Masterbedroom") + lightNum = 10 + else if (scene.currentSlideName === "Bedroom") + lightNum = 11 + else if (scene.currentSlideName === "Bathroom") + lightNum = 12 + //knxBackend.toggleLight(lightNum) + } + } + } + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSlider.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSlider.qml new file mode 100644 index 0000000..8f00abd --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSlider.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +SliderControl { + id: lightSlider + + property real lightValue: lightSlider.position + + sliderColor: "black" + currentValue: lightValue.toFixed(1) + + text: currentValue * 100 + "%" + iconSource: "qml/images/icon_light.png" + + onPositionChanged: { + setNewLightColor() + } + + function setNewLightColor() { + // From black to white + var newColorValue = lightSlider.position * 255 + sliderColor = rgbToHex(newColorValue, newColorValue, newColorValue) + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSwitch.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSwitch.qml new file mode 100644 index 0000000..86fe602 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/LightSwitch.qml @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.3 +import Style 1.0 + +Item { + id: lightSwitch + property real value: control.checked ? 1.0 : 0.0 + property real lightValue: control.position + property real currentValue: lightValue.toFixed(1) + property real lightNum: 0 + + width: sizesMap.controlHeight * 2 + height: sizesMap.controlHeight + sliderText.height + function updateLight(state) { + control.checked = state + } + + Text { + id: sliderText + anchors.bottom: control.top + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: sizesMap.fontSize + color: Style.textColor + font.bold: true + style: Text.Outline + styleColor: Style.sliderBackgroundColor + } + + Switch { + id: control + width: lightSwitch.width + height: sizesMap.controlHeight + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: sizesMap.controlMargin / 2 + onClicked: { + console.log('Clicked on ligth!'+ lightNum) + knxBackend.toggleLight(lightNum) + } + indicator: Rectangle { + implicitWidth: sizesMap.controlHeight * 2 + implicitHeight: sizesMap.controlHeight + x: control.leftPadding + y: control.topPadding + control.availableHeight / 2 - height / 2 + radius: height / 2 + color: control.checked ? Style.sliderSelectionColor : Style.sliderBackgroundColor + border.color: Style.backgroundColor + border.width: sizesMap.controlBorderWidth + opacity: control.enabled ? 1 : 0.3 + + Rectangle { + x: control.checked ? parent.width - width : 0 + width: sizesMap.controlHeight + height: sizesMap.controlHeight + radius: height / 2 + antialiasing: true + color: Style.backgroundColor + opacity: control.enabled ? 1 : 0.3 + Image { + id: handleItemIcon + anchors.fill: parent + fillMode: Image.PreserveAspectFit + anchors.margins: sizesMap.controlMargin / 2 + anchors.centerIn: parent + source: "qml/images/icon_light.png" + } + } + } + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/MainMenu.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/MainMenu.qml new file mode 100644 index 0000000..dcbb281 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/MainMenu.qml @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Style 1.0 + +Item { + id: menuItem + property int horizontalScreenCenter: main.width / 2 + property int verticalScreenCenter: main.height / 2 + + signal currentMenuItemChanged(int index, string currentItem) + + Repeater { + id: mainListView + model: houseModel + delegate: listElement + } + + // Delegate for items in list view + Component { + id: listElement + + RoomLabel { + // Position is defined in the model relative to the center of the screen. + // Scale the label position here. + x: menuItem.horizontalScreenCenter + (heightRatio * xPos) - sizesMap.labelMouseMargin + y: menuItem.verticalScreenCenter + (heightRatio * yPos) - sizesMap.labelMouseMargin + text: name + onRoomLabelClicked: currentMenuItemChanged(index, item) + } + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/RoomLabel.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/RoomLabel.qml new file mode 100644 index 0000000..f948917 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/RoomLabel.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Style 1.0 + +Item { + id: roomLabel + + // Provide bigger mouse area for label than the visual label is + + property alias text: roomText.text + + signal roomLabelClicked + + height: sizesMap.controlHeight + width: labelRect.width + sizesMap.labelMouseMargin * 2 + + Rectangle { + id: labelRect + width: roomText.width + sizesMap.controlMargin * 2 + height: roomText.height + sizesMap.controlMargin + anchors.centerIn: parent + color: Style.sliderBackgroundColor + radius: width / 2 + border.color: Style.backgroundColor + border.width: sizesMap.controlBorderWidth + + Text { + id: roomText + anchors.centerIn: parent + font.pixelSize: sizesMap.fontSize + color: Style.textColor + } + } + + MouseArea { + anchors.fill: parent + onClicked: roomLabelClicked() + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SliderControl.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SliderControl.qml new file mode 100644 index 0000000..14c6f5d --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SliderControl.qml @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 2.1 +import Style 1.0 + +Item { + id: sliderControl + signal moved(real position) + + property alias position: control.position + property alias value: control.value + property alias text: sliderText.text + property alias iconSource: handleItemIcon.source + + property color sliderColor + property real currentValue: 0 + + width: sizesMap.sliderMaxWidth + height: sizesMap.controlHeight + sliderText.height + + Text { + id: sliderText + anchors.bottom: control.top + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: sizesMap.fontSize + color: Style.textColor + font.bold: true + style: Text.Outline + styleColor: Style.sliderBackgroundColor + } + + Slider { + id: control + + width: sliderControl.width + height: sizesMap.controlHeight + + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.margins: sizesMap.controlMargin / 2 + + onMoved: parent.moved(position) + + background: Rectangle { + x: control.leftPadding + y: control.topPadding + control.availableHeight / 2 - height / 2 + implicitWidth: sizesMap.sliderMaxWidth + implicitHeight: sizesMap.controlHeight + width: control.availableWidth + height: implicitHeight + color: Style.sliderBackgroundColor + radius: height / 2 + border.color: Style.backgroundColor + border.width: sizesMap.controlBorderWidth + opacity: control.enabled ? 1 : 0.3 + + Rectangle { + width: handleItem.x + handleItem.width - 5 + height: parent.height + color: Style.sliderSelectionColor + border.color: Style.backgroundColor + border.width: sizesMap.controlBorderWidth + radius: height / 2 + } + } + + handle: Rectangle { + id: handleItem + x: control.leftPadding + control.visualPosition * (control.availableWidth - width) + y: control.topPadding + control.availableHeight / 2 - height / 2 + implicitWidth: sizesMap.controlHeight + implicitHeight: sizesMap.controlHeight + radius: height / 2 + antialiasing: true + color: Style.backgroundColor + opacity: control.enabled ? 1 : 0.3 + Image { + id: handleItemIcon + anchors.fill: parent + fillMode: Image.PreserveAspectFit + anchors.margins: sizesMap.controlMargin / 2 + anchors.centerIn: parent + + } + } + } + + function rgbToHex(red, green, blue) { + // Based on http://www.javascripter.net/faq/rgbtohex.htm + return "#" + toHex(red) + toHex(green) + toHex(blue) + } + + function toHex(n) { + if (isNaN(n)) + return "00" + n = Math.max(0, Math.min(n, 255)) + return "0123456789ABCDEF".charAt((n - n % 16) / 16) + + "0123456789ABCDEF".charAt(n % 16) + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SplashScreen.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SplashScreen.qml new file mode 100644 index 0000000..94df270 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/SplashScreen.qml @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Style 1.0 + +Rectangle { + anchors.fill: parent + color: Style.backgroundColor + + Image { + anchors.centerIn: parent + source: "qrc:/qml/images/QtSymbol.png" + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/TempSlider.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/TempSlider.qml new file mode 100644 index 0000000..8220669 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/TempSlider.qml @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 + +SliderControl { + id: tempSlider + property real redColor + property real blueColor + property real greenColor + property bool economy: currentValue < 22 ? true : false + + currentValue: 15 + sliderColor: "#0000ff" + + text: currentValue + "°" + iconSource: "qml/images/icon_temp.png" + + onPositionChanged: { + updateCurrentTemp() + setNewTempColor() + } + + onMoved: { + var position = 0.6; + if (currentValue > 17 && currentValue < 26) + position = 0.45; + else if (currentValue >= 26) + position = 0.30; + knxBackend.colorSwitch(position) + console.log('moved color slider!'+ position) + } + + function setPositionByColor(color) + { + if (Qt.colorEqual(color, "magenta")) { + value = 0.5 + } + else if (Qt.colorEqual(color, "red")) { + value = 1 + } + else if (Qt.colorEqual(color, "blue")) { + value = 0 + } + } + + function updateCurrentTemp() { + // Temperature range from 15 to 30 + // Slider range form 0 to 1 + var newTempValue = 15 + 15 * tempSlider.position + tempSlider.currentValue = newTempValue.toFixed(0) + } + + function setNewTempColor() { + var position = tempSlider.position * 100 + // From blue to red + var r = Math.floor((255 * Math.sqrt(Math.sin(position * Math.PI / 200)))) + var b = Math.floor((255 * Math.sqrt(Math.cos(position * Math.PI / 200)))) + var g = 0 + redColor = r / 255 + blueColor = b / 255 + greenColor = 0 + sliderColor = rgbToHex(r, g, b) + + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/main.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/main.qml new file mode 100644 index 0000000..ca42332 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/HomeAutom/main.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.8 +import Style 1.0 + +// Main Item +Item { + id: main + width: sizesMap.screenWidth + height: sizesMap.screenHeight + + // onPresentationReady() signal should be restored to 3D studio code so that we can hide + // the splashscreen without a timer, https://bugreports.qt.io/browse/QT3DS-414 + Timer { + id: showSplashScreenTimer + interval: 1000 + running: false + repeat: false + + onTriggered: hideSplashScreen() + } + + Loader { + id: appLoader + anchors.fill: parent + visible: false +// asynchronous: true // https://bugreports.qt.io/browse/QTBUG-50992 + } + + Connections { + target: appLoader.item + onStudio3DPresentationReady: hideSplashScreen() + } + + Timer { + interval: 5000 + running: true + repeat: true + onTriggered: knxBackend.reconnect() + } + + SplashScreen { + id: splashScreenLoader + visible: true + anchors.fill: parent + Component.onCompleted: { + appLoader.setSource("HomeView.qml") + showSplashScreenTimer.start() + } + } + + function hideSplashScreen() { + if (appLoader.status === Loader.Ready) { + splashScreenLoader.visible = false + appLoader.visible = true + } + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/QtSymbol.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/QtSymbol.png new file mode 100644 index 0000000..3c867cd --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/QtSymbol.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc885612c701d0b610bebe156dcb4b9d819a1ad6681465a53392705fed2b9d90 +size 4541 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_light.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_light.png new file mode 100644 index 0000000..2b35771 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_light.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:00eec2e449fdc77fb81df23a8959bb83804ebd366f313014a36eb0bb81e5a740 +size 1210 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_temp.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_temp.png new file mode 100644 index 0000000..a82320b --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/images/icon_temp.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32584803b4e6fdfb4000954d88056b81f25ae849afdc64f112124ddd95243252 +size 1207 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/Style.qml b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/Style.qml new file mode 100644 index 0000000..451d231 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/Style.qml @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +pragma Singleton + +import QtQuick 2.8 + +QtObject { + + // Theme colors to be used through out whole system + readonly property color backgroundColor: "white" + readonly property color textColor: "white" + readonly property color sliderToolbarTextColor: "white" + readonly property color sliderToolbarRaisedTextColor: "black" + readonly property color menuBackgroundColor: "gray" + readonly property color menuSelectedItemColor: "#80bfff" + readonly property color sliderBackgroundColor: "#595959" + readonly property color sliderSelectionColor: "#a6a6a6" + + readonly property int visibilityAnimatorDuration: 500 +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/qmldir b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/qmldir new file mode 100644 index 0000000..858dcaf --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qml/imports/Style/qmldir @@ -0,0 +1,2 @@ +module Style +singleton Style 1.0 Style.qml diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.cpp new file mode 100644 index 0000000..b6e3d50 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "demodatapoint.h" +#include "qmlknxdemo.h" +#include "utils.h" + +#include <QtCore/QString> +#include <QtGui/QColor> +#include <QtKnx/QKnxAddress> +#include <QtNetwork/QNetworkAddressEntry> +#include <QtNetwork/QNetworkInterface> + +namespace { + const double sliderSectionSize = 1 / 7.0; + using DeviceNumbers = EtsDevelopmentBoard::DeviceNumbers; +} + +QmlKnxDemo::QmlKnxDemo() + : m_tunnel(this) +{ + checkLightStatusOn(); + + if (auto blind = m_etsBoard.getBlind()) { + connect(blind, &DemoBlindDataPoint::blindChange, this, &QmlKnxDemo::blindPositionChange); + connect(blind, &DemoBlindDataPoint::blindFullyUp, this, &QmlKnxDemo::blindFullyUp); + connect(blind, &DemoBlindDataPoint::blindFullyDown, this, &QmlKnxDemo::blindFullyDown); + } + + if (auto rocker = m_etsBoard.getRocker()) + connect(rocker, &DemoRockerDataPoint::rockerChange, this, &QmlKnxDemo::rockerChange); + + if (auto colorLed = m_etsBoard.getColorLed()) + connect(colorLed, &DemoColorLed::colorChange, this, &QmlKnxDemo::colorLedChange); +} + +void QmlKnxDemo::toggleLight(int light) +{ + if (auto dpt = static_cast<DemoSwitchDataPoint *>(m_etsBoard.getGroupObject(light))) { + dpt->uiToggle(); + sendGroupValueWrite(m_tunnel, m_etsBoard.getAddress(light), dpt->bytes()); + } +} + +void QmlKnxDemo::colorSwitch(double value) +{ + QColor colorAtStart = colorState; + if (value < (sliderSectionSize / 2) + && colorState != Qt::black) + colorState = Qt::black; + + else if ((value > (sliderSectionSize / 2)) + && value < (3 * sliderSectionSize / 2) + && (colorState != Qt::white)) + colorState = Qt::white; + + else if ((value > (3 * sliderSectionSize / 2)) + && value < (5 * sliderSectionSize / 2) + && (colorState != Qt::red)) + colorState = Qt::red; + + else if ((value > (5 * sliderSectionSize / 2)) + && value < (7 * sliderSectionSize / 2) + && (colorState != Qt::magenta)) + colorState = Qt::magenta; + + else if ((value > (7 * sliderSectionSize / 2)) + && value < (9 * sliderSectionSize / 2) + && (colorState != Qt::blue)) + colorState = Qt::blue; + + else if ((value > (9 * sliderSectionSize / 2)) + && value < (11 * sliderSectionSize / 2) + && (colorState != Qt::cyan)) + colorState = Qt::cyan; + + else if (value > (11 * sliderSectionSize / 2) + && value < (13 * sliderSectionSize / 2) + && (colorState != Qt::green)) + colorState = Qt::green; + + else if (value > ((6 * sliderSectionSize) + (sliderSectionSize / 2)) + && (colorState != Qt::yellow)) + colorState = Qt::yellow; + + if (colorAtStart != colorState) { + if (auto led = m_etsBoard.getColorLed()) { + led->setCurrentColor(colorState); + sendColorLedGroupValueWriteFrames(m_tunnel, led); + } + } +} + +void QmlKnxDemo::toggleMiddleRight() +{ + auto light = DeviceNumbers::MIDDLE_RIGHT; + if (auto dpt = static_cast<DemoSwitchDataPoint *>(m_etsBoard.getGroupObject(light))) { + dpt->uiToggle(); + sendGroupValueWrite(m_tunnel, m_etsBoard.getAddress(light), dpt->bytes()); + } +} + +void QmlKnxDemo::toggleMiddleLeft() +{ + auto led = m_etsBoard.getColorLed(); + if (!led) + return; + + if (!led->isOn()) { + // set green color in dpt by default... + led->setCurrentColor(QColor(0, 255, 0)); + // send request to ets board + sendColorLedGroupValueWriteFrames(m_tunnel, led); + } else { + led->setCurrentColor(QColor(0, 0, 0)); + sendColorLedGroupValueWriteFrames(m_tunnel, led); + } +} + +QString QmlKnxDemo::getColor() const +{ + if (auto obj = m_etsBoard.getColorLed()) + return obj->currentColor().name(); + return {}; +} + +int QmlKnxDemo::getRockerPosition() const +{ + if (auto rocker = m_etsBoard.getRocker()) + return rocker->position(); + return 0; +} + +bool QmlKnxDemo::getLightState(int lightNum) const +{ + if (auto dpt = static_cast<DemoSwitchDataPoint *>(m_etsBoard.getGroupObject(lightNum))) + return dpt->isOn(); + return false; +} + +int QmlKnxDemo::getBlindPosition() const +{ + if (auto blind = m_etsBoard.getBlind()) + return blind->position(); + return 0; +} + +void QmlKnxDemo::moveBlindUp() +{ + if (auto dpt = m_etsBoard.getBlind()) { + sendGroupValueWrite(m_tunnel, m_etsBoard.getAddress(DeviceNumbers::E7), dpt->moveUpBytes(), + 0xac); + } +} + +void QmlKnxDemo::moveBlindDown() +{ + if (auto dpt = m_etsBoard.getBlind()) { + sendGroupValueWrite(m_tunnel, m_etsBoard.getAddress(DeviceNumbers::E7), dpt->moveDownBytes(), + 0xac); + } +} + +void QmlKnxDemo::stopBlind() +{ + auto index = DeviceNumbers::E16; + if (auto dpt = static_cast<DemoBlindDataPoint *>(m_etsBoard.getGroupObject(index))) + sendGroupValueWrite(m_tunnel, m_etsBoard.getAddress(index), dpt->stopBytes(), 0xac); +} + +void QmlKnxDemo::handleFrame(const QKnxTunnelFrame &frame) +{ + auto str = frame.serviceInformation().bytes().toHex(); + auto dstAdd = frame.destinationAddress().toString(); + + if (QKnxCemiFrame::MessageCode::DataConfirmation == frame.messageCode() + || QKnxCemiFrame::MessageCode::DataIndication == frame.messageCode()) { + // data indication come from pushing buttons on the Board + // data confirmation are responses to App UI requests + bool boardStateChanged = false; + const QKnxAddress dstAddress = frame.destinationAddress(); + if (m_etsBoard.exists(dstAddress)) + boardStateChanged = m_etsBoard.getGroupObject(dstAddress)->updateDataPointState(frame); + + if (boardStateChanged) + emit boardUpdate(m_etsBoard.getIndex(dstAddress)); + } +} + +static QHostAddress obtainLocalAddress() +{ + auto addresses = QNetworkInterface::allAddresses(); + for (auto address : qAsConst(addresses)) { + if (address.isLoopback() || address.protocol() != QAbstractSocket::IPv4Protocol) + continue; + qDebug() << "using IP " << address; + return address; + } + qDebug() << "using loopback IP!!!"; + return QHostAddress::LocalHost; // no local address found! +} + +QmlKnxTunnel::QmlKnxTunnel(QmlKnxDemo *demo) +{ + connect(&m_connection, &QKnxNetIpTunnelConnection::stateChanged, + this, &QmlKnxTunnel::handleConnection); + connect(&m_connection, &QKnxNetIpTunnelConnection::receivedTunnelFrame, + demo, &QmlKnxDemo::handleFrame); + connect(&m_timer, &QTimer::timeout, this, &QmlKnxTunnel::send); + auto newAddress = obtainLocalAddress(); + m_connection.setLocalAddress(newAddress); + m_discoveryAgent.setLocalAddress(newAddress); + m_ip.setAddress("192.168.1.50"); + m_port = 3671; + reconnect(); + qDebug() << " m_ip" << m_ip; + // Automatic KNXnet/Ip router discovery. Connects to first router found + static auto handleDiscoveredServer = [&](const QKnxNetIpServerInfo &info) { + if (!m_connected) { + m_ip = info.controlEndpointAddress(); + m_port = info.controlEndpointPort(); + // establish the knx tunnel + reconnect(); + m_connected = true; + } + }; + connect(&m_discoveryAgent, &QKnxNetIpServerDiscoveryAgent::deviceDiscovered, this, + handleDiscoveredServer); + autoDiscoverKnxServers(); +} + +void QmlKnxTunnel::sendTunnelFrame(const QKnxCemiFrame &frame) +{ + if (frame.size() == 0) + return; + + if (m_frames.size() == 0) + m_timer.start(200); + m_frames.enqueue(frame); +} + +void QmlKnxTunnel::reconnect() +{ + m_connection.connectToHost(m_ip, m_port); +} + +void QmlKnxTunnel::autoDiscoverKnxServers() +{ + if (m_connection.state() != m_connection.Connected) { + m_discoveryAgent.stop(); + m_connected = false; + m_discoveryAgent.start(); + } +} + +void QmlKnxTunnel::changeIp(const QString &ip, quint16 port) +{ + m_ip = ip; + m_port = port; + m_connection.disconnectFromHost(); +} + +void QmlKnxTunnel::send() +{ + m_connection.sendTunnelFrame(m_frames.dequeue()); + if (m_frames.size() == 0) + m_timer.stop(); +} + +void QmlKnxTunnel::handleConnection(QKnxNetIpEndpointConnection::State state) +{ + switch (state) { + case QKnxNetIpEndpointConnection::State::Disconnected: + autoDiscoverKnxServers(); + break; + default: + break; + } +} + +void QmlKnxDemo::changeTunnelIp(const QString &ipStr, quint16 port) +{ + m_tunnel.changeIp(ipStr, port); +} + +void QmlKnxDemo::changeRoom(int roomId) +{ + currentRoom = roomId; + emit roomChanged(currentRoom); +} + +void QmlKnxDemo::checkLightStatusOn() +{ + initBoard(m_etsBoard, m_tunnel); +} + +void QmlKnxDemo::test() +{ + static int c = 0; + if (c == 0) + emit colorLedChange(QColor("blue")); + else if (c==1) + emit colorLedChange(QColor("magenta")); + else if (c==2) { + emit colorLedChange(QColor("green")); + c = 0; + return; + } + c++; +} + +void QmlKnxDemo::reconnect() +{ + m_tunnel.reconnect(); +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.h new file mode 100644 index 0000000..d4dc45c --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qmlknxdemo.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLKNXDEMO_H +#define QMLKNXDEMO_H + +#include "etsdevelopmentboard.h" + +#include <QtCore/QQueue> +#include <QtCore/QTimer> +#include <QtGui/QColor> +#include <QtKnx/QKnxNetIpServerDiscoveryAgent> +#include <QtKnx/QKnxNetIpTunnelConnection> +#include <QtKnx/QKnxTunnelFrame> + +class QmlKnxDemo; +class QmlKnxTunnel : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QmlKnxTunnel) + +public: + QmlKnxTunnel(QmlKnxDemo *demo); + void sendTunnelFrame(const QKnxCemiFrame &frame); + void changeIp(const QString &ip, quint16 port = 3671); + void autoDiscoverKnxServers(); + void reconnect(); +public slots: + void handleConnection(QKnxNetIpEndpointConnection::State state); + void send(); + +private: + + + QQueue<QKnxCemiFrame> m_frames; + QKnxNetIpTunnelConnection m_connection; + QKnxNetIpServerDiscoveryAgent m_discoveryAgent; + + QTimer m_timer; + QHostAddress m_ip; + quint16 m_port { 3671 }; + bool m_connected { false }; +}; + +class QmlKnxDemo : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(QmlKnxDemo) + +public: + QmlKnxDemo(); + + Q_INVOKABLE void toggleMiddleRight(); + Q_INVOKABLE void toggleMiddleLeft(); + Q_INVOKABLE QString getColor() const; + Q_INVOKABLE int getRockerPosition() const; + Q_INVOKABLE int getBlindPosition() const; + Q_INVOKABLE bool getLightState(int lightNum) const; + + Q_INVOKABLE void moveBlindUp(); + Q_INVOKABLE void moveBlindDown(); + Q_INVOKABLE void stopBlind(); + + Q_INVOKABLE void colorSwitch(double value); + Q_INVOKABLE void toggleLight(int light); + + Q_INVOKABLE void test(); + Q_INVOKABLE void reconnect(); + Q_INVOKABLE void changeTunnelIp(const QString &ipStr, quint16 port = 3671); + + Q_INVOKABLE void changeRoom(int roomId); + +Q_SIGNALS: + void boardUpdate(quint32 lightNum); + void blindPositionChange(int position); + void blindFullyDown(); + void blindFullyUp(); + void rockerChange(int position); + void colorLedChange(QColor color); + void roomChanged(int roomId); + +public slots: + void handleFrame(const QKnxTunnelFrame &frame); + +private: + void checkLightStatusOn(); + +private: + QColor colorState; + QmlKnxTunnel m_tunnel; + EtsDevelopmentBoard m_etsBoard; + int currentRoom = { 0 }; +}; + +#endif diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.cpp new file mode 100644 index 0000000..933fe40 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.cpp @@ -0,0 +1,459 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qupnprootdevice.h" +#include <QCryptographicHash> +#include <QNetworkDatagram> + +// 239.255.255.250:1900 is the IANA reserved UPnP multicast address. +const QHostAddress QUPnPRootDevice::multicastAddress("239.255.255.250"); +const quint16 QUPnPRootDevice::multicastPort = 1900; + +QList<QUPnPRootDevice*> QUPnPRootDevice::allUPnPRootDevices; + +QUPnPRootDevice::QUPnPRootDevice(QObject *parent, const QString &name, const QString &searchTarget) + : QMinimalHttpServer(parent) +{ + allUPnPRootDevices.push_back(this); + + static bool didRandomize = false; + if (!didRandomize) + qsrand(QTime::currentTime().msec()); + didRandomize = true; + + foreach (const QHostAddress &address, QNetworkInterface::allAddresses()) + if (address.protocol() == QAbstractSocket::IPv4Protocol + && address != QHostAddress(QHostAddress::LocalHost)) + this->localIpAddress = address.toString(); + + this->searchTarget = searchTarget; + this->product = name; + this->uuid = createUuid(name); + connect(&udpSocket, &QUdpSocket::readyRead, this, &QUPnPRootDevice::onUdpDataReceived); +} + +QUPnPRootDevice::~QUPnPRootDevice() +{ + stopListening(); + allUPnPRootDevices.removeAll(this); +} + +void QUPnPRootDevice::stopAllUPnPRootDevices() +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::stopAllUPnPRootDevices"; + #endif + for (QUPnPRootDevice* dev : allUPnPRootDevices) + dev->stopListening(); +} + +QString QUPnPRootDevice::getUPnPxml() +{ + /* + <deviceType>urn:schemas-upnp-org:device:DimmableLight:1</deviceType> + <modelDescription>UPnP-to-KNX Bridge</modelDescription> + <modelName>UPnP-to-KNX Bridge</modelName> + <modelNumber>0.1</modelNumber> + <modelURL>https://qt.io</modelURL> + <serialNumber>0.1</serialNumber> + <presentationURL/> + */ + + QString upnp_xml = QStringLiteral( + "<?xml version=\"1.0\"?>" + "<root xmlns=\"urn:schemas-upnp-org:device-1-0\">" + "<specVersion>" + "<major>1</major>" + "<minor>0</minor>" + "</specVersion>" + "<device>" + "<deviceType>upnp:rootdevice</deviceType>" + "<friendlyName>") + this->product + "</friendlyName>" + "<manufacturer>" + this->manufacturer + "</manufacturer>" + "<manufacturerURL>" + this->manufacturerURL + "</manufacturerURL>" + "<modelName>" + this->product + "</modelName>" + "<modelNumber>0.1</modelNumber>" + "<UDN>uuid:" + this->uuid + "</UDN>"; + + // icons + if (icons.size() > 0) { + upnp_xml += "<iconList>"; + for (QString iconKey : icons.keys()) { + QImage icon = icons[iconKey]; + upnp_xml += QStringLiteral( + "<icon>") + + "<mimetype>" + httpFileMimeTypes[iconKey] + "</mimetype>" + "<width>" + QString::number(icon.width()) + "</width>" + "<height>" + QString::number(icon.height()) + "</height>" + "<depth>" + QString::number(icon.depth()) + "</depth>" + "<url>" + iconKey + "</url>" + "</icon>"; + } + upnp_xml += "</iconList>"; + } + + // services + if (services.size() > 0) { + upnp_xml += "<serviceList>"; + for (auto service : services) + upnp_xml += service->upnpServiceListEntry(); + upnp_xml += "</serviceList>"; + } + + upnp_xml += + "</device>" + "</root>"; + + return upnp_xml; +} + +QUPnPService *QUPnPRootDevice::getService(const QString &urlUpper) +{ + QString serviceKey; + if (urlUpper.startsWith("/") && urlUpper.endsWith("/CONTROL")) + serviceKey = urlUpper.mid(1, urlUpper.size() - 9); + else if (urlUpper.startsWith("/") && urlUpper.endsWith("/EVENTS")) + serviceKey = urlUpper.mid(1, urlUpper.size() - 8); + else if (urlUpper.startsWith("/") && urlUpper.endsWith("/SCPD.XML")) + serviceKey = urlUpper.mid(1, urlUpper.size() - 10); + + if (serviceKey != "" && services.contains(serviceKey)) + return services[serviceKey]; + return nullptr; +} + +void QUPnPRootDevice::onUdpDataReceived() +{ + QHostAddress senderAddress; + quint16 senderPort; + while (udpSocket.hasPendingDatagrams()) { + //udpSocket.readDatagram(datagram.data(), datagram.size(), &senderAddress, &senderPort); + QNetworkDatagram datagram = udpSocket.receiveDatagram(int(udpSocket.pendingDatagramSize())); + senderAddress = datagram.senderAddress(); + senderPort = datagram.senderPort(); +#ifdef QT_DEBUG + QString sdatagram = QString::fromUtf8(datagram.data()); + if (!sdatagram.contains("ST: urn:dial-multiscreen-org:") + && !sdatagram.contains("ST:urn:schemas-upnp-org:device:InternetGatewayDevice:") + && !sdatagram.contains("ST: urn:schemas-upnp-org:device:InternetGatewayDevice:") + && !sdatagram.contains("ST:urn:schemas-upnp-org:device:MediaRenderer:") + && !sdatagram.contains("ST:urn:schemas-upnp-org:device:MediaServer:") + && !sdatagram.contains("NOTIFY * HTTP/") + //&& !sdatagram.contains("") + ) { + qDebug() << "QUPnPRootDevice::onUdpDataReceived " << sdatagram; + qDebug() << "QUPnPRootDevice::onUdpDataReceived ip and port:" << senderAddress << senderPort; + } + #endif + processUdpData(QString::fromUtf8(datagram.data()), senderAddress, senderPort); + } +} + +void QUPnPRootDevice::processUdpData(const QString &data, QHostAddress senderAddress, quint16 senderPort) +{ + if (!data.startsWith("M-SEARCH") + || !data.contains("MAN: \"ssdp:discover\"", Qt::CaseInsensitive) + || ( !data.contains("ST: ssdp:all", Qt::CaseInsensitive) + && !data.contains("ST: upnp:rootdevice", Qt::CaseInsensitive) + && !data.contains(QStringLiteral("ST: ") + this->searchTarget, Qt::CaseInsensitive))) + return; + + // SSDP Requests should not be answered immediately, because the sender of the + // request might get many results and might run on weak hardware. + int responseDelay = 1000; // milliseconds + QStringList lines = data.split("\r\n"); + for (QString line : lines) { + if (line.startsWith("MX:", Qt::CaseInsensitive)) + responseDelay = 1000 * line.mid(3).trimmed().toInt(); + } + if (responseDelay > 0) + responseDelay = qrand() % responseDelay; + + QTimer::singleShot(responseDelay, [this, senderAddress, senderPort](){ + QString message = QStringLiteral( + "HTTP/1.1 200 OK\r\n" + "LOCATION: http://") + localIpAddress + ":" + QString::number(tcpServer.serverPort()) + "/upnp.xml\r\n" + "EXT:\r\n" + "USN: uuid:" + this->uuid + "::" + this->searchTarget + "\r\n" + "SERVER: " + QSysInfo::productType() + "/" + QSysInfo::productVersion() + " UPnP/1.0 " + product + "/" + version + "\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "ST: " + this->searchTarget + "\r\n" + "DATE: " + DateRfc7231() + "\r\n" + "CONTENT-LENGTH: 0\r\n" + "\r\n"; + + QUdpSocket responseSocket; + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::processUdpData senderIp:" << senderAddress << message; + #endif + responseSocket.writeDatagram(message.toUtf8(), senderAddress, senderPort); + }); +} + +bool QUPnPRootDevice::processHttpGetRequest(QString urlUpper, QString &responseHead, QByteArray &responseBody) +{ + if (urlUpper == "/UPNP.XML") + { + responseBody = this->getUPnPxml().toUtf8(); + responseHead += "content-type: text/xml; charset=utf-8\r\n"; + return true; + } + else + { + QUPnPService *service = getService(urlUpper); + if (service) { + responseBody = service->getScpd().toUtf8(); + responseHead += QStringLiteral( + "content-type: text/xml; charset=utf-8\r\n" + "server: ") + QSysInfo::productType() + "/" + QSysInfo::productVersion() + " UPnP/1.0 " + product + "/" + version + "\r\n"; + return true; + } + } + return QMinimalHttpServer::processHttpGetRequest(urlUpper, responseHead, responseBody); +} + +int QUPnPRootDevice::processHttpPostRequest(QString urlUpper, QByteArray &postBody, QString &responseHead, QByteArray &responseBody) +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::processHttpPostRequest"; + qDebug() << postBody; + #endif + + QUPnPService *service = getService(urlUpper); + if (!service) { + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; + } + + QDomDocument doc; + QString errorMsg; int errorLine; int errorColumn; + if (!doc.setContent(postBody, true, &errorMsg, &errorLine, &errorColumn)) { + #ifdef QT_DEBUG + qDebug() << "doc.setContent failed (" << errorLine << ":" << errorColumn << ") " << errorMsg; + #endif + responseHead = "HTTP/1.0 400 Bad Request\r\n"; + return 400; + } + + QDomElement envelope = doc.documentElement(); + QDomNodeList bodies = envelope.elementsByTagNameNS("http://schemas.xmlsoap.org/soap/envelope/", "Body"); + for (int bodyIdx = 0; bodyIdx < bodies.size(); bodyIdx++) { + + QString actionName; + + // iterate the RPC calls in the envelope + QDomNodeList RPCs = bodies.at(bodyIdx).toElement().childNodes(); + for (int RPCIdx = 0; RPCIdx < RPCs.size(); RPCIdx++) { + if (!RPCs.at(RPCIdx).isElement()) + continue; + + actionName = RPCs.at(RPCIdx).toElement().localName(); + + // collect parameters + QMap<QString, QString> actionParameters; + QDomNodeList params = RPCs.at(RPCIdx).toElement().childNodes(); + for (int paramIdx = 0; paramIdx < params.size(); paramIdx++) { + if (!params.at(paramIdx).isElement()) + continue; + + QString paramName = params.at(paramIdx).toElement().localName(); + QString paramValue = ""; + // get paramValue + QDomNodeList paramChildren = params.at(paramIdx).toElement().childNodes(); + for (int paramChildIdx = 0; paramChildIdx < paramChildren.size(); paramChildIdx++) + if (paramChildren.at(paramChildIdx).isText()) + paramValue = paramChildren.at(paramChildIdx).toText().data(); + + actionParameters[paramName] = paramValue; + } + + // execute the RPC call + return service->executeRemoteProcedureCall(actionName, actionParameters, responseHead, responseBody); + + } + } + + return QMinimalHttpServer::processHttpPostRequest(urlUpper, postBody, responseHead, responseBody); +} + +int QUPnPRootDevice::processHttpSubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::processHttpSubscribeRequest"; + #endif + + QUPnPService *service = getService(urlUpper); + if (!service) { + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; + } + + return service->processHttpSubscribeRequest(requestLines, responseHead, responseBody); +} + +int QUPnPRootDevice::processHttpUnsubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::processHttpUnsubscribeRequest"; + #endif + + QUPnPService *service = getService(urlUpper); + if (!service) { + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; + } + + return service->processHttpUnsubscribeRequest(requestLines, responseHead, responseBody); +} + +QString QUPnPRootDevice::createUuid(const QString &base) +{ + QString uuid; + if (base == QString()) { + uuid = QUuid::createUuid().toString(); // random uuid + uuid = uuid.mid(1, uuid.length()-2); // remove leading { and trailing } + } else { + uuid = QString(QCryptographicHash::hash(base.toUtf8(),QCryptographicHash::Sha1).toHex()); + } + + return uuid; +} + +void QUPnPRootDevice::startListening(quint16 port) +{ + if (isListening()) + return; + + QMinimalHttpServer::startListening(port); + + udpSocket.bind(QHostAddress::AnyIPv4, multicastPort, QUdpSocket::ReuseAddressHint); + udpSocket.joinMulticastGroup(multicastAddress); + + // notify network via multicast + QString message = QStringLiteral( + "NOTIFY * HTTP/1.1\r\n" + "HOST: ") + multicastAddress.toString() + ":" + QString::number(multicastPort) + "\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "LOCATION: http://" + localIpAddress + ":" + QString::number(tcpServer.serverPort()) + "/upnp.xml\r\n" + "SERVER: " + QSysInfo::productType() + "/" + QSysInfo::productVersion() + " UPnP/1.0 " + product + "/" + version + "\r\n" + "NTS: ssdp:alive\r\n" + "NT: " + this->searchTarget + "\r\n" + "USN: uuid:" + this->uuid + "::" + this->searchTarget + "\r\n" + "\r\n"; + QUdpSocket aliveSocket; + aliveSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, 4); + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::startListening " << message; + #endif + aliveSocket.writeDatagram(message.toUtf8(), multicastAddress, multicastPort); +} + +void QUPnPRootDevice::stopListening() +{ + if (!isListening()) + return; + + // notify network via multicast + QString message = QStringLiteral( + "NOTIFY * HTTP/1.1\r\n" + "HOST: ") + multicastAddress.toString() + ":" + QString::number(multicastPort) + "\r\n" + "NT: " + this->searchTarget + "\r\n" + "NTS: ssdp:byebye\r\n" + "USN: uuid:" + this->uuid + "::" + this->searchTarget + "\r\n" + "SERVER: " + QSysInfo::productType() + "/" + QSysInfo::productVersion() + " UPnP/1.0 " + product + "/" + version + "\r\n" + "DATE: " + DateRfc7231() + "\r\n" + "CONTENT-LENGTH: 0\r\n" + "\r\n"; + QUdpSocket byebyeSocket; + byebyeSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, 4); + #ifdef QT_DEBUG + qDebug() << "QUPnPRootDevice::stopListening " << message; + #endif + byebyeSocket.writeDatagram(message.toUtf8(), multicastAddress, multicastPort); + + udpSocket.leaveMulticastGroup(multicastAddress); + udpSocket.close(); + QMinimalHttpServer::stopListening(); +} + +void QUPnPRootDevice::addIcon(const QString &filename) +{ + QFileInfo info(filename); + QString nameonly = QString("/") + info.fileName().toUpper(); + + QFile file(filename); + file.open(QFile::ReadOnly); + QByteArray data = file.readAll(); + file.close(); + this->addFile(nameonly, data); + + QImage img; + img.load(filename); + icons[nameonly] = img; + + if (isListening()) { + stopListening(); + startListening(); + } +} + +void QUPnPRootDevice::addService(QUPnPService *service) +{ + QString id = service->identifier.toUpper(); + if (this->services.contains(id)) + return; + service->rootdevice = this; + this->services[id] = service; + + if (isListening()) { + stopListening(); + startListening(); + } +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.h new file mode 100644 index 0000000..10d47ad --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnprootdevice.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUPNPROOTDEVICE_H +#define QUPNPROOTDEVICE_H + +#include <QObject> +#include <QUdpSocket> +#include <QHostAddress> +#include <QNetworkInterface> +#include <QTimer> +#include <QUuid> +#include <QFileInfo> +#include <QImage> +#include <QtXml/QtXml> + +#include "qminimalhttpserver.h" +#include "qupnpservice.h" + +class QUPnPRootDevice : public QMinimalHttpServer +{ + Q_OBJECT + friend class QUPnPService; + friend class MainWindow; + +private: + static QList<QUPnPRootDevice*> allUPnPRootDevices; + +protected: + QString manufacturer = "The Qt Company GmbH"; + QString manufacturerURL = "https://qt.io"; + QString product = "Qt UPnP-to-KNX Bridge"; + QString version = "0.1"; + QString uuid = ""; + QString searchTarget = "upnp:rootdevice"; + QMap<QString, QImage> icons; + QMap<QString, QUPnPService*> services; + + QString localIpAddress = ""; + QUdpSocket udpSocket; + virtual QString getUPnPxml(); + virtual QUPnPService *getService(const QString &urlUpper); + void onUdpDataReceived(); + virtual void processUdpData(const QString &data, QHostAddress senderAddress, quint16 senderPort); + bool processHttpGetRequest(QString urlUpper, QString &responseHead, QByteArray &responseBody) override; + int processHttpPostRequest(QString urlUpper, QByteArray &postBody, QString &responseHead, QByteArray &responseBody) override; + int processHttpSubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) override; + int processHttpUnsubscribeRequest(QString urlUpper, QStringList &requestLines, QString &responseHead, QByteArray &responseBody) override; + + static const QHostAddress multicastAddress; + static const quint16 multicastPort; + static QString createUuid(const QString &base = QString()); + +public: + explicit QUPnPRootDevice(QObject *parent, const QString &searchTarget, const QString &name = "upnp:rootdevice"); + ~QUPnPRootDevice(); + + void startListening(quint16 port = 0); + void stopListening(); + void addIcon(const QString &filename); + void addService(QUPnPService* service); + static void stopAllUPnPRootDevices(); + +signals: + +}; + +#endif // QUPNPROOTDEVICE_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.cpp new file mode 100644 index 0000000..6e09ed7 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.cpp @@ -0,0 +1,367 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qupnpservice.h" +#include "qupnprootdevice.h" + +QUPnPService::QUPnPService(QObject *parent, QString identifier) + : QObject(parent) +{ + this->identifier = identifier; +} + +QUPnPService::~QUPnPService() +{ +} + +QString QUPnPService::upnpServiceListEntry() +{ + return QStringLiteral( + "<service>" + "<serviceType>urn:schemas-upnp-org:service:") + identifier + ":1</serviceType>" + //"<serviceId>urn:upnp-org:serviceId:" + identifier + ":1</serviceId>" + "<serviceId>" + identifier + "</serviceId>" + "<SCPDURL>/" + identifier + "/scpd.xml</SCPDURL>" + "<controlURL>/" + identifier + "/Control</controlURL>" + "<eventSubURL>/" + identifier + "/Events</eventSubURL>" + "</service>"; +} + +int QUPnPService::executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(actionName); + Q_UNUSED(actionParams); + Q_UNUSED(responseHead); + Q_UNUSED(responseBody); + responseHead = "HTTP/1.0 404 Not Found\r\n"; + return 404; +} + +int QUPnPService::processHttpSubscribeRequest(QStringList &lines, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(responseBody); + #ifdef QT_DEBUG + qDebug() << "QUPnPService::processHttpSubscribeRequest"; + #endif + + QUPnPServiceSubscription subscription; + QString timeout = "0"; + for (int i = 1; i < lines.size(); i++) { + if (lines.at(i).startsWith("CALLBACK:", Qt::CaseInsensitive)) { + QString url = lines.at(i).mid(9).trimmed(); + if (url.startsWith("<") && url.endsWith(">")) + url = url.mid(1, url.size()-2); + subscription.url = QUrl(url); + } else if (lines.at(i).startsWith("TIMEOUT:", Qt::CaseInsensitive)) { + timeout = lines.at(i).mid(8).trimmed(); + } else if (lines.at(i).startsWith("SID:", Qt::CaseInsensitive)) { + // renewing a subscription + subscription.uuid = lines.at(i).mid(4).trimmed(); + } + } + + if (timeout.startsWith("SECOND-", Qt::CaseInsensitive)) + timeout = timeout.mid(7).trimmed(); + bool ok = false; + int iTimeout = timeout.toInt(&ok); + subscription.timeoutTime = QDateTime::currentDateTime().addSecs(iTimeout); + + if (!ok || !subscription.url.isValid()) { + responseHead = "HTTP/1.0 400 Bad Request\r\n"; + return 400; + } + + // no SID header => new subscription => new SID + if (subscription.uuid == "") { + subscription.uuid = QUuid::createUuid().toString(); + subscription.uuid = QStringLiteral("uuid:") + subscription.uuid.mid(1, subscription.uuid.size()-2); + + subscriptions[subscription.uuid] = subscription; + + // delay the notification so that the "HTTP/1.1 200 OK" message comes first + QString uuid = subscription.uuid; + QTimer::singleShot(50, [uuid, this](){ + if (subscriptions.contains(uuid)) + onNewSubscriber(subscriptions[uuid]); + }); + + } else { + // only update the timeout. seq and url must stay the same, uuid would stay the same anyways + if (subscriptions.contains(subscription.uuid)) { + responseHead = "HTTP/1.0 412 Precondition Failed\r\n"; + return 412; + } + subscriptions[subscription.uuid].timeoutTime = subscription.timeoutTime; + } + + responseHead = responseHead + + "SERVER: " + QSysInfo::productType() + "/" + QSysInfo::productVersion() + " UPnP/1.0 " + rootdevice->product + "/" + rootdevice->version + "\r\n" + + "SID: " + subscription.uuid + "\r\n" + + "TIMEOUT: Second-" + QString::number(iTimeout) + "\r\n"; + + return 200; +} + +int QUPnPService::processHttpUnsubscribeRequest(QStringList &lines, QString &responseHead, QByteArray &responseBody) +{ + Q_UNUSED(responseBody); + #ifdef QT_DEBUG + qDebug() << "QUPnPService::processHttpUnsubscribeRequest"; + #endif + + // find SID: header + QString SubscriptionUuid; + for (int i = 1; i < lines.size(); i++) + if (lines.at(i).startsWith("SID:", Qt::CaseInsensitive)) + SubscriptionUuid = lines.at(i).mid(4).trimmed(); + if (SubscriptionUuid == "" || !subscriptions.contains(SubscriptionUuid)) { + responseHead = "HTTP/1.0 412 Precondition Failed\r\n"; + return 412; + } + + subscriptions.remove(SubscriptionUuid); + return 200; +} + +bool QUPnPService::notifySubscriber(QUPnPServiceSubscription &subscription, const QString &propertyName, const QString &propertyValue) +{ + QByteArray notificationBody = (QStringLiteral( + "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">" + "<e:property>" + "<") + propertyName + ">" + propertyValue + "</" + propertyName + ">" + "</e:property>" + "</e:propertyset>").toUtf8(); + + QString notification = QStringLiteral( + "NOTIFY ") + subscription.url.path() + " HTTP/1.1\r\n" + "HOST: " + subscription.url.host(); + if (subscription.url.port() > 0) + notification += QStringLiteral(":") + QString::number(subscription.url.port()); + notification += "\r\n" + "CONTENT-TYPE: text/xml; charset=utf-8\r\n" + "NT: upnp:event\r\n" + "NTS: upnp:propchange\r\n" + "CONTENT-LENGTH: " + QString::number(notificationBody.size()) + "\r\n" + "SID: " + subscription.uuid + "\r\n" + "SEQ: " + QString::number(subscription.sequenceNumber) + "\r\n" + "CONNECTION: close\r\n" + "\r\n"; + + if (subscription.sequenceNumber >= UINT_MAX) + subscription.sequenceNumber = 1; // not 0! + else + subscription.sequenceNumber++; + + QByteArray message = notification.toUtf8(); + message.append(notificationBody); + #ifdef QT_DEBUG + qDebug() << "QUPnPService::notifySubscriber: " << message; + #endif + + QTcpSocket notificationSocket; + notificationSocket.connectToHost(subscription.url.host(), subscription.url.port(80)); + if (!notificationSocket.waitForConnected(10000)) { + qDebug() << "QUPnPService::notifySubscriber: ERROR could not connect to host"; + return false; + } + + notificationSocket.write(message); + notificationSocket.waitForReadyRead(30000); // See UPnP specification, chapter 4.2.1 + #ifdef QT_DEBUG + qDebug() << "QUPnPService::notifySubscriber RESPONSE: " << message; + #endif + return true; +} + +void QUPnPService::notifyPropertyChanged(const QString &propertyName, const QString &propertyValue) +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPService::notifyPropertyChanged"; + #endif + QDateTime now = QDateTime::currentDateTime(); + QList<QString> expiredSubscriptions; + + for (QString subscriptionKey : subscriptions.keys()) { + QUPnPServiceSubscription &subscription = subscriptions[subscriptionKey]; + bool mustRemove = true; + if (now <= subscription.timeoutTime) + mustRemove = !notifySubscriber(subscription, propertyName, propertyValue); + if (mustRemove) + expiredSubscriptions.push_back(subscriptionKey); + } + + for (QString expiredKey : expiredSubscriptions) + subscriptions.remove(expiredKey); +} + + + +QUPnPBooleanService::QUPnPBooleanService(QObject *parent, QString identifier) + : QUPnPService(parent, identifier) +{ +} + +bool QUPnPBooleanService::doSetState(bool state) +{ +// if (state == this->state) +// return false; + this->state = state; + return true; +} + +void QUPnPBooleanService::setState(bool state) +{ + if (doSetState(state)) { + notifyPropertyChanged("state", state?"1":"0"); + emit this->stateChanged(state); + } else { + emit this->stateChangeFailed(); + } +} + +bool QUPnPBooleanService::getState() +{ + return state; +} + +QString QUPnPBooleanService::getScpd() +{ + return QStringLiteral( + "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">" + "<specVersion>" + "<major>1</major>" + "<minor>0</minor>" + "</specVersion>" + + "<actionList>" + "<action>" + "<name>setState</name>" + "<argumentList>" + "<argument>" + "<name>newState</name>" + "<relatedStateVariable>state</relatedStateVariable>" + "<direction>in</direction>" + "</argument>" + "</argumentList>" + "</action>" + "</actionList>" + + "<serviceStateTable>" + "<stateVariable sendEvents=\"yes\">" + "<name>state</name>" + "<dataType>boolean</dataType>" + "<defaultValue>") + (getState()?"1":"0") + "</defaultValue>" + "</stateVariable>" + "</serviceStateTable>" + "</scpd>"; +} + +int QUPnPBooleanService::executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody) +{ + #ifdef QT_DEBUG + qDebug() << "QUPnPBooleanService::executeRemoteProcedureCall"; + #endif + + bool ok = false; + int newStateValue = actionParams["newState"].toInt(&ok); + if (actionName.toUpper() != "SETSTATE" || newStateValue < 0 || 1 < newStateValue || !ok) { + responseHead = "HTTP/1.0 400 Bad Request\r\n"; + return 400; + } + + this->setState(newStateValue == 1); + responseHead = QStringLiteral( + "HTTP/1.0 200 OK\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"); + responseBody = (QStringLiteral( + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" + " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<s:Body>" + "<u:") + actionName + "Response xmlns:u=\"urn:schemas-upnp-org:service:" + identifier +":1\">" + "</u:" + actionName + "Response>" + "</s:Body>" + "</s:Envelope>").toUtf8(); + return 200; +} + +void QUPnPBooleanService::onNewSubscriber(QUPnPServiceSubscription &subscription) +{ + this->notifySubscriber(subscription, "state", getState()?"1":"0"); +} + + + +QUPnPBooleanServiceProxy::QUPnPBooleanServiceProxy(QObject *parent, QUPnPBooleanService *target, QString identifier) + : QUPnPBooleanService(parent, identifier) + , m_target(target) +{ + if (target) { + connect(target, &QUPnPBooleanService::stateChanged, [this](bool state){ + this->notifyPropertyChanged("state", state?"1":"0"); + emit stateChanged(state); + }); + connect(target, &QUPnPBooleanService::stateChangeFailed, [this](){ + emit stateChangeFailed(); + }); + } +} + +void QUPnPBooleanServiceProxy::setState(bool state) +{ + if (m_target) + m_target->setState(state); +} + +bool QUPnPBooleanServiceProxy::getState() +{ + if (!m_target) + return false; + return m_target->getState(); +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.h new file mode 100644 index 0000000..fa3f51a --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qupnpservice.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QUPNPSERVICE_H +#define QUPNPSERVICE_H + +#include <QObject> +#include <QTcpSocket> +#include <QtXml/QtXml> + + +class QUPnPServiceSubscription +{ + friend class QUPnPService; + QString uuid; + QUrl url; + QDateTime timeoutTime; + quint32 sequenceNumber = 0; +}; +class QUPnPRootDevice; + +class QUPnPService : public QObject +{ + Q_OBJECT + friend class QUPnPRootDevice; + friend class QVirtualBelkinWeMo; + +protected: + QUPnPRootDevice *rootdevice; + QString identifier; + QMap<QString, QUPnPServiceSubscription> subscriptions; + virtual QString upnpServiceListEntry(); + virtual QString getScpd() = 0; + virtual int executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody); + virtual int processHttpSubscribeRequest(QStringList &requestLines, QString &responseHead, QByteArray &responseBody); + virtual int processHttpUnsubscribeRequest(QStringList &requestLines, QString &responseHead, QByteArray &responseBody); + void notifyPropertyChanged(const QString &propertyName, const QString &propertyValue); + bool notifySubscriber(QUPnPServiceSubscription &subscription, const QString &propertyName, const QString &propertyValue); + virtual void onNewSubscriber(QUPnPServiceSubscription &subscription) = 0; + +public: + explicit QUPnPService(QObject *parent = nullptr, QString identifier=QString()); + virtual ~QUPnPService(); + Q_DISABLE_COPY(QUPnPService) +}; + + +class QUPnPBooleanService : public QUPnPService +{ + Q_OBJECT + +protected: + bool state = false; + virtual bool doSetState(bool state); + QString getScpd() override; + int executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody) override; + void onNewSubscriber(QUPnPServiceSubscription &subscription) override; + +public: + explicit QUPnPBooleanService(QObject *parent = nullptr, QString identifier=QString()); + virtual void setState(bool state); + virtual bool getState(); + +signals: + void stateChanged(bool newState); + void stateChangeFailed(); +}; + + +class QUPnPBooleanServiceProxy : public QUPnPBooleanService +{ + Q_OBJECT + +protected: + QUPnPBooleanService *m_target; + +public: + explicit QUPnPBooleanServiceProxy(QObject *parent, QUPnPBooleanService *target, QString identifier=QString()); + void setState(bool state) override; + bool getState() override; +}; + +#endif // QUPNPSERVICE_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.cpp b/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.cpp new file mode 100644 index 0000000..cb92db8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Parts of this work are derived from makermusings fauxmo, see +// http://www.makermusings.com/2015/07/18/virtual-wemo-code-for-amazon-echo/ +// https://github.com/makermusings/fauxmo +// commit 54e00be77552fba7b177866f55cf89d017c57dc6 +// provided under the terms of + +/**************************************************************************** +The MIT License (MIT) + +Copyright (c) 2015 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +****************************************************************************/ + +#include "qvirtualbelkinwemo.h" +#include "qupnpservice.h" + + +QVirtualBelkinWeMo::QVirtualBelkinWeMo(QObject *parent, const QString &name) + : QUPnPRootDevice(parent, name, QStringLiteral("urn:Belkin:device:**")) +{ + this->service = new QVirtualBelkinWeMoService(this); + this->addService(this->service); + +} + +QString QVirtualBelkinWeMo::getUPnPxml() +{ + QString upnp_xml = QStringLiteral( + "<?xml version=\"1.0\"?>" + "<root>" + "<device>" + "<deviceType>urn:Belkin:device:")+ deviceType +":1</deviceType>" + "<friendlyName>" + this->product + "</friendlyName>" + "<manufacturer>Belkin International Inc.</manufacturer>" + "<modelName>Emulated Socket</modelName>" + "<modelNumber>3.1415</modelNumber>" + "<UDN>uuid:Socket-1_0-" + this->uuid + "</UDN>"; + + // icons + if (icons.size() > 0) { + upnp_xml += "<iconList>"; + for (QString iconKey : icons.keys()) { + QImage icon = icons[iconKey]; + upnp_xml += QStringLiteral( + "<icon>") + + "<mimetype>" + httpFileMimeTypes[iconKey] + "</mimetype>" + "<width>" + QString::number(icon.width()) + "</width>" + "<height>" + QString::number(icon.height()) + "</height>" + "<depth>" + QString::number(icon.depth()) + "</depth>" + "<url>" + iconKey + "</url>" + "</icon>"; + } + upnp_xml += "</iconList>"; + } + + // services + if (services.size() > 0) { + upnp_xml += "<serviceList>"; + for (auto service : services) + upnp_xml += service->upnpServiceListEntry(); + upnp_xml += "</serviceList>"; + } + + upnp_xml += + "</device>" + "</root>"; + + return upnp_xml; +} + +QUPnPService *QVirtualBelkinWeMo::getService(const QString &urlUpper) +{ + Q_UNUSED(urlUpper); + return service; +} + +QVirtualBelkinWeMoService::QVirtualBelkinWeMoService(QObject *parent) + : QUPnPBooleanService(parent, "SwitchPower") +{ + +} + +QString QVirtualBelkinWeMoService::upnpServiceListEntry() +{ + return QStringLiteral( + "<service>" + "<serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>" + "<serviceId>") + identifier + "</serviceId>" + "<SCPDURL>/" + identifier + "/scpd.xml</SCPDURL>" + "<controlURL>/upnp/control</controlURL>" + "</service>"; +} + +QString QVirtualBelkinWeMoService::getScpd() +{ + return QStringLiteral( + "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">" + "<specVersion>" + "<major>1</major>" + "<minor>0</minor>" + "</specVersion>" + + "<actionList>" + "<action>" + "<name>SetBinaryState</name>" + "<argumentList>" + "<argument>" + "<name>BinaryState</name>" + "<relatedStateVariable>state</relatedStateVariable>" + "<direction>in</direction>" + "</argument>" + "</argumentList>" + "</action>" + + "<action>" + "<name>GetBinaryState</name>" + "<argumentList>" + "<argument>" + "<name>BinaryState</name>" + "<relatedStateVariable>state</relatedStateVariable>" + "<direction>out</direction>" + "</argument>" + "</argumentList>" + "</action>" + "</actionList>" + + "<serviceStateTable>" + "<stateVariable sendEvents=\"no\">" + "<name>state</name>" + "<dataType>boolean</dataType>" + "<defaultValue>") + (getState()?"1":"0") + "</defaultValue>" + "</stateVariable>" + "</serviceStateTable>" + "</scpd>"; +} + +int QVirtualBelkinWeMoService::executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody) +{ + #ifdef QT_DEBUG + qDebug() << "QVirtualBelkinWeMoService::executeRemoteProcedureCall " << actionName << actionParams; + #endif + + if (actionName.toUpper() == "SETBINARYSTATE") { + bool ok = false; + int newStateValue = actionParams["BinaryState"].toInt(&ok); + if (newStateValue < 0 || 1 < newStateValue || !ok) { + responseHead = "HTTP/1.0 400 Bad Request\r\n"; + return 400; + } + + this->setState(newStateValue == 1); + } else if (actionName.toUpper() != "GETBINARYSTATE") { + responseHead = "HTTP/1.0 400 Bad Request\r\n"; + return 400; + } + + responseHead = QStringLiteral( + "HTTP/1.0 200 OK\r\n" + "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"); + responseBody = (QStringLiteral( + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" + " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<s:Body>" + "<u:") + actionName + "Response xmlns:u=\"urn:schemas-upnp-org:service:" + identifier +":1\">" + "<BinaryState>" + (getState() ? "1" : "0") + "</BinaryState>" + "</u:" + actionName + "Response>" + "</s:Body>" + "</s:Envelope>").toUtf8(); + return 200; +} diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.h new file mode 100644 index 0000000..852444c --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/qvirtualbelkinwemo.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVIRTUALBELKINWEMO_H +#define QVIRTUALBELKINWEMO_H + +#include "qupnprootdevice.h" + +class QVirtualBelkinWeMoService : public QUPnPBooleanService +{ + Q_OBJECT + +protected: + QString upnpServiceListEntry(); + QString getScpd(); + int executeRemoteProcedureCall(QString actionName, QMap<QString, QString> &actionParams, QString &responseHead, QByteArray &responseBody) override; + +public: + explicit QVirtualBelkinWeMoService(QObject *parent = nullptr); +}; + +class QVirtualBelkinWeMo : public QUPnPRootDevice +{ + Q_OBJECT + friend class MainWindow; +private: + +protected: + QVirtualBelkinWeMoService *service; + QString getUPnPxml() override; + + +public: + QVirtualBelkinWeMo(QObject *parent, const QString &name); + QUPnPService *getService(const QString &urlUpper) override; + QString deviceType = "controllee"; +}; + +#endif // QVIRTUALBELKINWEMO_H diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/readme.md b/tradeshow/knx-demo/3d-Alexa-knx-demo/readme.md new file mode 100644 index 0000000..48553f5 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/readme.md @@ -0,0 +1,15 @@ +# Qt 3D Studio Home Automation Demo + +This demo application is created with Qt 3D Studio and Qt Quick. +It uses a Qt 3D presentation (.uip file) to show what home automation application could look like. +The demo has controls to change lighting and temperature (represented as color) of the rooms. + +![Home Automation Demo](/HomeAutomation/images/home-automation-demo.png) + +The application is designed to be used with Pixel C, but it also has basic scaling in place. +By default the screen size is used as the main application window size. Uncommenting FIXEDWINDOW +definition from main.cpp will force the main application window to be of size 1280x900. + +Config variable KNX_BOARD can be used to compile the application so that it controls the +KNX board. + diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/House.import b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/House.import new file mode 100644 index 0000000..d1aad35 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/House.import @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" > + <Model id="Ground" name="Ground" orientation="Right Handed" position="-0.957248 -0.10826 -2.79746" rotation="0 -0 0" rotationorder="XYZr" scale="1.73739 1 1.00748" sourcepath=".\meshes\Ground.mesh#1" > + <Material id="phong1" name="phong1" blendmode="Normal" diffuse="0.233766 0.233766 0.233766" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="roof1" name="roof1" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\roof1.mesh#1" > + <Material id="BaseWall" name="BaseWall" blendmode="Normal" diffuse="0.552284 0.552284 0.552284" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + <Material id="roof" name="roof" blendmode="Normal" diffuse="0.0609137 0.0609137 0.0609137" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + <Material id="lambert1" name="lambert1" blendmode="Normal" diffuse="1 1 1" emissivepower="0" opacity="100" specularamount="0" /> + </Model> + <Group id="Group_HeatAreas" name="Group_HeatAreas" orientation="Right Handed" position="0 5.53285 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" > + <Model id="Heat_MasterBedroom" name="Heat_MasterBedroom" orientation="Right Handed" position="-6.01453 0.0613521 -9.90316" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_MasterBedroom.mesh#1" > + <Material id="masterbedroomheat" name="masterbedroomheat" blendmode="Normal" diffuse="0.15472 0.15096 0.14256" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_Entrance" name="Heat_Entrance" orientation="Right Handed" position="0.0827332 1.40091 -12.9964" rotation="8.53363 -0 0" rotationorder="XYZr" scale="0.852158 1 0.900558" sourcepath=".\meshes\Heat_Entrance.mesh#1" > + <Material id="entrance" name="entrance" blendmode="Normal" diffuse="0.519797 0.519797 0.519797" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_BedRoom" name="Heat_BedRoom" orientation="Right Handed" position="6.03439 1.73831 -10.6134" rotation="7.55792 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_BedRoom.mesh#1" > + <Material id="bedroom" name="bedroom" blendmode="Normal" diffuse="0.24488 0.388 0.46264" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_DressRoom" name="Heat_DressRoom" orientation="Right Handed" position="8.02201 2.41339 -5.07462" rotation="8.34257 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_DressRoom.mesh#1" > + <Material id="dressroom" name="dressroom" blendmode="Normal" diffuse="0.714721 0.714721 0.714721" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_Toilet" name="Heat_Toilet" orientation="Right Handed" position="3.90588 2.58136 -5.05141" rotation="5.57327 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_Toilet.mesh#1" > + <Material id="toilet" name="toilet" blendmode="Normal" diffuse="0.19208 0.24752 0.37672" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_StoreRoom" name="Heat_StoreRoom" orientation="Right Handed" position="2.97044 0.814303 -17.1022" rotation="8.02365 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_StoreRoom.mesh#1" > + <Material id="storeroom" name="storeroom" blendmode="Normal" diffuse="0.166497 0.166497 0.166497" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_Sauna" name="Heat_Sauna" orientation="Right Handed" position="-7.99717 0.0613521 7.72293" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_Sauna.mesh#1" > + <Material id="sauna1" name="sauna1" blendmode="Normal" diffuse="0.24984 0.24984 0.24984" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_BathRoom" name="Heat_BathRoom" orientation="Right Handed" position="-8.61282 1.1588 -1.06378" rotation="0 -0 0" rotationorder="XYZr" scale="1.04514 1 1" sourcepath=".\meshes\Heat_BathRoom.mesh#1" > + <Material id="bathroom" name="bathroom" blendmode="Normal" diffuse="0.4 0.4 0.4" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + <Model id="Heat_LivingRoom" name="Heat_LivingRoom" orientation="Right Handed" position="2.34465 3.80193 4.35739" rotation="7.88151 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Heat_LivingRoom.mesh#1" > + <Material id="livingroom" name="livingroom" blendmode="Normal" diffuse="0.24984 0.23336 0.16168" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" /> + </Model> + </Group> + <Group id="Group_house" name="Group_house" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" > + <Model id="house1" name="house1" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\house1.mesh#1" > + <Material id="house2" name="house2" blendmode="Normal" diffuse="1 1 1" diffusemap="house2_diffusemap" emissivepower="0" opacity="100" specularamount="0" specularroughness="20" > + <Image id="house2_diffusemap" name="house2_diffusemap" sourcepath=".\maps\houseShape.png" /> + </Material> + </Model> + </Group> + <Model id="Windows" name="Windows" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath=".\meshes\Windows.mesh#1" > + <Material id="Window" name="Window" blendmode="Normal" diffuse="0.35152 0.66672 0.74704" emissivepower="0" opacity="100" specularamount="0" specularroughness="12.1818" /> + </Model> + </Group> + </Graph> + <Import SrcFile="..\..\House\House.fbx" ImageDir="Images" MeshDir="Meshes" > + <Image > + <Source >.\houseShape.png</Source> + <Dest >.\maps\houseShape.png</Dest> + </Image> + <Mesh > + <Source >Heat_BathRoom</Source> + <Dest >.\meshes\Heat_BathRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_Sauna</Source> + <Dest >.\meshes\Heat_Sauna.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_BedRoom</Source> + <Dest >.\meshes\Heat_BedRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >Ground</Source> + <Dest >.\meshes\Ground.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_Toilet</Source> + <Dest >.\meshes\Heat_Toilet.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_StoreRoom</Source> + <Dest >.\meshes\Heat_StoreRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_LivingRoom</Source> + <Dest >.\meshes\Heat_LivingRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >house1</Source> + <Dest >.\meshes\house1.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_DressRoom</Source> + <Dest >.\meshes\Heat_DressRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >Windows</Source> + <Dest >.\meshes\Windows.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_MasterBedroom</Source> + <Dest >.\meshes\Heat_MasterBedroom.mesh</Dest> + </Mesh> + <Mesh > + <Source >roof1</Source> + <Dest >.\meshes\roof1.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_Entrance</Source> + <Dest >.\meshes\Heat_Entrance.mesh</Dest> + </Mesh> + </Import> + </Project> +</UIP> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/maps/houseShape.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/maps/houseShape.png new file mode 100644 index 0000000..41707e1 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/maps/houseShape.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f51993d6c61e765bda9ec72e716512ada65dd95a3bad97518648448b85263ac6 +size 4005995 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Ground.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Ground.mesh new file mode 100644 index 0000000..fc4f211 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Ground.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5c4af427e71594fd244ae2b5d712c662e337a42cb05c372df3a770d4bad49a44 +size 580 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BathRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BathRoom.mesh new file mode 100644 index 0000000..4feca59 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BathRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f39301d0409dba0ed768afbd284127ea71a88b1be5a40a5d872bc358a4d28e4 +size 944 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BedRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BedRoom.mesh new file mode 100644 index 0000000..ded60ae --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_BedRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:800b8155ee25712ad65a4529617b10a4d350fd3f8352a8940dbed0aac4afa004 +size 584 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_DressRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_DressRoom.mesh new file mode 100644 index 0000000..6f1c335 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_DressRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0a8e5bcf3fafbe637e7f50e7f7929979da52f8c687392ce64dbcb54329528eb +size 588 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Entrance.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Entrance.mesh new file mode 100644 index 0000000..4d2ad7d --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Entrance.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c59c5d3eb5ea7ff8fdd83e77ed87a0241f72fce9c05f1be23e6246ac23b98dd9 +size 584 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_LivingRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_LivingRoom.mesh new file mode 100644 index 0000000..6ba80a8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_LivingRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4f460eb3b33365d287ec7d6e07d05203ff7f4d1076ffc667847daabe29726519 +size 2376 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_MasterBedroom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_MasterBedroom.mesh new file mode 100644 index 0000000..ebea101 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_MasterBedroom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:75060f0f0e828a43ff95594c58fde213c50f08fad09e2fc1442cbce61004fa0d +size 852 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Sauna.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Sauna.mesh new file mode 100644 index 0000000..6e6e089 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Sauna.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b3cdd7103b6ad0582242f991f82e66d7f40f871174ab41ba16f7d5e2df1f1c3 +size 580 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_StoreRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_StoreRoom.mesh new file mode 100644 index 0000000..53d7234 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_StoreRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d7260110eac2557697a9021ac0a1b287969fce3aa0fa041f5b7ad66684abcc2 +size 588 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Toilet.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Toilet.mesh new file mode 100644 index 0000000..2c9efe1 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Heat_Toilet.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:03fbf8872237fa58910e8d92b674ef6061f7d24f6741f5038b35796edabc2ddb +size 580 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Windows.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Windows.mesh new file mode 100644 index 0000000..a36ec89 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/Windows.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:667333174e964b7cb50738c62abe5013d94e77dc7d8f503cacdcffb09ae97b0c +size 4592 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/house1.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/house1.mesh new file mode 100644 index 0000000..ed2da37 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/house1.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c4dca286b17a72672cc317de811befd0ec5ba183514ecd5e88db00e2dd15375 +size 284484 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/roof1.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/roof1.mesh new file mode 100644 index 0000000..3f77b0c --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/House/meshes/roof1.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13f329118e118749595ac1751e7de7bf45eb1bcc058bf95b2f420f367a9c5774 +size 19180 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/houseStudio.uip b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/houseStudio.uip new file mode 100644 index 0000000..f64204e --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/houseStudio.uip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fc30878cd2956d3007ca060c3e40e0d7454b218453c92a0caf8c3c6c0d22cf01 +size 279 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BathroomLightmap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BathroomLightmap.png new file mode 100644 index 0000000..94be8b5 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BathroomLightmap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7dd6647023eee217a16ef63c8418ff29bab5005f77e9e0153c46fdc42cfe5ae0 +size 203590 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BedRoomLightmap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BedRoomLightmap.png new file mode 100644 index 0000000..7602e32 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/BedRoomLightmap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c7713b2b823a6d46f14459dfa8b9db2f9efe8928e869474b241e0b36ec7394b +size 70519 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/EntranceLightmap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/EntranceLightmap.png new file mode 100644 index 0000000..c4b4d44 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/EntranceLightmap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d5afdc5d67400592ae384d5c1c91d1ec3487181455ec445cb88015312b78ce08 +size 41621 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Ground.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Ground.png new file mode 100644 index 0000000..a0440f7 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Ground.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aa0488d336670f297721d8fa05ba9048b7b9cebe889cd4e712fe46c6e938063b +size 77518 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseGroundOpacitymap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseGroundOpacitymap.png new file mode 100644 index 0000000..ac42dbb --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseGroundOpacitymap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2ab5cf08c8d3e75e0ef547402d0327232ff4210c19fd3d6cb2806f04f2dfc6c6 +size 76323 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.jpg b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.jpg new file mode 100644 index 0000000..fa9d021 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa9683142d3954dc32a6bf9307f860d45bed3b7e9d983d5051b54219cf43fe42 +size 3459775 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.png new file mode 100644 index 0000000..316661d --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/HouseTexture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:071d192dd3f95d31ae042ae64dfcb02e56da64237587466420a5a8dec1a0f7ce +size 14132813 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/LivingRoomLightMap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/LivingRoomLightMap.png new file mode 100644 index 0000000..8e9b7d1 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/LivingRoomLightMap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:520dbc10ec404e7c83a4b52c6533a5a8dafbbbb74082bdb053156a270af6f6df +size 552205 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/MasterBedroomLightmap.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/MasterBedroomLightmap.png new file mode 100644 index 0000000..3b0acb1 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/MasterBedroomLightmap.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:92e32450eaf3ff1519da5e4e3ff274a46921f8e35a296f9a9d67cb34c47e4d41 +size 113642 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/OpenfootageNET_Pinzgau-512.hdr b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/OpenfootageNET_Pinzgau-512.hdr new file mode 100644 index 0000000..2fd25a6 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/OpenfootageNET_Pinzgau-512.hdr @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0baf00208f32e5f037c2f9433b3ae3cc27e244160bbc8a321f716acbf15747e +size 416212 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Roof.png b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Roof.png new file mode 100644 index 0000000..60f27f8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/maps/Roof.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e8c888be1ac45994fa43824b10003d5e140a9fc9e998e333401ffddf13c280d +size 107095 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/HeatAreas.import b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/HeatAreas.import new file mode 100644 index 0000000..72ddff0 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/HeatAreas.import @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" > + <Group id="Group_HeatAreas" name="Group_HeatAreas" orientation="Right Handed" position="0 0 -0" rotation="-90 -0 0" rotationorder="XYZr" scale="100 100 100" > + <Model id="Heat_Entrance HeatAreas" name="Heat_Entrance HeatAreas" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\Heat_Entrance HeatAreas.mesh#1" > + <Material id="Heat_EntranceSG" name="Heat_EntranceSG" blendmode="Normal" diffuse="0.65 0.65 0.65" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_Sauna" name="HeatAreas Heat_Sauna" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_Sauna.mesh#1" > + <Material id="Heat_SaunaSG" name="Heat_SaunaSG" blendmode="Normal" diffuse="0.31 0.31 0.31" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_BathRoom" name="HeatAreas Heat_BathRoom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_BathRoom.mesh#1" > + <Material id="Heat_BathRoomSG" name="Heat_BathRoomSG" blendmode="Normal" diffuse="0.5 0.5 0.5" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_StoreRoom" name="HeatAreas Heat_StoreRoom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_StoreRoom.mesh#1" > + <Material id="Heat_StoreRoomSG" name="Heat_StoreRoomSG" blendmode="Normal" diffuse="0.21 0.21 0.21" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_DressRoom" name="HeatAreas Heat_DressRoom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_DressRoom.mesh#1" > + <Material id="Heat_DressRoomSG" name="Heat_DressRoomSG" blendmode="Normal" diffuse="0.89 0.89 0.89" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_LivingRoom" name="HeatAreas Heat_LivingRoom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_LivingRoom.mesh#1" > + <Material id="Heat_LivingRoomSG" name="Heat_LivingRoomSG" blendmode="Normal" diffuse="0.31 0.29 0.2" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_MasterBedroom" name="HeatAreas Heat_MasterBedroom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_MasterBedroom.mesh#1" > + <Material id="Heat_MasterBedroomSG" name="Heat_MasterBedroomSG" blendmode="Normal" diffuse="0.19 0.19 0.18" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_BedRoom" name="HeatAreas Heat_BedRoom" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_BedRoom.mesh#1" > + <Material id="Heat_BedRoomSG" name="Heat_BedRoomSG" blendmode="Normal" diffuse="0.31 0.49 0.58" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + <Model id="HeatAreas Heat_Toilet" name="HeatAreas Heat_Toilet" orientation="Right Handed" position="0 0 -0" rotation="90 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes\HeatAreas Heat_Toilet.mesh#1" > + <Material id="Heat_ToiletSG" name="Heat_ToiletSG" blendmode="Normal" diffuse="0.24 0.31 0.47" emissivepower="0" opacity="0" specularamount="0" specularroughness="1.76471" /> + </Model> + </Group> + </Group> + </Graph> + <Import SrcFile="..\..\..\..\House\Vol2Exports\HeatAreas.fbx" ImageDir="Images" MeshDir="Meshes" > + <Mesh > + <Source >HeatAreas Heat_LivingRoom</Source> + <Dest >meshes\HeatAreas Heat_LivingRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >Heat_Entrance HeatAreas</Source> + <Dest >meshes\Heat_Entrance HeatAreas.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_Sauna</Source> + <Dest >meshes\HeatAreas Heat_Sauna.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_Toilet</Source> + <Dest >meshes\HeatAreas Heat_Toilet.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_StoreRoom</Source> + <Dest >meshes\HeatAreas Heat_StoreRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_BedRoom</Source> + <Dest >meshes\HeatAreas Heat_BedRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_MasterBedroom</Source> + <Dest >meshes\HeatAreas Heat_MasterBedroom.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_DressRoom</Source> + <Dest >meshes\HeatAreas Heat_DressRoom.mesh</Dest> + </Mesh> + <Mesh > + <Source >HeatAreas Heat_BathRoom</Source> + <Dest >meshes\HeatAreas Heat_BathRoom.mesh</Dest> + </Mesh> + </Import> + </Project> +</UIP> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BathRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BathRoom.mesh new file mode 100644 index 0000000..df02c6f --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BathRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e18aead7ab11e9be5eb9558a7547a901ba1e058e849e7c67267cde84673c3332 +size 1072 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BedRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BedRoom.mesh new file mode 100644 index 0000000..c1dbfb4 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_BedRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:51cdbbe7e30f4e45754c9d3341063fb2cb8b4bd219a036496ca979274516143e +size 596 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_DressRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_DressRoom.mesh new file mode 100644 index 0000000..d4a85f8 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_DressRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:222446510da9bcbeb6c742d25d17ad86db760439d43981aca9aa387e91ba3d51 +size 600 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_LivingRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_LivingRoom.mesh new file mode 100644 index 0000000..99b0236 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_LivingRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5021ff6b3834d26ba635bec3a38444d2db5a9a341d9047b95870c4a3d3d83df0 +size 3064 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_MasterBedroom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_MasterBedroom.mesh new file mode 100644 index 0000000..d20100b --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_MasterBedroom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a695743b3441e9eaa444503c5e353b7ad5ad24217ed70aa7ffc383e35533b471 +size 1080 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Sauna.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Sauna.mesh new file mode 100644 index 0000000..e77e3e7 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Sauna.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6afa17f05c26b53bee94c92a54c32a9090d9f0f0374fa8e3d855ba55d54b8373 +size 592 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_StoreRoom.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_StoreRoom.mesh new file mode 100644 index 0000000..4c88238 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_StoreRoom.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b7bfb1f10bb45230c58895d941adbc044dd89436d2c486bc9ba38fdb5a0c58a4 +size 600 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Toilet.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Toilet.mesh new file mode 100644 index 0000000..aeb9ee2 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/HeatAreas Heat_Toilet.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dbcd0d0c561a1f73188a3378339e81343ce77b2c9113ce063c5e555daecd4dea +size 596 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/Heat_Entrance HeatAreas.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/Heat_Entrance HeatAreas.mesh new file mode 100644 index 0000000..68af64c --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/HeatAreas/meshes/Heat_Entrance HeatAreas.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f391836bea853a31f21d460242f89028a6955f9bfa7466ab06961d780bfcbb27 +size 600 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/House.import b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/House.import new file mode 100644 index 0000000..4c87625 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/House.import @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" > + <Model id="Ground" name="Ground" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath="meshes\Ground.mesh#1" > + <Material id="Ground_0001" name="Ground" blendmode="Normal" diffuse="0.257969 0.287919 0.389518" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="House" name="House" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath="meshes\House.mesh#1" > + <Material id="House_0001" name="House" blendmode="Normal" diffuse="0.64 0.64 0.64" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="Windows" name="Windows" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath="meshes\Windows.mesh#1" > + <Material id="WindowsSG" name="WindowsSG" blendmode="Normal" diffuse="0.44 0.83 0.93" emissivepower="0" opacity="0" specularamount="0" specularroughness="0.980392" /> + </Model> + <Model id="Roof" name="Roof" orientation="Right Handed" position="0 0 4.54747e-11" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath="meshes\Roof.mesh#1" > + <Material id="Roof_0001" name="Roof" blendmode="Normal" diffuse="0.0836838 0.0836838 0.0836838" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + </Group> + </Graph> + <Import SrcFile="..\..\..\..\House\Vol2Exports\House.fbx" ImageDir="Images" MeshDir="Meshes" > + <Mesh > + <Source >Roof</Source> + <Dest >meshes\Roof.mesh</Dest> + </Mesh> + <Mesh > + <Source >Ground</Source> + <Dest >meshes\Ground.mesh</Dest> + </Mesh> + <Mesh > + <Source >Windows</Source> + <Dest >meshes\Windows.mesh</Dest> + </Mesh> + <Mesh > + <Source >House</Source> + <Dest >meshes\House.mesh</Dest> + </Mesh> + </Import> + </Project> +</UIP> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Ground.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Ground.mesh new file mode 100644 index 0000000..36ac289 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Ground.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8b25be4c0cded582c9aa0fc06fd53e0a5d70fb448f7f6a87fdc3982b20ea5cf6 +size 692 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/House.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/House.mesh new file mode 100644 index 0000000..2568ef3 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/House.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:080b2e1cadc82771c0e114ca75ea5340cce164d2b49f54cfaf251cb298052f01 +size 375532 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Roof.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Roof.mesh new file mode 100644 index 0000000..59a1889 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Roof.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d464763d1ad262ee9ec37c0e7649a2c0736db39b963fc16f909ab1b8b77fe059 +size 33324 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Windows.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Windows.mesh new file mode 100644 index 0000000..1c7cf65 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/House/meshes/Windows.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84defa65be6e62eb0ae63a42f33eb9982a3e741d71b72a775502e368252a57df +size 5048 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/Light/Light.import b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/Light/Light.import new file mode 100644 index 0000000..9deb049 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/Light/Light.import @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" /> + </Graph> + <Import SrcFile="..\..\..\..\House\Vol2Exports\Light.fbx" ImageDir="Images" MeshDir="Meshes" /> + </Project> +</UIP> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/RoomLights.import b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/RoomLights.import new file mode 100644 index 0000000..e39b9d5 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/RoomLights.import @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" > + <Model id="EntranceLightmap" name="EntranceLightmap" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath=".\meshes\EntranceLightmap.mesh#1" > + <Material id="House" name="House" blendmode="Normal" diffuse="0.052218 0.052218 0.052218" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="BathroomLightmap" name="BathroomLightmap" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath=".\meshes\BathroomLightmap.mesh#1" > + <Material id="House_0001" name="House" blendmode="Normal" diffuse="0.052218 0.052218 0.052218" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="MasterbedroomLightmap" name="MasterbedroomLightmap" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath=".\meshes\MasterbedroomLightmap.mesh#1" > + <Material id="House_0002" name="House" blendmode="Normal" diffuse="0.052218 0.052218 0.052218" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="LivingroomLightMap" name="LivingroomLightMap" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath=".\meshes\LivingroomLightMap.mesh#1" > + <Material id="House_0003" name="House" blendmode="Normal" diffuse="0.052218 0.052218 0.052218" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + <Model id="BedroomLightmap" name="BedroomLightmap" orientation="Right Handed" position="0 0 -0" rotation="9.33467e-06 -0 0" rotationorder="XYZr" scale="100 100 100" sourcepath=".\meshes\BedroomLightmap.mesh#1" > + <Material id="House_0004" name="House" blendmode="Normal" diffuse="0.052218 0.052218 0.052218" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.60784" /> + </Model> + </Group> + </Graph> + <Import SrcFile="..\..\..\..\RoomLights\RoomLights.fbx" ImageDir="Images" MeshDir="Meshes" > + <Mesh > + <Source >BedroomLightmap</Source> + <Dest >.\meshes\BedroomLightmap.mesh</Dest> + </Mesh> + <Mesh > + <Source >EntranceLightmap</Source> + <Dest >.\meshes\EntranceLightmap.mesh</Dest> + </Mesh> + <Mesh > + <Source >BathroomLightmap</Source> + <Dest >.\meshes\BathroomLightmap.mesh</Dest> + </Mesh> + <Mesh > + <Source >LivingroomLightMap</Source> + <Dest >.\meshes\LivingroomLightMap.mesh</Dest> + </Mesh> + <Mesh > + <Source >MasterbedroomLightmap</Source> + <Dest >.\meshes\MasterbedroomLightmap.mesh</Dest> + </Mesh> + </Import> + </Project> +</UIP> diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BathroomLightmap.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BathroomLightmap.mesh new file mode 100644 index 0000000..f850d88 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BathroomLightmap.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:645b3f16c5f782da28944cfb45251fe23dd96080ae86c0c1c5801e898eae52fc +size 16344 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BedroomLightmap.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BedroomLightmap.mesh new file mode 100644 index 0000000..61ce5d4 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/BedroomLightmap.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60f5a2c3f079add7486699a9712f2eca374a5bcd054be1386393f64bc7c28009 +size 16472 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/EntranceLightmap.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/EntranceLightmap.mesh new file mode 100644 index 0000000..13734ba --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/EntranceLightmap.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:762e6c6890b7162f0a7cb4f46d3d6f097595a2555412373460f9eb858ed38aa0 +size 12072 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/LivingroomLightMap.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/LivingroomLightMap.mesh new file mode 100644 index 0000000..2e9aed0 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/LivingroomLightMap.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f1727480055d9de07f96b7ee4b92fbceff3109b450c03612ab75180f83d772e +size 108380 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/MasterbedroomLightmap.mesh b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/MasterbedroomLightmap.mesh new file mode 100644 index 0000000..e6dfd73 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/uip/models/RoomLights/meshes/MasterbedroomLightmap.mesh @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:463612a790952c9c2ea9f6389ace48d31432db5e1bf3cd0936e034b632fba5b1 +size 18852 diff --git a/tradeshow/knx-demo/3d-Alexa-knx-demo/utils.h b/tradeshow/knx-demo/3d-Alexa-knx-demo/utils.h new file mode 100644 index 0000000..147e8d0 --- /dev/null +++ b/tradeshow/knx-demo/3d-Alexa-knx-demo/utils.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio Demos. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef UTILS_H +#define UTILS_H + +#include "demodatapoint.h" + +#include <QtKnx/QKnxAddress> +#include <QtKnx/QKnxNpduFactory> + +QKnxTunnelFrame createRequestFrame(const QKnxAddress &address, const QKnxNpdu &npdu, + quint8 ctrl = 0xac, quint8 extCtrl = 0xe0) +{ + QKnxTunnelFrame frame(QKnxTunnelFrame::MessageCode::DataRequest); + frame.setControlField(QKnxControlField(ctrl)); + frame.setExtendedControlField(QKnxExtendedControlField(extCtrl)); + frame.setSourceAddress({ QKnxAddress::Type::Group, 0 }); + frame.setDestinationAddress(address); + frame.setNpdu(npdu); + return frame; +} + +void sendGroupValueWrite(QmlKnxTunnel &tunnel, const QKnxAddress &address, + const QByteArray &data, quint8 ctrl = 0xa4, quint8 extCtrl = 0xe0) +{ + tunnel.sendTunnelFrame(createRequestFrame(address, + QKnxNpduFactory::Multicast::createGroupValueWriteNpdu(data), ctrl, extCtrl)); +} + +void sendColorLedGroupValueWriteFrames(QmlKnxTunnel &tunnel, const DemoColorLed *const dpt) +{ + if (dpt) { + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 12), + QKnxNpduFactory::Multicast::createGroupValueWriteNpdu(dpt->redBytes()))); + + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 13), + QKnxNpduFactory::Multicast::createGroupValueWriteNpdu(dpt->greenBytes()))); + + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 14), + QKnxNpduFactory::Multicast::createGroupValueWriteNpdu(dpt->blueBytes()))); + } +} + +void initBoard(EtsDevelopmentBoard &board, QmlKnxTunnel &tunnel) +{ + auto npdu = QKnxNpduFactory::Multicast::createGroupValueReadNpdu(); + for (int i = 1; i <= board.size(); ++i) { + if (i >= 9 && i <= 12) + continue; // skip red leds readings because they are not indicating the state! + if ((i == 7) || (i == 8) || (i == 16)) + continue; // skip checking blinds state + + if (QKnxAddress::createGroup(0, 0, 12) == board.getAddress(i)) { + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 12), npdu)); + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 13), npdu)); + tunnel.sendTunnelFrame(createRequestFrame(QKnxAddress::createGroup(0, 0, 14), npdu)); + } else { + tunnel.sendTunnelFrame(createRequestFrame(board.getAddress(i), npdu, 0xa4)); + } + } +} + +#endif |