App Development Tutorial 2

Contents

Tutorial 2: Listening For Sensor Events

The previous tutorial introduced how to create and run apps in CHAOS. This section will progress into the real world and describe how to receive notifications from devices in the home environment and perform an action whenever the sensor fires.

This tutorial will cover:

  1. Getting a reference to the device we want to receive signals from.
  2. Discover what signals the device emits.
  3. Connect the signal to a custom method what we've written.
  4. Perform some action in the method.

Background

We will first cover the tools necessary to achieve the desired response. Since the run() method is executed when the app starts, this is where we will obtain a reference to a device and form a connection from this device's signal to a method, which we shall also define.

Obtain Reference to Device

The first step in receiving events from a device is to retrieve the object which represents the device. All CHAOS apps have access to a list of all the devices detected in the home. This list is referred to as self.deviceList. The simplest approach to retrieve a device is to use the getDevice("...") method. This method, when called on a deviceList, will return the single device which has the name specified in the string argument.

Hence, to obtain a reference to a device using this method, we must first know the name of the device we wish to retrieve. To do this we need to go to the Home Simulator. Observe that every device on the home map has a '?' attached to it:

MotionSensorTooltipLocation.png

These '?' icons are called tooltips. Each tooltip contains things like the device name, the function of the device, how to interact with the device and examples of such a device. If we click the tooltip for the device on the upper-left of the home simulator it expands to give:

MotionSensorTooltip.png

We can see from the tooltip that this device's ID is 'livingRoomMotionSensor'. Armed with this knowledge, we can now retrieve a reference to this device using the code:

motionSensor = self.deviceList.getDevice("livingRoomMotionSensor")

Note: In a real deployment the names of devices can vary, depending on the specific home. In such real deployments, retrieving the device ID will be more dynamic, but for demonstration purposes retrieving the device ID from the map will suffice. There are also methods to retrieve all devices in the home of a specific type, which will be covered in later tutorials.

Discover the Device's Signals

Now that we can obtain a reference to a device, we must ascertain which signals from the device we wish to intercept. If we scroll down on the deivce's tooltip we will see a section called "Signals". This section lists all the signals which this type of device can emit:

MotionSensorTooltipShowingSignals.png

We can see that the motion sensor emits one signal; motionDetected(). This signal is emitted when motion is detected in front of the sensor in a real home or when the motion sensor is clicked in the simulated home.

Connect Signal to Our Method

Before we can make use of a device's signal we must first understand what a signals is. The CHAOS platform utilises the Qt framework, which is a framework that enables responsive UI design. Key to Qt's responsiveness is it's Signals and Slots mechanism. An object can emit a signal at any time when an event occurs. We can connect a signal to a slot, to trigger some functionality in that slot when the signal is emitted. A slot is like a traditional method, but it can also receive signals. Hence, we can cause functionality in one object's slot trigger when a signal in another object is emitted, provided we have defined a connection from the signal to the slot.

For a more precise and extensive explanation of signals and slots please refer to: Signals and Slots | Documentation | Qt Project.

Returning to our example, we have an object which we called motionSensor which emits a signal motionDetected and we want to connect it to method which we shall call onMotionDetected(). The code to create this connection is:

motionSensor.motionDetected.connect(self.onMotionDetected)

Thus, when motion is detected, the onMotionDetected method or slot will be called.

Define Custom Method

The one outstanding issue we have, however, is that onMotionDetected does not exist yet. We can define onMotionDetected anywhere in our code just like we would a regular method:

def onMotionDetected(self):
    self.print("Motion Detected")

As you can probably guess, that this code simply outputs the string "Motion Detected" to the debug console when it's connected signal is emits.

The App

Putting together everything we've discussed so far, we can write an app which outputs "Motion Detected" when the chosen motion sensor triggers. First we will outline how the app can be tested and the expected response and let you write the app to get the desired response for yourself.

Objective

To simulate a motion sensor detecting motion and firing, we merely click the motion sensor icon in the CHAOS simulated home:

MotionSensorUnfired.png

When the motion sensor fires, the icon will change to:

MotionSensorFired.png

until the motion sensor resets. The motion sensor cannot fire again until it resets.

We want our app to produce the following output when we click the motion sensor:

MotionSensorAppDebugConsole.png

Solution

If you are feeling confident, try to achieve this functionality for yourself. If you are having trouble or want to compare your result, have a look at the example solution below.

Example Solution:

from __future__ import print_function
from ChaosApps import BaseChaosApp

class ChaosApp(BaseChaosApp):
        def run(self):
                self.appName='tutorial 2'
                self.print("Skeleton App '"+self.appName+"' Running")

                #Connect devices to other devices and functions here...
               
                motionSensor = self.deviceList.getDevice("livingRoomMotionSensor")
                motionSensor.motionDetected.connect(self.onMotionDetected)
               
        def onMotionDetected(self):
                self.print("Motion Detected")

        def initAppGui(self):
                self.print("'" + self.appName + "': CHAOS has asked for the current HTML of the phone app GUI for this CHAOS App")

                htmlString = """appGuiConstructionString"""

                return htmlString

        def appGuiInteractionCallback(self,someData):
                self.print(self.appName + ": Some information has arrived for this CHAOS App from the phone GUI ")

        def stop(self):
                self.print("Disconnecting any created signals and then stopping '" + self.appName + "'")

The highlighted lines are the only lines we've added to the skeleton app to achieve this functionality.

Wrap Up

This tutorial has introduced how to obtain a reference to a device and connect signals from that device to some custom functionality. The next tutorial shall explore the reception of more complicated signals from devices and how to use these signals as triggers to control other devices.

<< - <Prev - Next>