Pi IoT In Python Using GPIO Zero - On/Off Devices
Written by Harry Fairhead & Mike James   
Monday, 14 December 2020
Article Index
Pi IoT In Python Using GPIO Zero - On/Off Devices
Buzzer & Custom Device

Buzzer

The only other standard on/off device is the Buzzer and it goes on and off in the sense that it is driven by a single GPIO line, just like an LED, and makes a sound when the line is high and is silent when the line is low. It isn’t capable of making different tones, it is either on or off.
The exact type of buzzer is a piezoelectric buzzer which emits a single tone and can be very loud:

buzzer1

You don’t need a current-limiting resistor as piezo buzzers take very little current. All you have to do is to make sure that will operate at 3 volts. All you have to do to use one is connect the negative lead to ground and the positive lead to a GPIO line:

 

buzzer2

The Buzzer object has all of the properties and methods of the LED object. The on and off methods now make the buzzer sound but work in exactly the same way. The one small change is that blink is now renamed beep. It works in exactly the same way but now the buzzer is switched on and off.

from gpiozero import Buzzer
from signal import pause
buzz = Buzzer(4)
buzz.beep(on_time=1,off_time=1,n=100)
print("Program Complete")
pause()

You can see quite clearly that creating a Buzzer class is more about renaming things, so that your program can be more understandable, than introducing anything new.

A Custom On/Off Device

There are lots of on/off devices other than LED and Buzzer, so how do you arrange to work with them?

One solution is to treat everything as if it was an LED. For example, if you have an electric door lock you could write:

lock=LED(4)
lock.on()
…
lock.off()

It would work, but it might be confusing in the future when you have forgotten the program and are forced to wonder what an LED is doing with a lock and what lock.on() means.

A better and simpler solution is to derive a custom on/off device. You can do this using inheritance from DigitalOutputDevice which provides nearly all of the methods that LED has – in particular it has on and off methods. In this case we can simply pass the constructor parameters to the constructor of DigitalOutputDevice:

class Lock(DigitalOutputDevice):
    def __init__(self,*args,**kwargs):
        super().__init__(*args,**kwargs)        

At this point Lock is really just a copy of DigitalOutputDevice and to customize it to be a Lock class we need to add appropriate methods. What we really need are two new methods, lock and unlock, and these can be implemented by calling the on and off methods of the super class:

def lock(self):
     super().on()
def unlock(self):
     super().off()

Now we have a Lock object that has lock and unlock methods that make sense for the device. However, we also still have on, off and blink which don’t make any sense.

The simplest solution is to override them with methods that raise an appropriate exception:

def on(self):
  raise AttributeError(
"'Lock' object has no attribute 'on'") def off(self): raise AttributeError(
"'Lock' object has no attribute 'off'") def blink(self): raise AttributeError(
"'Lock' object has no attribute 'blink'")

This stops the use of the method calls, but the inappropriate attributes are still accessible. That is:

lock.on()

results in an exception, but:

myOn=lock.on

works even if you can’t actually call the method. This is probably good enough for most use cases, but you could take it one step further by customizing the constructor. After all, you don’t want to allow active_high to be set to False and have lock mean unlock and vice versa.

You can check for any keyword parameter using something like:

def __init__(self,*args,**kwargs):
   if 'active_high' in kwargs:
      raise TypeError("active_high not supported")
   super().__init__(*args,**kwargs)  

If you would like a more specific error, you could define your own exception class.

You can carry on tailoring the behavior of Lock to be more lock-like until you have the perfect class. It is also a good idea to put your code into a module so that you can import Lock.

The complete program is:

from gpiozero import DigitalOutputDevice
class Lock(DigitalOutputDevice):
  def __init__(self,*args,**kwargs):
      if 'active_high' in kwargs:
          raise TypeError("active_high not supported")
      super().__init__(*args,**kwargs)            
  def lock(self):
      super().on()
  def unlock(self):
      super().off()
  def on(self):
      raise AttributeError(
"'Lock' object has no attribute 'on'") def off(self): raise AttributeError(
"'Lock' object has no attribute 'off'") def blink(self): raise AttributeError(
"'Lock' object has no attribute 'blink'")

Using Lock is trivial:

office_door=Lock(4)
office_door.lock()
…
office_door.unlock()

You can use the same ideas to implement a custom class for any on/off device you care to use. What is interesting is that in practice customizing an existing class using inheritance is often as much about changing and restricting what the class can do as it is about extending it, which is what textbooks always emphasize.

This completes the software and it is worth remarking that simple locks of this sort are the same hardware problem as driving a solenoid. As these mostly work with 6 or 12 volts you will need to use a transistor driver and you will need to take account of the voltage and the current involved. See the next chapter for more details.

Not in this extract:

  • Phased On/Off

 

Summary

  • There are only two simple on/off devices, LED and Buzzer. They both inherit from DigitalOutputDevice.

  • The blink method turns the device on and off a given number of times and can be run in the background while the program gets on with something else or in the foreground when your program will wait.

  • The toggle method turns the device on if it is off and off if it is on.

  • The Buzzer class is intended to be used with a piezo buzzer, which is either on or off and hence either emits a sound or remains silent. It can only make one tone, which cannot be varied.

  • A piezo buzzer doesn’t need a driver as it takes very little current.

  • You can create a custom on/off device by inheriting from DigitalOutputDevice and providing the additional methods that are required. Restricting access to any existing inappropriate methods is a more difficult task.

  • You can switch multiple on/off devices at the same time or at coordinated times, but there is always a lag between switching devices - 140µs for a Pi Zero and 10µs for a Pi 4.

 

Raspberry Pi IoT In Python Using GPIO Zero

By Harry Fairhead & Mike James

pyIoT360cover

Buy from Amazon.

Contents

  1. Why Pi for IoT?
  2. Getting Started With Python And GPIO Zero
  3. Introduction to the GPIO
  4. Python - Class and Object
  5. Simple On/Off Devices
      Extract 1: On/Off Devices 
  6. Pins And Pin Factories
  7. Some Electronics
  8. Simple Input
  9. Complex Input Devices
      Extract 1: Complex Input 
  10. Pulse Width Modulation
      Extract 1:  PWM ***NEW!!!
  11. Controlling Motors And Servos
      Extract 1: DC Motors 
  12. Working With Compound Devices
      Extract 1: Compound Devices 
  13. The SPI Bus
  14. Custom SPI Devices
  15. Appendix Visual Studio Code Remote Python

 <ASIN:1871962668>

<ASIN:B08NZ2QP41>

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

Banner


Apache Ignite Changes SQL Engine
05/05/2022

Apache Ignite has been updated to use a new SQL engine based on Apache Calcite, and new 'read repair' strategies.



Racket Improves Load Speeds
03/05/2022

Racket has been updated with improvements including a flag to improve load speeds and extensions to the use of Racket 'Chez Scheme' (CS).


More News

pythondata

 



 

Comments




or email your comment to: comments@i-programmer.info

 

 



Last Updated ( Monday, 14 December 2020 )