How to use interrupts with Python on the Raspberry Pi and RPi.GPIO – part 2

http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-2

Mar202013

 

Circuit for second interrupt experiment

Interrupts are an efficient way for a program to be able to respond immediately to a specific event. In the previous article I explained the basics of using interrupts in RPi.GPIO and gave an example of a simple “wait for an event” interrupt program.

In this second article I will introduce “threaded callback” which opens up a lot of new possibilities.

Threaded callback – what the heck is that?

I know it sounds complicated. And it probably is complicated in the C code it’s written in, but we’re Pythonites and we don’t have to go there. ;)

If you remember the previous example program was just a simple “wait for port 23 to be connected to GND when we press the button and then print a message and exit the program”.

So, while it was waiting, the program wasn’t doing anything else. The program only had one thread, which means only one thing was being done at once. Python is capable of running more than one thread at once. It’s called multi-threading. It means that you can go through more than one piece of code simultaneously. This is where we can reap the benefit of interrupts because we can do something else while we wait for our “event” to happen. (Just like your “postman detector” allowed you to get on with something else instead of being distracted by waiting for the mail.)

So that covers the threading part of threaded callback. What’s a callback?
When an event is detected in the second thread, it communicates this back to the main thread (calls back). What we now have in RPi.GPIO is the ability to start a new thread for an interrupt and specify a set of instructions (function) that will run when the interrupt occurs in the second thread. This is a threaded callback function.

This is like your “postman detector” giving you a list of reminders of things you wanted to do when your delivery arrives AND doing them for you, so you can carry on with what you want to be doing.

So What are we going to do now?

We’ll keep most of what we did before and add another button and an event detect threaded callback that runs when the new button is pressed, even though we are still waiting for the first button to be pressed.

But this time, the new button will connect GPIO port 24 to 3.3V (3V3) when pressed. This will allow us to demonstrate a rising edge detection. So we’ll be setting up port 24 with the built in pulldown resistor enabled.

Circuit for second interrupt experiment

Later on we’ll have to modify the code to cope with ‘button bounce’, but we won’t say any more about that just yet.

Do you need to update RPi.GPIO?

If you didn’t do it for the first example, you will quite likely need to update your RPi.GPIO package. You can check what version of RPi.GPIO you have in the command line with…

sudo python
import RPi.GPIO as GPIO
GPIO.VERSION

This should show you what RPi.GPIO version you have. You need 0.5.2a or higher for this example.
You can exit the python environment with CTRL+Z

Install RPi.GPIO version 0.5.2 for simple interrupts

If you need to, you can install 0.5.2 or later with
sudo apt-get update
sudo apt-get dist-upgrade
 (This will update all your Raspbian packages and may take up to an hour)

or, from the command line prompt (this will only update RPi.GPIO)…
wget http://raspberry-gpio-python.googlecode.com/files/python-rpi.gpio_0.5.2a-1_armhf.deb
wget http://raspberry-gpio-python.googlecode.com/files/python3-rpi.gpio_0.5.2a-1_armhf.deb
sudo dpkg -i python-rpi.gpio_0.5.2a-1_armhf.deb
sudo dpkg -i python3-rpi.gpio_0.5.2a-1_armhf.deb

And now onto the code

