diff options
author | Kari Hautamäki <kari.hautamaki@qt.io> | 2017-02-16 08:33:49 +0200 |
---|---|---|
committer | Maurice Kalinowski <maurice.kalinowski@qt.io> | 2017-02-28 13:16:09 +0000 |
commit | 35c1c07cd676b9c9afb23ad7266a67d5b6aef03a (patch) | |
tree | d43445955be5f1799ca9bb9db2c6e2cfd7915370 /tradeshow/iot-sensortag/resources | |
parent | dec3883a1d0d7d24c797cf517fa7fad85b24a1f2 (diff) |
iot-sensortag: Allow reconnect after a failed connection attempt
A disconnected sensor tag can be tried to be reconnected by clicking
on the chart area or starting rescan from the Sensor settings menu.
During a (re)connection process a progress indicator is shown to
the user.
The user has a possibility to disconnect (and reconnect) a
currently connect SensorDataProvider
A new state, 'NotFound' is added in SensorTagDataProvider to
distinguish between states when a Sensor Tag has not been discovered
at all, and when it has already been discovered but is has been
disconnected.
Change-Id: I54eea72d8c92a67a5ccbb3bc192ac8f33ada1c39
Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
Diffstat (limited to 'tradeshow/iot-sensortag/resources')
6 files changed, 367 insertions, 94 deletions
diff --git a/tradeshow/iot-sensortag/resources/base/BaseChart.qml b/tradeshow/iot-sensortag/resources/base/BaseChart.qml index 58549b5..d144916 100644 --- a/tradeshow/iot-sensortag/resources/base/BaseChart.qml +++ b/tradeshow/iot-sensortag/resources/base/BaseChart.qml @@ -61,9 +61,17 @@ Item { property bool rightSide: false property alias titlePaneHeight: titleIcon.height property bool hasData: baseChart.sensor ? baseChart.sensor.state === SensorTagData.Connected : false + property int sensorState: sensor ? sensor.state : SensorTagData.NotFound signal clicked + onSensorStateChanged: { + if (sensorState === SensorTagData.Scanning) + sensorIcon.startBlinking(); + else + sensorIcon.stopBlinking(); + } + Image { id: titleIcon @@ -89,6 +97,42 @@ Item { anchors.bottomMargin: 16 anchors.left: parent.left anchors.right: parent.right + visible: sensorState === SensorTagData.Connected + } + + Item { + anchors.top: titleIcon.bottom + anchors.bottom: separator.bottom + anchors.bottomMargin: 16 + anchors.left: parent.left + anchors.right: parent.right + visible: sensorState === SensorTagData.Scanning || + sensorState === SensorTagData.Disconnected || + sensorState === SensorTagData.Error || + sensorState === SensorTagData.NotFound + + Column { + anchors.centerIn: parent + spacing: 20 + + BlinkingIcon { + id: sensorIcon + + source: pathPrefix + "Toolbar/icon_topbar_sensor.png" + anchors.horizontalCenter: parent.horizontalCenter + visible: sensorState === SensorTagData.Scanning + } + + Text { + id: stateText + + color: "white" + text: sensorState === SensorTagData.Scanning ? "Connecting to sensor..." + : sensorState === SensorTagData.Disconnected ? "Disconnected" + : sensorState === SensorTagData.NotFound ? "Device not found" + : "" + } + } } Image { diff --git a/tradeshow/iot-sensortag/resources/base/BlinkingIcon.qml b/tradeshow/iot-sensortag/resources/base/BlinkingIcon.qml new file mode 100644 index 0000000..fc29fc9 --- /dev/null +++ b/tradeshow/iot-sensortag/resources/base/BlinkingIcon.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of Qt for Device Creation. +** +** $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.0 + +Image { + id: icon + + property bool activeBlink: false + + function startBlinking() { + if (!activeBlink) { + activeBlink = true; + mainWindow.startBlink(); + } + } + + function stopBlinking() { + if (activeBlink) { + activeBlink = false; + mainWindow.stopBlink(); + } + } + + opacity: activeBlink ? mainWindow.globalBlinkOpacity: 1 +} diff --git a/tradeshow/iot-sensortag/resources/base/RotationPage.qml b/tradeshow/iot-sensortag/resources/base/RotationPage.qml index 347a886..eee47c1 100644 --- a/tradeshow/iot-sensortag/resources/base/RotationPage.qml +++ b/tradeshow/iot-sensortag/resources/base/RotationPage.qml @@ -56,55 +56,101 @@ Item { property var sensor property var rotationUpdateInterval: sensor ? sensor.rotationUpdateInterval : 0 - focus: true + property int sensorState: sensor ? sensor.state : SensorTagData.Disconnected - Image { - id: ring - anchors.centerIn: parent - source: pathPrefix + "Gyro/gyro_outer.png" + onSensorStateChanged: { + if (sensorState === SensorTagData.Scanning) + sensorIcon.startBlinking(); + else + sensorIcon.stopBlinking(); } - Image { - id: outerRing - anchors.centerIn: parent - source: pathPrefix + "Gyro/gyro_ring3.png" - rotation: sensor ? sensor.rotationX : 0 - Behavior on rotation { - RotationAnimator { - easing.type: Easing.Linear - duration: rotationUpdateInterval - direction: RotationAnimator.Shortest + + Item { + anchors.fill: parent + + visible: sensorState === SensorTagData.Connected + + Image { + id: ring + anchors.centerIn: parent + source: pathPrefix + "Gyro/gyro_outer.png" + } + Image { + id: outerRing + anchors.centerIn: parent + source: pathPrefix + "Gyro/gyro_ring3.png" + rotation: sensor ? sensor.rotationX : 0 + Behavior on rotation { + RotationAnimator { + easing.type: Easing.Linear + duration: rotationUpdateInterval + direction: RotationAnimation.Shortest + } } } - } - Image { - id: largeRing - anchors.centerIn: parent - source: pathPrefix + "Gyro/gyro_ring2.png" - rotation: sensor ? sensor.rotationY : 0 - Behavior on rotation { - RotationAnimator { - easing.type: Easing.Linear - duration: rotationUpdateInterval - direction: RotationAnimator.Shortest + Image { + id: largeRing + anchors.centerIn: parent + source: pathPrefix + "Gyro/gyro_ring2.png" + rotation: sensor ? sensor.rotationY : 0 + Behavior on rotation { + RotationAnimator { + easing.type: Easing.Linear + duration: rotationUpdateInterval + direction: RotationAnimation.Shortest + } } } - } - Image { - id: mediumRing - anchors.centerIn: parent - source: pathPrefix + "Gyro/gyro_ring1.png" - rotation: sensor ? sensor.rotationZ : 0 - Behavior on rotation { - RotationAnimator { - easing.type: Easing.Linear - duration: rotationUpdateInterval - direction: RotationAnimator.Shortest + Image { + id: mediumRing + anchors.centerIn: parent + source: pathPrefix + "Gyro/gyro_ring1.png" + rotation: sensor ? sensor.rotationZ : 0 + Behavior on rotation { + RotationAnimator { + easing.type: Easing.Linear + duration: rotationUpdateInterval + direction: RotationAnimation.Shortest + } } } + Image { + id: centerRing + anchors.centerIn: parent + source: pathPrefix + "Gyro/gyro_center.png" + } } - Image { - id: centerRing - anchors.centerIn: parent - source: pathPrefix + "Gyro/gyro_center.png" + + Item { + id: connectingNote + + anchors.fill: parent + visible: sensorState === SensorTagData.Scanning || + sensorState === SensorTagData.Disconnected || + sensorState === SensorTagData.Error || + sensorState === SensorTagData.NotFound + + Column { + anchors.centerIn: parent + spacing: 20 + + BlinkingIcon { + id: sensorIcon + + source: pathPrefix + "Toolbar/icon_topbar_sensor.png" + anchors.horizontalCenter: parent.horizontalCenter + visible: sensorState === SensorTagData.Scanning + } + + Text { + id: stateText + + color: "white" + text: sensorState === SensorTagData.Scanning ? "Connecting to sensor..." + : sensorState === SensorTagData.Disconnected ? "Disconnected" + : sensorState === SensorTagData.NotFound ? "Device not found" + : "" + } + } } } diff --git a/tradeshow/iot-sensortag/resources/base/SensorSettings.qml b/tradeshow/iot-sensortag/resources/base/SensorSettings.qml index a2a8202..5aace2c 100644 --- a/tradeshow/iot-sensortag/resources/base/SensorSettings.qml +++ b/tradeshow/iot-sensortag/resources/base/SensorSettings.qml @@ -57,8 +57,8 @@ Rectangle { property alias listModelCount: list.count - width: 360 - height: 252 + width: 620 + height: 480 color: "black" Text { @@ -73,68 +73,129 @@ Rectangle { Image { id: icon - width: 60 - height: 60 + anchors.top: titleText.bottom anchors.horizontalCenter: parent.horizontalCenter anchors.margins: 8 source: pathPrefix + "Toolbar/icon_topbar_sensor.png" - - MouseArea { - anchors.fill: parent - onClicked: dataProviderPool.startScanning() - } } ListView { id: list anchors.top: icon.bottom anchors.topMargin: 16 - height: 150 - width: parent.width - clip: true + anchors.left: parent.left + anchors.leftMargin: 30 + anchors.right: parent.right + anchors.rightMargin: 30 orientation: ListView.Horizontal model: dataProviderPool.dataProviders + height: parent.height + clip: true + snapMode: ListView.SnapToItem + boundsBehavior: Flickable.StopAtBounds + + function getTagTypeStr(tagType) { + var tagStr = ""; + if (tagType & SensorTagData.AmbientTemperature) + tagStr += "Ambient Temperature\n"; + if (tagType & SensorTagData.ObjectTemperature) + tagStr += "Object Temperature\n"; + if (tagType & SensorTagData.Humidity) + tagStr += "Humidity\n"; + if (tagType & SensorTagData.Altitude) + tagStr += "Altitude\n"; + if (tagType & SensorTagData.Light) + tagStr += "Light\n"; + if (tagType & SensorTagData.Rotation) + tagStr += "Gyroscope\n"; + if (tagType & SensorTagData.Magnetometer) + tagStr += "Magnetometer\n"; + if (tagType & SensorTagData.Accelometer) + tagStr += "Accelometer\n"; + + return tagStr; + } delegate: Item { id: listItem width: mainRect.width / 3 + height: childrenRect.height + ColumnLayout { spacing: 8 - Item { - width: listItem.width - height: 40 - Text { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 4 - horizontalAlignment: Text.AlignHCenter - text: providerId.toUpperCase() - color: "white" - font.pixelSize: 16 - elide: Text.ElideMiddle - clip: true - } + + Text { + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + horizontalAlignment: Text.AlignHCenter + text: providerId + color: "white" + font.pixelSize: 16 + elide: Text.ElideMiddle } - Image { - Layout.alignment: Qt.AlignHCenter - width: 40 - height: 40 + + BlinkingIcon { + id: sensorIcon + + property bool canBlink: modelData.state === SensorTagData.Scanning + + onCanBlinkChanged: { + if (canBlink) + sensorIcon.startBlinking(); + else + sensorIcon.stopBlinking(); + } + source: pathPrefix + "Toolbar/icon_topbar_sensor.png" - opacity: (modelData.state === SensorTagData.Connected - || modelData.state === SensorTagData.Scanning) ? 1 : 0.5 + anchors.horizontalCenter: parent.horizontalCenter + + Component.onDestruction: { + sensorIcon.stopBlinking() + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (modelData.state === SensorTagData.Connected) + dataProviderPool.disconnectProvider(modelData.providerId); + else if (modelData.state === SensorTagData.NotFound) + dataProviderPool.startScanning(); + else if (modelData.state === SensorTagData.Scanning) + dataProviderPool.disconnectProvider(modelData.providerId) + else + modelData.startServiceScan(); + } + } } Text { Layout.alignment: Qt.AlignHCenter - text: modelData.state === SensorTagData.Disconnected ? "Disconnected" - : (modelData.state === SensorTagData.Scanning) ? "Scanning" - : (modelData.state === SensorTagData.Connected) ? "Connected" + text: modelData.state === SensorTagData.NotFound ? "\nNOT FOUND" + : (modelData.state === SensorTagData.Disconnected) ? "\nDISCONNECTED" + : (modelData.state === SensorTagData.Scanning) ? "\nCONNECTING" + : (modelData.state === SensorTagData.Connected) ? "\nCONNECTED" : "Error" color: "white" font.pixelSize: 14 } + + Item { + height: 30 + width: 10 + } + + Text { + color: "white" + text: "Provides data for:" + } + + Text { + color: "white" + lineHeight: 0.7 + text: list.getTagTypeStr(modelData.tagType()) + } } } } diff --git a/tradeshow/iot-sensortag/resources/base/main.qml b/tradeshow/iot-sensortag/resources/base/main.qml index c55d8ee..2840433 100644 --- a/tradeshow/iot-sensortag/resources/base/main.qml +++ b/tradeshow/iot-sensortag/resources/base/main.qml @@ -58,6 +58,7 @@ Window { property alias contentFile: contentLoader.source property DataProviderPool dataProviderPool property SeriesStorage seriesStorage + property real globalBlinkOpacity: 1.0 // Size defaults to the small display width: 1920 @@ -76,4 +77,40 @@ Window { anchors.fill: parent anchors.centerIn: parent } + + + + function startBlink() { + flash.blinkers++; + } + + function stopBlink() { + flash.blinkers--; + } + + // Animation to allow synchronized + // blinking of BlinkingIcons + SequentialAnimation { + id: flash + + property int blinkers: 0 + + running: blinkers + loops: Animation.Infinite + alwaysRunToEnd: true + + PropertyAnimation { + target: mainWindow + property: "globalBlinkOpacity" + to: 0.3 + duration: 700 + } + + PropertyAnimation { + target: mainWindow + property: "globalBlinkOpacity" + to: 1 + duration: 700 + } + } } diff --git a/tradeshow/iot-sensortag/resources/small/MainSmall.qml b/tradeshow/iot-sensortag/resources/small/MainSmall.qml index df4a868..83835e3 100644 --- a/tradeshow/iot-sensortag/resources/small/MainSmall.qml +++ b/tradeshow/iot-sensortag/resources/small/MainSmall.qml @@ -54,25 +54,31 @@ import "../base" Item { id: main + function startRescan(sensor) { + if (sensor.state === SensorTagData.NotFound) + dataProviderPool.startScanning(); + else if (sensor.state === SensorTagData.Scanning) + dataProviderPool.disconnectProvider(sensor.providerId) + else if (sensor.state !== SensorTagData.Connected) + sensor.startServiceScan(); + } + anchors.fill: parent Component.onCompleted: { - dataProviderPool.startScanning() - } - - Connections { - target: dataProviderPool - onScanFinished: { - ambientTemp.sensor = dataProviderPool.getProvider(SensorTagData.AmbientTemperature); - objectTemp.sensor = dataProviderPool.getProvider(SensorTagData.ObjectTemperature); - humidity.sensor = dataProviderPool.getProvider(SensorTagData.Humidity); - airPressure.sensor = dataProviderPool.getProvider(SensorTagData.AirPressure); - light.sensor = dataProviderPool.getProvider(SensorTagData.Light); - magnetometer.sensor = dataProviderPool.getProvider(SensorTagData.Magnetometer); - rotation.sensor = dataProviderPool.getProvider(SensorTagData.Rotation); - accelometer.sensor = dataProviderPool.getProvider(SensorTagData.Accelometer); - rotationMain.sensor = dataProviderPool.getProvider(SensorTagData.Rotation); - } + dataProviderPool.startScanning(); + + // UI gets information about the intended setup of the + // sensor even though they have not been really discovered yet + ambientTemp.sensor = dataProviderPool.getProvider(SensorTagData.AmbientTemperature); + objectTemp.sensor = dataProviderPool.getProvider(SensorTagData.ObjectTemperature); + humidity.sensor = dataProviderPool.getProvider(SensorTagData.Humidity); + airPressure.sensor = dataProviderPool.getProvider(SensorTagData.AirPressure); + light.sensor = dataProviderPool.getProvider(SensorTagData.Light); + magnetometer.sensor = dataProviderPool.getProvider(SensorTagData.Magnetometer); + rotation.sensor = dataProviderPool.getProvider(SensorTagData.Rotation); + accelometer.sensor = dataProviderPool.getProvider(SensorTagData.Accelometer); + rotationMain.sensor = dataProviderPool.getProvider(SensorTagData.Rotation); } Column { @@ -92,6 +98,7 @@ Item { width: leftPane.width height: leftPane.indicatorHeight + onClicked: main.startRescan(sensor) } ObjectTemperatureChart { @@ -99,6 +106,7 @@ Item { width: leftPane.width height: leftPane.indicatorHeight + onClicked: main.startRescan(sensor) } HumidityChart { @@ -106,6 +114,7 @@ Item { width: leftPane.width height: leftPane.indicatorHeight + onClicked: main.startRescan(sensor) } AltitudeChart { @@ -113,6 +122,7 @@ Item { width: leftPane.width height: leftPane.indicatorHeight + onClicked: main.startRescan(sensor) } } @@ -131,6 +141,7 @@ Item { width: rightPane.width height: rightPane.height / 4 + onClicked: main.startRescan(sensor) } MagnetometerChart { @@ -138,6 +149,7 @@ Item { width: rightPane.width height: rightPane.height * 0.3 - 30 + onClicked: main.startRescan(sensor) } GyroChart { @@ -145,6 +157,7 @@ Item { width: rightPane.width height: rightPane.height * 0.3 - 60 + onClicked: main.startRescan(sensor) } AccelChart { @@ -152,6 +165,7 @@ Item { width: rightPane.width height: rightPane.height - light.height - magnetometer.height - rotation.height - 3 * rightPane.spacing + onClicked: main.startRescan(sensor) } } @@ -167,7 +181,6 @@ Item { onSensorChanged: if (sensor) sensor.recalibrate() } - TopToolbar { id: topToolbar |