The previous tutorial explained how to trigger a method when a device emits a signal and control another device within that method. We can also avoid the intermediate step and connect a signal directly to the input (or slot) of a device.
Let's cover the basics of forming a direct device-to-device connection.
As we learned already, we can connect a signal containing a known set of argument types to any custom method that takes as inputs the same number and types of arguments. Similarly, any signal that we can connect to a custom method can also be connected to a device's method, assuming the same criteria are met.
Remember the light actuator from the previous example:
If we wanted to connect the stateChanged signal to this device, we would not be able to connect it to the turnOn() method which we used in the previous example. This is because the signal arguments don't match the slot's arguments. Observe, however, that this device has a setState(bool) slot/method. This slot's set of input arguments matches the set of arguments in the setState signal. We can, therefore, connect them directly together.
This can be achieved in code by:
This example shows a connection to a custom method, which we used in the previous example and compares it to a device-to-device connection. The only real difference is that for a custom method defined in this app we prepend the method name with self. whereas for a method/slot in another device, we prepend the method/slot with deviceReferenceVariable. .
This code will turn on the light every time the door opens and turn off the light every time the door closes. It will also call the custom method self.onSensorStateChanged(bool) when the door either opens or closes.
When we use device-to-device connections we also have to remember to disconnect the connections we created when the app stops. Previously, when we connected a device signal to a custom method, the signal was automatically disconnected and the functionality was disabled when the app was stopped. However, when our app connects a signal from one device directly to a slot in another device, that connection will continue to exist, even after the app which created the connection is stopped.
Hence, whenever we create a device-to-device connection in our app, we must explicitly put a corresponding disconnection in the stop() method of the app. Otherwise the connection will persist after the app has stopped, causing inexplicable behaviour for the user.
The syntax for a disconnection is identical to that for a connection, except we replace the 'connect' with 'disconnect'. For example:
It is important to note here that we had to keep instance variables for the devices so that they were available for disconnection in the stop() method.
To cement our understanding thus far, let's write another app.
We want to write an app that:
We could achieve this without using device-to-device connections, but it would require more code. Use device-to-device connections for this example to make the code as concise as possible.
Note: if your app is giving unexpected behaviour, look in the App Drawer and make sure there aren't other apps running at the same time. It is always a good idea to stop any other apps that are running when developing and testing your app.
When you want to compare with your solution, click Expand below.
The highlighted lines are the lines we've added to the skeleton app to achieve this functionality.
This tutorial has discussed how code can be simplified sometimes by connecting a device's signal directly to another device's slot. The next tutorial will explore how we can achieve different behaviour at different times of the day by using the clock object.