I’ve put most of the explanation in the code, so that if you use it, you will still have it.

  1. #!/usr/bin/env python2.7
  2. # script by Alex Eames http://RasPi.tv
  3. import RPi.GPIO as GPIO
  4. GPIO.setmode(GPIO.BCM)
  5. # GPIO 23 & 24 set up as inputs. One pulled up, the other down.
  6. # 23 will go to GND when button pressed and 24 will go to 3V3 (3.3V)
  7. # this enables us to demonstrate both rising and falling edge detection
  8. GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  9. GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
  10. # now we’ll define the threaded callback function
  11. # this will run in another thread when our event is detected
  12. def my_callback(channel):
  13.     print ”Rising edge detected on port 24 - even though, in the main thread,”
  14.     print ”we are still waiting for a falling edge - how cool?\n”
  15. print ”Make sure you have a button connected so that when pressed”
  16. print ”it will connect GPIO port 23 (pin 16) to GND (pin 6)\n”
  17. print ”You will also need a second button connected so that when pressed”
  18. print ”it will connect GPIO port 24 (pin 18) to 3V3 (pin 1)”
  19. raw_input(“Press Enter when ready\n>”)
  20. # The GPIO.add_event_detect() line below set things up so that
  21. # when a rising edge is detected on port 24, regardless of whatever
  22. # else is happening in the program, the function ”my_callback” will be run
  23. # It will happen even while the program is waiting for
  24. # a falling edge on the other button.
  25. GPIO.add_event_detect(24, GPIO.RISING, callback=my_callback)
  26. try:
  27.     print ”Waiting for falling edge on port 23″
  28.     GPIO.wait_for_edge(23, GPIO.FALLING)
  29.     print ”Falling edge detected. Here endeth the second lesson.”
  30. except KeyboardInterrupt:
  31.     GPIO.cleanup()       # clean up GPIO on CTRL+C exit
  32. GPIO.cleanup()           # clean up GPIO on normal exit

Two ways to get the above code on your Pi

If you are in the command line on your Pi, type…
nano interrupt2.py
Then click “copy to clipboard” (above) and paste into the nano window. Then
CTRL+O
Enter
CTRL+X

Alternatively, you can download this directly to your Pi using…
wget http://raspi.tv/download/interrupt2.py.gz
gunzip interrupt2.py.gz

Then you can run it with…
sudo python interrupt2.py

What’s supposed to happen?

When you run the code it gives you a message “Waiting for falling edge on port 23″
If you press button 1, it will terminate the program as before and give you a message
“Falling edge detected.”

If, instead of button 1, you press button 2, you’ll get a message
“Rising edge detected on port 24″.

This will occur as many times as you press the button. The program is still waiting for the original falling edge on port 23, and it won’t terminate until it gets it. Because your second button press is detected in another thread, it doesn’t affect the main thread.

You may also notice, depending on how cleanly you press the second button, that sometimes you get more than one message for just one button press. This is called “switch bounce”.

Bouncy, bouncy, bouncy

When you press a button switch, the springy contacts may flex and rapidly make and break contact one or more times. This may cause more than one edge detection to trigger, so you may get more than one message for one button press. There is, of course, a way round it, in software.

Why didn’t this happen before?

I hear you ask. The answer is simple. Last time the program was simply waiting for a single button press. As soon as that button press was detected, it stopped waiting. So if the switch bounced, it was ignored. The program had already moved on. In our case, it had closed. But, when the event detection is running constantly in another thread, this is not the case and we actually need to slow things down a bit in what is called “software debouncing”.

How to do software debouncing

In order to debounce, we need to be able to measure time intervals. To do that, we use the time module. Near the top of the program we need to add a line…

import time. I add it immediately after the RPi.GPIO import

  1. import RPi.GPIO as GPIO
  2. import time
  3. GPIO.setmode(GPIO.BCM)

Then, also quite near the top of the program we need to set an intial value for the variable time_stamp that we will use to measure time intervals

time_stamp = time.time() I put this after the GPIO.setup commands. This sets time_stamp equal to the time in seconds right now.

  1. GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)
  2. GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
  3. time_stamp = time.time()

Now we have to change our threaded callback function from

  1. def my_callback(channel):
  2.     print ”Rising edge detected on port 24 - even though, in the main thread,”
  3.     print ”we are still waiting for a falling edge - how cool?\n”

to..

  1. def my_callback(channel):
  2.     global time_stamp       # put in to debounce
  3.     time_now = time.time()
  4.     if (time_now - time_stamp) >= 0.3:
  5.         print ”Rising edge detected on port 24 - even though, in the main thread,”
  6.         print ”we are still waiting for a falling edge - how cool?\n”
  7.     time_stamp = time_now

And now, even if you deliberately press the button twice, as long as you do it within 0.3 seconds it will only register one button press. You have debounced the switch, by forcing the program to ignore a button press if it occurs less than 0.3 seconds after the previous one.

If you are IDLE (Python joke) you can get the amended code here…
wget http://raspi.tv/download/interrupt2a.py.gz
gunzip interrupt2a.py.gz

