1
votes

I have updated the code to look like this:

import RPi.GPIO as GPIO
import time
import datetime

BUTTON_PIN = 16
GPIO.setmode(GPIO.BCM)


class TimedButton:
    def __init__(self, pin, callback, pull_up_down=GPIO.PUD_UP, package=None):
        """
        A TimedButton initiates a callback after a button has been pressed and then released.  It passes the duration
        the button was pressed to the callback
        :param pin: pin the button is on
        :param callback: callback to call when pressed
        :param pull_up_down: indicates the button is pulled up or down with a resistor
        :param package: package to pass to the callback
        """
        self.pin = pin
        self.package = package
        self.last_push = datetime.datetime.now()
        self.callback = callback
        self.press_time = None
        GPIO.setup(pin, GPIO.IN, pull_up_down=pull_up_down)
        GPIO.add_event_detect(pin, edge=GPIO.BOTH, callback=self._debounce_function)

    def _debounce_function(self, pin):
        """
        This function debounces the button.  Buttons are inherently noisy (they ring when pressed)  This function waits
        a period of time before declaring the button to have settled into the current state.
        :param pin: pin the button is on
        :return: None
        """
        time_now = datetime.datetime.now()
        current_state = GPIO.input(self.pin)
        if (time_now - self.last_push).microseconds > .1 * units.microseconds_per_second:
            if current_state and self.press_time is not None:
                self.callback(pin, datetime.datetime.now() - self.press_time, self.package)
            else:
                self.press_time = datetime.datetime.now()
        self.last_push = time_now

def button_callback(pin, state, argument):
    print('{} Pin {} now at {}.  Message:{}'.format(datetime.datetime.now(), pin, state, argument))

def main():
    import RPi.GPIO as GPIO
    print('Starting test_Button')
    GPIO.remove_event_detect(BUTTON_PIN)
    TimedButton(pin=BUTTON_PIN, callback=button_callback)
    while True:
        time.sleep(1)


if __name__ == "__main__":
    main()

I have tried:

  • sudoing as root
  • running as root
  • changing ownership of /dev/mem
  • reinstalling rpi.gpio

I always get the same error: RuntimeError: No access to /dev/mem. Try running as root!

Here is what I have tried: (as pi):

pi@snail-patrol:python3 test.py
Starting test_Button
Traceback (most recent call last):
  File "test.py", line 56, in <module>
    main()
  File "test.py", line 49, in main
    GPIO.remove_event_detect(BUTTON_PIN)
RuntimeError: No access to /dev/mem.  Try running as root!

(su to root - note tried su without the - also)

pi@snail-patrol:sudo su -
root@snail-patrol:/home/pi/temp# python3 test.py
Starting test_Button
Traceback (most recent call last):
  File "test.py", line 56, in <module>
    main()
  File "test.py", line 49, in main
    GPIO.remove_event_detect(BUTTON_PIN)
RuntimeError: No access to /dev/mem.  Try running as root!

(sudo)
pi@snail-patrol:sudo python3 test.py
Starting test_Button
Traceback (most recent call last):
  File "test.py", line 56, in <module>
    main()
  File "test.py", line 49, in main
    GPIO.remove_event_detect(BUTTON_PIN)
RuntimeError: No access to /dev/mem.  Try running as root!

Here is what the permissions look like

pi@snail-patrol:ls -l /dev/mem
crw-r----- 1 root kmem 1, 1 Jul 17 20:56 /dev/mem
pi@snail-patrol:ls -l test.py
-rw-r--r-- 1 pi pi 2110 Jul 18 17:01 test.p

Note that I also tried:

sudo rpi-update
sudo reboot
sudo apt-get update
sudo apt-get upgrade
sudo adduser pi gpio
sudo chown root.gpio /dev/mem && sudo chmod g+rw /dev/mem

And I still get the same error!

1
It helps if you show us both your code and the specific commands you've tried to run it. - larsks
I tried @Axiumin_'s suggestion from here: raspberrypi.stackexchange.com/questions/40105/… to no avail. - jordanthompson
I also added all of the code as suggested by @larsks - jordanthompson

1 Answers

0
votes

The error you're getting is misleading. It doesn't actually have anything to do with permissions on /dev/mem. It's actually because you're calling GPIO.remove_event_detect(BUTTON_PIN) before setting up up the pin.

Consider the following code:

import RPi.GPIO as GPIO

BUTTON_PIN = 16

GPIO.setmode(GPIO.BCM)
GPIO.remove_event_detect(BUTTON_PIN)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)

print('current value of pin', BUTTON_PIN, 'is', GPIO.input(BUTTON_PIN))

This fails with the same error as your code:

root@raspberrypi:/home/pi# python test_error.py
Traceback (most recent call last):
  File "test_error.py", line 6, in <module>
    GPIO.remove_event_detect(BUTTON_PIN)
RuntimeError: No access to /dev/mem.  Try running as root!

If we swap the position of the GPIO.setup and GPIO.remove_event_detect calls, so that we have:

import RPi.GPIO as GPIO

BUTTON_PIN = 16

GPIO.setmode(GPIO.BCM)
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.remove_event_detect(BUTTON_PIN)

print('current value of pin', BUTTON_PIN, 'is', GPIO.input(BUTTON_PIN))

It runs without any error:

root@raspberrypi:/home/pi# python test_error.py
('current value of pin', 16, 'is', 1)

If we rewrite your main function so that it looks like this:

def main():
    TimedButton(pin=BUTTON_PIN, callback=button_callback)
    while True:
        time.sleep(1)

Everything works without error. This is the result of me grounding the pin a few times while your code runs:

root@raspberrypi:/home/pi# python testgpio.py
2020-07-19 16:48:31.000582 Pin 16 now at 0:00:01.313176.  Message:None
2020-07-19 16:48:34.187487 Pin 16 now at 0:00:01.178778.  Message:None

There's no reason to call GPIO.remove_event_detect at this point in your code, because you haven't set up any event detection. There's also no reason to have that import statement in your main function, since you're alreadying import-ing RPI.GPIO at the top of your code.