Page 1 of 3 Most devices are complex with more than one function. To cope with these we need to build compound devices. In this extract from a new book on using GPIO Zero on the Pi in Python we look at how to get started.
Raspberry Pi IoT In Python Using GPIO Zero Second Edition
By Harry Fairhead & Mike James
Buy from Amazon.
Contents
- Why Pi for IoT?
- Getting Started With Python And GPIO Zero
- Introduction to the GPIO
- Python - Class and Object
- Simple On/Off Devices
Extract 1: On/Off Devices *
- Pins And Pin Factories
Extract 1: Pins
- Some Electronics
- Simple Input
Extract 1:Getting Input ***NEW!!
- Complex Input Devices
Extract 1: Complex Input *
- Pulse Width Modulation
Extract 1: PWM*
- Controlling Motors And Servos
Extract 1: DC Motors *
- Working With Compound Devices
Extract 1: Compound Devices*
- The SPI Bus
- Custom SPI Devices
- Using The Lgpio Library
- Appendix Visual Studio Code Remote Python
*Extracts from first edition - will be updated.
<ASIN:1871962870>
You might well start off with a single GPIO line flashing an LED, but slowly and surely you will graduate to more elaborate devices such as a robot that consists of a number of flashing LED, motors and so on. If what you have created is a development on an existing device then you might create a new custom class using inheritance and we have seen examples of this in earlier chapters. For example, when we wanted to implement a door lock class, the obvious way was to create a new class that inherited from the existing LED class. The reason is that both the LED and lock share a basic on/off behavior, but in the case of the lock it is better called “lock/unlock”.
Compare this to the problem of building a custom class to control three or more separate LEDs. In this case you don’t need to inherit the behavior of a single LED, you need multiple instances of the LED class. In this case what you need is composition, i.e. combining classes, rather than inheritance. GPIO Zero has a class that you can use to create composite devices and this chapter looks at how this works in enough detail for you to create your own.
Devices That Contain Devices
The CompositeDevice class is intended to be inherited by your custom classes to make it easy to include instances of other classes but first it makes sense to see how to do the job without help.
If you were implementing a composite device from scratch then the logical thing to do is to create a tuple, list or dictionary of the instances you need. For example if you wanted to create a custom TriLED class, you might write in the constructor something like:
self.LEDs=(LED(pin1),LED(pin2),LED(pin3))
After this you would write methods that are required using the tuple to access the LEDs.
For example, you might want an AllOn and AllOff method:
from gpiozero import LED
from time import sleep
class TriLED():
def __init__(self, pin1=None,pin2=None,pin3=None):
self.LEDs=(LED(pin1),LED(pin2),LED(pin3))
def AllOn(self):
self.LEDs[0].on()
self.LEDs[1].on()
self.LEDs[2].on()
def AllOff(self):
self.LEDs[0].off()
self.LEDs[1].off()
self.LEDs[2].off()
A program to make use of the new class would be something like:
leds=TriLED(4,17,27)
while True:
leds.AllOn()
sleep(0.001)
leds.AllOff()
sleep(0.001)
Of course, in a real TriLED application you might have methods for set patterns – rotate left, rotate right and so on, but the general idea is the same.
The CompositeDevice Class
The CompositeDevice class is designed to help with this general pattern of using a tuple of devices. You add the devices in the constructor and you can add them as unnamed members of a tuple or as named attributes. The difference is that named attributes make it easier to access the sub-devices from the outside world. If you specify a device as a positional parameter, then it is added to a tuple. If you specify a device as a named parameter then attributes with the same name are added. The only slight mystery is how do you access the tuple of devices? The answer is that the CompositeDevice class itself behaves like a tuple and you can access its contents in the usual way. It doesn’t achieve this by inheritance. Instead it overrides the __getitem__ magic method which is called when you use indexing.
For example:
compdev=CompositeDevice(LED(pin1),LED(pin2))
compdev[1].on()
turns on the LED on pin2.
Named parameters are easier to understand:
compdev=CompositeDevice(led1=LED(pin1),led2=LED(pin2))
compdev.led2.on()
You should use the first approach for devices that are used internally and the second if you want to allow outside access to the component devices.
Of course, if you are creating a custom class for some device then a better idea is to inherit from CompositeDevice rather than create an instance so that your custom class inherits the same behavior.
|