How does this work?

time_now = time.time() stores the current time in seconds in the variable time_now.
Now look at the last line of the function.
time_stamp = time_now This stores the time in seconds when the function was started in a global variable calledtime_stamp So next time this function is called, it will be able to check how much time has elapsed since the last time.

That’s what is happening in the if statement.
if (time_now - time_stamp) >= 0.3: In English this means “If more than 0.3 seconds has elapsed since the last button press, execute the code in the indented block”.

So if more than 0.3 seconds have elapsed it would print the message…
“Rising edge detected on port 24 – even though, in the main thread we are still waiting for a falling edge – how cool?”

If less than 0.3 seconds has elapsed, it will do nothing. Job done. Button switch is debounced.

Update – RPi.GPIO 0.5.2 onwards includes this debounce algorithm

Ben has included the above debounce algorithm in 0.5.2 onwards. This article was originally written for 0.5.1. So the above debounce code has been superseded by adding bouncetime=xxx, where xxx is a time in milliseconds. e.g.

GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200)

I will update the next example to reflect this.

So, what’s next?

  1. We’ve learnt about simple “wait for” interrupts in the previous article
  2. We’ve covered threaded callback in this article.
  3. In the next article, we’ll go over the situation where you want to do more than one threaded callback interrupt at once.

If you can’t wait for the next article (coming soon to a blog near you) check out the documentation here and press on by yourself.

I hope you are enjoying this series. Click here for Part 3.

Share this:

 71 Responses to “How to use interrupts with Python on the Raspberry Pi and RPi.GPIO – part 2”

  1. [...] button press” interrupt. There’s a lot more you can do with them, as I will show you in the next article, which will cover “threaded callback”, which allows us to use the spare capacity we’ve freed up by not polling [...]

  2. This is absolutely excellent. I can see a lot of applications for this in remote control motor projects where you want to respond to, say Forward and Left at the same time. Nicely explained :-)

    • Cheers Mike. Yes it opens up the possibilities quite radically doesn’t it? Of course, you can do all that with polling, but with the Pi we want as much efficiency as we can get.

  3. Bonus question for extra credit. Can anyone tell me why I chose those ports?

    • Internal pull-up and pull-down Resistors

      • Good guess, but not the reason. I think all the GPIO have them actually (although the i2c ports have them permanently).

    • Hallo Alex,

      on the Gertboard ports 25 24 23 working together with S1, S2 and S3.

      I thank you so much for this tutorial and so may other hints and tipps.
      Your English is perfect understandable to me and all is so logical and easy to follow, a very good teacher!

      Regards Olaf

      • Another very good guess, but not the reason I chose them. ;) I didn’t use the Gertboard for this particular experiment. Thank you for your kind words. :)

    • I like to use those 2 pins because there is a ground next to each of them. Plus they are right in front the way I have my RPi facing. By default they are not used for any of the communication interfaces, either.

      • That’s pretty much it Marv – well done. :)

        For this test I used button switches scavenged from an old PC (same as in my reset switch video). Each switch is wired to a 2 pin female connector, so it makes it really easy to pick pins on the GPIO header that have a GND next to them (and aren’t used for anything else significant).

        • Andrew Scheller says:

          I guess that would be more obvious if the fritzing diagram actually showed what all the pins were connected to, rather than listing a bunch of them as “–” :-/

          Yeah, I know it’s because they were originally DoNotConnect pins, but that hasn’t been the case now for a long time.
          http://elinux.org/RPi_Low-level_peripherals

          • It’s worse than that Andrew, the Fritzing Pi model won’t allow connection to those pins so I had no choice. It wasn’t meant to be an easy one and I’m surprised anyone got it. :) Well done Marv.

  4. OK I know,

    It’s because in Fritzing the blue wire looked better horizontal if the yellow was horizontal it would have been CS0 which was no good so you picked the next one to the blue one. :-)

    Now tell me am I right

    • Nope. The Fritzing circuit was done afterwards. OK I’ll give you guys a (not very big) clue. The answer lies on the 26 GPIO pins themselves.

  5. I’ve got an LED hooked up to pin 25, a button to pin 24, and another button to pin 23 (all through the Gertboard). I run the following code:


    cleanup()
    gpio.setmode(gpio.BCM)
    gpio.setup(25,gpio.OUT)
    gpio.setup(24,gpio.IN,pull_up_down=gpio.PUD_UP)
    gpio.setup(23,gpio.IN,pull_up_down=gpio.PUD_UP)

    def buttonRising():
    gpio.output(25,gpio.HIGH)
    time.sleep(1)
    gpio.output(25,gpio.LOW)
    print(“buttonRising”)

    gpio.add_event_detect(24,gpio.RISING, callback=buttonRising)

    while True:
    try:
    if gpio.input(23)==False:
    gpio.output(25,gpio.HIGH)
    else:
    gpio.output(25,gpio.LOW)
    except KeyboardInterrupt:
    gpio.cleanup()

    I hoping that when I press the button on 24 that the LED on 25 will light for a second. It does not. I am stumped as to why this wouldn’t work.

    I know I have the LED wired properly, because when I press the button on 23, the LED on 25 lights up, and when release the button on 23, the LED on 25 goes out.

    I know that I have the button on 24 wired properly because when I let go of the button, after a second pause, the message prints out.

    Any ideas on what I’m doing wrong?

    Thanks
    Rick

    • cleanup() at the top? GPIO.cleanup() only cleans up ports opened or used by THIS script. Putting it at the top does nothing.

      Your problem appears to be that you’re waiting for a rising edge on 24 but you’ve pulled port 24 high. If it’s already high it can’t rise. It may well work if you change it to falling (but I don’t know how it’s wired).

      Try it and see. :)

      • The cleanup is at the top because I forgot to remove it after I added the keyboardinterrupt exception catch. :)

        I know that the program is catching the rising button because of the print statement. It prints out the “buttonRising” each time I press and release the button (sometimes more than once). The sleep even happens (there’s a second pause before the “buttonRising” appears. So I know it’s going into the callback code. It’s just not lighting the LED.

      • I played with my code, a lot. Changing various settings, and finally got it to work.


        import RPi.GPIO as gpio
        import time

        gpio.setmode(gpio.BCM)
        gpio.setup(25,gpio.OUT)
        gpio.setup(24,gpio.IN,pull_up_down=gpio.PUD_UP)
        gpio.setup(23,gpio.IN,pull_up_down=gpio.PUD_UP)

        def lightSecond():
        gpio.output(25,gpio.HIGH)
        time.sleep(1)
        gpio.output(25,gpio.LOW)

        def buttonRising():
        lightSecond()

        gpio.add_event_detect(24,gpio.RISING, callback=buttonRising)

        lightSecond()

        while True:
        try:
        if gpio.input(23)==False:
        lightSecond()
        except KeyboardInterrupt:
        gpio.cleanup()

  6. [...] out the second part of the series we shared last week, from Raspi.TV: Interrupts are an efficient way for a program to be able to respond immediately to a specific [...]

  7. Fascinating stuff! As a newbie, maybe you can help. Rather than printing to the screen, is there anyway to have the input added to an existing database to record the Time/Date and Duration of the button push?

    • Well you can certainly write the information to a file, but I haven’t delved into databases more complex than flat files in case you’re talking about MYSQL or something like that.

  8. Thanks again for this, Alex – my Picorder now switches to the next function without having to hold the button down :-)

  9. Thanks for the great tutorial! I have it up and running on my pi with great success. I have two questions I was hoping to get help with:

    1. Is there any way to detect whether it caught the rising or falling edge in the callback? I would like to either have a callback for falling and another for rising which doesnt seem to be allowed or to have one callback with an if statement to check for rising or falling

    2. Is there a way to extend this feature to other buttons? Specifically I would like to use the buttons on an I2C adafruit pi plate with lcd.

    Thanks again!
    Tim

    • AndrewS says:

      1. http://code.google.com/p/raspberry-gpio-python/source/browse/source/py_gpio.c#377 would seem to indicate you can’t have separate callbacks for RISING and FALLING on a single GPIO. I haven’t tested this, but couldn’t you add the callback for BOTH and then just check the current value of the GPIO inside the callback? If the GPIO is now high, it must have been a rising edge; if the GPIO is low it must have been a falling edge… ? *shrug*

      2. I guess edge-detection depends on the specifics of the I2C GPIO expander chip that’s being used – check the datasheet. But you won’t be able to use the specific library being used here, https://pypi.python.org/pypi/RPi.GPIO says “Note that the current release does not support SPI, I2C, hardware PWM or serial functionality on the RPi yet.”

      • Yes Andrew’s 1) above would surely work.

        And 2) there’s no native support for i2c in RPi.GPIO (although the chip you specified does have a driver in the forthcoming WiringPi 2)

      • Well sure I can check the GPIO Pin if you want to take the easy and efficient way :-) No idea why I didn’t think of that.

        BTW checking that pin allowed me to have the push and hold condition that I was looking for.

        Thanks AndrewS!

  10. Christos says:

    Thanks for the useful subjects you have in your blog!

    One observation though. I have spent quite some time trying to handle Ctrl+C properly but I couldn’t figure it out.
    Does handling CTRL+c in your code work fine ?
    In my case it doesn’t and I suspect after a few tests it’s because the the ctrl+c takes place while we are not in the try: part.

    For example when I try this from the console

    1. try:
    2.      user_input = input(“”)
    3.      print(“test”)
    4. except KeyboardInterrupt:
    5.      print(“\nbye!”)

    it works fine. I get the ‘Bye!’

    When I try the following from the console

    1. user_input = input(“”)
    2. try:
    3.      print(“test”)
    4. except KeyboardInterrupt:
    5.      print(“\nbye!”)

    it doesn’t handle the exception properly (I don’t get ‘bye!’ but an unhandled exception).

    I think I am hitting the second scenario with your code but not 100% sure

    Great stuff nonetheless!

    • You’re right, it’s because you are hitting CTRL+C before you get to the try: part.

      • Christos says:

        Ok for the record I was wrong. Everything looked well. The system was hanging withing the try: so it should have worked. Not sure why it doesn’t.
        After a bit of googling I added

        sys.stdin.read()

        in the try: part and it seems to work now. I don’t know why it doesn’t work with out it (the except part is not getting caught) but that’s more like a python question rather that RPi question. Seems like I am hitting something like the one described here

        http://stackoverflow.com/questions/4606942/why-cant-i-handle-a-keyboardinterrupt-in-python

        Just in case sbd else runs into the same issue

  11. Daniele says:

    Hi thanks a lot for his tutorial, i have a question, is possible to use the GPIO.wait_for_edge(23, GPIO.FALLING) in a while loop with other GPIO.wait_for_edge(24, GPIO.FALLING)?

    • I think you can only do one wait_for_edge in a thread. Wouldn’t you be better of using callbacks if you want more than one?

    • AndrewS says:

      Nope, wait_for_edge is a blocking function (i.e. no other code can run at the same time). That’s what the callback functions are for (AFAIK there’s no problem having separate callback functions on different GPIO pins). I guess you could even have a while loop that did nothing but sleep(1).

      • I think you can have as many callbacks as you want. It was a bit temperamental at first, but I think it’s nicely polished now. I haven’t tested it to a silly extent though. ;)

    • Daniele says:

      Thanks for the quick answer anyway i got it working with callbacks.. Here is the code if somebody need it:


      import RPi.GPIO as GPIO
      from time import sleep
      GPIO.setmode(GPIO.BOARD)

      GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_UP)
      GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)

      def Gate(channel):
      # Internal button, to open the gate
      print ‘Gate opened’;

      def Bell(channel):
      # External button, to ring the bell
      print ‘Bell rang’;

      GPIO.add_event_detect(19, GPIO.BOTH, callback=Gate, bouncetime=300)
      GPIO.add_event_detect(24, GPIO.BOTH, callback=Bell, bouncetime=300)

      while True:
      # Here everythink to loop normally
      sleep(60);

    • Daniele says:

      Well i can’t understand why but using this script when i turn on any light on my house it run the callback gate

      • AndrewS says:

        I’m afraid “it doesn’t work properly” is never a very helpful comment – you’ll need to provide full details of your hardware setup (what connections have you wired to which GPIOs, using which resistors, which pullup settings, which Pi model/revision, etc.), your software setup (source code to your full script, which version of RPi.GPIO, which version of Python, etc.), and anything else relevant.
        http://catb.org/~esr/faqs/smart-questions.html

        You could also try asking at http://www.raspberrypi.org/phpBB3/ – I don’t want to take anything away from Alex’s excellent blog, but there’s surely many more people reading the RaspberryPi Forums than read RasPI.TV

        • AndrewS says:

          Ahhh, by chance I’ve just spotted http://www.raspberrypi.org/phpBB3/viewtopic.php?t=50323 where you explain the problem in more detail (from your description here, I’d wondered if you had been connecting lights to your Pi).
          Sounds like your Pi is picking up electrical interference from the mains-spark caused when you toggle your light-switch. You might be able to eliminate the interference by using proper pull-up resistors in your circuit, instead of relying on the Pi’s internal pull-up resistors.
          http://raspi.tv/2013/rpi-gpio-basics-4-setting-up-rpi-gpio-numbering-systems-and-inputs

        • Yep – the Python section is the best place for RPi.GPIO type stuff. There’s a few people on there who know an awful lot about this sort of stuff. :)
          It’s where I go for help.

        • Daniele says:

          Thanks a lot for helping me, anyway i’m not sure to be able to use pull up resistor cause raspberry is far from the buttons and they are connected only to gnd and gpio.. There is no software way to eliminate this interference?

          I did a test using this code

          import RPi.GPIO as GPIO
          GPIO.setmode(GPIO.BOARD)
          GPIO.setup(19, GPIO.IN, pull_up_down=GPIO.PUD_UP)
          while True:
          if GPIO.input(19):
          print('1')
          else:
          print('0')

          And i got something like ten 1 and then ten 0 then ten 1 and again ten 0 and so on…

          • AndrewS says:

            Having long wires is a great way to pick up interference :-/ Unless your wires are shielded, they effectively act like aerials, so the longer the wire the more interference you’ll pick up. And this is just about where my knowledge on this subject runs out…
            No, there’s no way to “fix this in software”.

          • Can’t the resistors go at the Pi end of the wires?

          • Daniele says:

            Well if resistor can go at the end of the wires i can do it.. This afternoon i will try.. On the raspberry pi forum a user told me to use a capacitor in parallel with the buttons..

          • I know that helps with debounce. If it helps with floating to, that’s great.

          • AndrewS says:

            I think a capacitor can sometimes be used to filter out “spikes” of interference (IIRC it’s the hardware equivalent of what software de-bouncing does), but this is all beyond my depth – I’m a software guy not a hardware guy ;-) Good luck!

          • Daniele says:

            I’ve seen with the digital multimeter that when the button is not pressed there is a very big resistance like 200Kohm maybe if i add a resistance in series i could delete any interference or not? (just like AndrewS i like software and i don’t know so much about hardware)

          • Daniele says:

            Perhaps i did it!! =D It seems to work correctly.. I’ve connected everything as following:

          • That looks OK to me, but I’m not an expert. Well done if it works :)

          • AndrewS says:

            Eeek, that shows 5V connected to the Pi’s GPIO pins! You’re only supposed to connect 3.3V to the GPIO pins, otherwise you risk damaging them.

          • I think the 10k + 1k resistors limit the current enough to make it a non-fatal condition.
            I seem to remember a post by Mah Jongh on the Pi forums where he said something like ‘you don’t need level converters as long as you have a >1k resistor in series with the port’. That’s not a quote though – it’s what I remember from the thread.

          • As AndrewS points out, THE DIAGRAM SHOWS 5V CONNECTED TO THE Pi’s GPIO INPUT (PORT 24) – WHEN THE BUTTON IS PUSHED. alex says “I think the 10k + 1k resistors limit the current enough” … BUT THERE ARE NO RESISTORS IN THE DIAGRAM. CORRECTION NEEDED.

          • Andrew is talking about another diagram linked to in the comments by Daniele – one that’s on circuitlab.

            My diagram above is connected to 3V3. If you take a close look you will be able to verify that for yourself.

  12. Daniele says:

    Hi, another question, i set up a switch (not a button), how can i read the state of that switch? I tried with this code but it don’t work, thanks for any help =)


    if GPIO.input(21) == 1:
    print "On"
    state = "1"
    else:
    print = "Off"
    state = "0"

    • That should work fine (assuming your switch is connected to GPIO21 if you’re using BCM), but only once unless you put it in a loop.

      Also, you don’t need the “== 1″, simply if GPIO.input(21):
      will return 1 or 0 (HIGH or LOW and True or False).

      • Daniele says:

        Thanks for answering =) well I’m using BOARD maybe that’s why it don’t work?

        • Well are you using pin 21 or GPIO 21? Have you read the RPi.GPIO basics series on here this week? It’s all covered.
          Pin 21 is GPIO9
          GPIO21 is pin 13 if you have a Rev 1 Pi. If you have a Rev 2 it doesn’t exist.

          • Daniele says:

            I’m using pin 21 on rev 1 so gpio 9

          • AndrewS says:

            There’s no reason that a switch shouldn’t work identically to the way a button works – electrically they’re either on (closed) or off (open). How have you got the switch wired up, what pull-up / pull-down settings (or resistors) are you using, etc. ?

          • Daniele says:

            I’ve connected the switch one wire to the gnd and the other to the pin 23 and this is the script i use.. even if i have the switch on sometimes it print on and sometimes off..


            #import RPi.GPIO library as GPIO
            import RPi.GPIO as GPIO
            import MySQLdb as mdb
            GPIO.setwarnings(False)
            #Set GPIO numbering scheme to pinnumber
            GPIO.setmode(GPIO.BOARD)
            #setup pin 23 as an input
            GPIO.setup(23,GPIO.IN)

            if GPIO.input(23):
            print “Light ON”
            state = “1″
            else:
            print “Light OFF”
            state = “0″

            con = mdb.connect(‘localhost’, ‘root’, ‘rasp’, ‘domopi’);

            with con:

            cur = con.cursor()
            cur.execute("UPDATE settings SET light=" + (state) + " WHERE id=1")

          • Daniele says:

            Ok i got it working just adding pull_up_down=GPIO.PUD_UP

            Thanks anyway =D

          • AndrewS says:

            Ahhh, so you just needed to RTFM RAFG – Read Alex’s Fabulous Guides :-)

  13. Alex
    Before my questions, can I just thank you for all the work you have done on your site. Without it I would be far more confused than I already am, and would never have got to grips with the Gertboard.

    Now the questions:

    1. Why have you used the function, e.g.,
    GPIO.add_event_detect(24, GPIO.RISING, callback=my_callback)
    when the manual on the raspberry-gpio-python/wiki page provides the function
    GPIO.add_event_callback(….)
    which appears to do the same job? Or does it?

    2. How does one know when a “word” such as “channel” in a function has to be left as it is, as in
    def my-callback(channel),
    and when it has to be substituted with and actual value, such as 24 in
    GPIO.add_event_detect(24, …) above?
    Cheers!

    • 1. GPIO.add_event_callback(….) is used if you want to run more than one callback function from a single interrupt event.

      2. Simple answer, you rely on good documentation conventions and up to date documentation which is not always fool-proof. Sometimes you just have to “poke it and see” what happens. :)

      I wasted some time yesterday trying to get tweepy working, only to realise that the official documentation was WAY out of date and what I was trying to do would never work again (they’ve changed the way twitter authentication works).

    • def my-callback(channel)
      is a function definition, i.e. channel is a local variable inside the function which contains the value passed to the function.

      GPIO.add_event_detect(24, …)
      is you calling a function, i.e. inside the add_event_detect function (which is inside the GPIO module) there’ll be some local variable inside it set to the value 24.

      1. # declare a function
      2. def my_function(name):
      3.     print ”Hello ” + name
      4. # call the function
      5. my_function(“Harry”)
      6. # create a variable
      7. person = ”Alex”
      8. # call the function again
      9. my_function(person)

      would print out “Hello Harry” and then “Hello Alex”.

      You’ll naturally get the hang of these things once you’ve been programming for a while ;-)