Skip to content

Commit

Permalink
Refactor to use gpiozero instead of RPi.GPIO for Kernel 6.6 Compat.
Browse files Browse the repository at this point in the history
  • Loading branch information
NeonDaniel committed Mar 29, 2024
1 parent 64f3510 commit 48f98b8
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 68 deletions.
126 changes: 59 additions & 67 deletions neon_phal_plugin_switches/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,22 @@
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import RPi.GPIO as GPIO

from os.path import exists
from abc import ABC
from time import sleep
from typing import Optional

from ovos_plugin_manager.phal import PHALPlugin
from ovos_plugin_manager.hardware.switches import AbstractSwitches
from ovos_utils.log import LOG
from ovos_bus_client.message import Message
from sj201_interface.revisions import detect_sj201_revision
from gpiozero import Button


class SwitchValidator:
@staticmethod
def validate(_=None):
# TODO: More generic validation
# TODO: More generic validation that GPIO exists
return detect_sj201_revision() is not None


Expand All @@ -62,21 +63,34 @@ def __init__(self, bus=None, config=None):
self.switches.on_vol_up = self.on_button_volup_press
self.switches.on_vol_down = self.on_button_voldown_press

if GPIO.input(self.switches.mute_pin) == self.switches.muted:
if self.switches.mute_switch.is_active:
LOG.debug(f"Mute switch active")
self.bus.emit(Message('mycroft.mic.mute'))

self.bus.on('mycroft.mic.status', self.on_mic_status)

@property
def gpio_device(self):
if self.config.get("gpio_device"):
LOG.debug(f"GIPIO device from config: {self.config['gpio_device']}")
return self.config.get("gpio_device")
if exists("/dev/gpiochip4"):
LOG.info("Selecting gpiochip4")
return "gpiochip4"
if exists("/dev/gpiochip0"):
return "gpiochip0"
raise RuntimeError(f"No GPIO device available")

def on_mic_status(self, message):
if GPIO.input(self.switches.mute_pin) == self.switches.muted:
if self.switches.mute_switch.is_active:
msg_type = 'mycroft.mic.mute'
else:
msg_type = 'mycroft.mic.unmute'
self.bus.emit(message.reply(msg_type))

def on_button_press(self):
LOG.info("Listen button pressed")
if GPIO.input(self.switches.mute_pin) != self.switches.muted:
if not self.switches.mute_switch.is_active:
self.bus.emit(Message("mycroft.mic.listen"))
else:
self.bus.emit(Message("mycroft.mic.error",
Expand All @@ -100,25 +114,42 @@ def on_hardware_unmute(self):


class GPIOSwitches(AbstractSwitches, ABC):
def __init__(self, action_callback, volup_callback, voldown_callback,
mute_callback, unmute_callback, volup_pin: int = 22,
voldown_pin: int = 23, action_pin: int = 24,
mute_pin: int = 25, sw_active_state: int = 0,
sw_muted_state: int = 1):
def __init__(self, action_callback: callable,
volup_callback: callable, voldown_callback: callable,
mute_callback: callable, unmute_callback: callable,
volup_pin: int = 22, voldown_pin: int = 23,
action_pin: int = 24, mute_pin: int = 25,
sw_muted_state: int = 1, sw_pullup: bool = True):
"""
Creates an object to manage GPIO switches and callbacks on switch
activity.
@param action_callback: Called when the "Action" switch is activated
@param volup_callback: Called when the volume up switch is activated
@param voldown_callback: Called when the volume down switch is activated
@param mute_callback: Called when the mute switch is activated
@param unmute_callback: Called when the mute switch is de-activated
@param volup_pin: GPIO pin of the volume up switch
@param voldown_pin: GPIO pin of the volume down switch
@param action_pin: GPIO pin of the action switch
@param mute_pin: GPIO pin of the mute slider
@param sw_muted_state: mute pin state associated with muted
@param sw_pullup: if True, pull up switches, else pull down
"""
self.on_action = action_callback
self.on_vol_up = volup_callback
self.on_vol_down = voldown_callback
self.on_mute = mute_callback
self.on_unmute = unmute_callback

self.mute_switch: Optional[Button] = None

self.vol_up_pin = volup_pin
self.vol_dn_pin = voldown_pin
self.action_pin = action_pin
self.mute_pin = mute_pin
self._active = sw_active_state
self._muted = sw_muted_state

self.setup_gpio()
self.setup_gpio(pull_up=sw_pullup)

@property
def muted(self):
Expand All @@ -127,63 +158,24 @@ def muted(self):
"""
return self._muted

def setup_gpio(self, debounce=100):
def setup_gpio(self, debounce: int = 0.1, pull_up: bool = True):
"""
Do GPIO setup.
@param debounce: bounce time in seconds for button presses
@param pull_up: If true, pull up switches, else pull down
"""
# use BCM GPIO pin numbering
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

if self._active == 0:
pull_up_down = GPIO.PUD_UP
else:
pull_up_down = GPIO.PUD_DOWN
# we need to pull up the 3 buttons and mute switch
GPIO.setup(self.action_pin, GPIO.IN, pull_up_down=pull_up_down)
GPIO.setup(self.vol_up_pin, GPIO.IN, pull_up_down=pull_up_down)
GPIO.setup(self.vol_dn_pin, GPIO.IN, pull_up_down=pull_up_down)
GPIO.setup(self.mute_pin, GPIO.IN, pull_up_down=pull_up_down)

# attach callbacks
GPIO.add_event_detect(self.action_pin,
GPIO.BOTH,
callback=self.handle_action,
bouncetime=debounce)

GPIO.add_event_detect(self.vol_up_pin,
GPIO.BOTH,
callback=self.handle_vol_up,
bouncetime=debounce)

GPIO.add_event_detect(self.vol_dn_pin,
GPIO.BOTH,
callback=self.handle_vol_down,
bouncetime=debounce)

GPIO.add_event_detect(self.mute_pin,
GPIO.BOTH,
callback=self.handle_mute,
bouncetime=debounce)

def handle_action(self, _):
if GPIO.input(self.action_pin) == self._active:
self.on_action()

def handle_vol_up(self, _):
if GPIO.input(self.vol_up_pin) == self._active:
self.on_vol_up()

def handle_vol_down(self, _):
if GPIO.input(self.vol_dn_pin) == self._active:
self.on_vol_down()

def handle_mute(self, _):
sleep(0.05)
if GPIO.input(self.mute_pin) == self._muted:
self.on_mute()
else:
self.on_unmute()
Button(self.action_pin, pull_up=pull_up,
bounce_time=debounce).when_activated = self.on_action
Button(self.vol_up_pin, pull_up=pull_up,
bounce_time=debounce).when_activated = self.on_vol_up
Button(self.vol_dn_pin, pull_up=pull_up,
bounce_time=debounce).when_activated = self.on_vol_down

self.mute_switch = Button(self.mute_pin, pull_up=pull_up,
bounce_time=debounce)
self.mute_switch.when_deactivated = self.on_unmute
self.mute_switch.when_activated = self.on_mute

@property
def capabilities(self) -> dict:
Expand Down
3 changes: 2 additions & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
sj201-interface~=0.0.2
ovos-plugin-manager~=0.0.20
ovos-utils~=0.0.26
ovos-bus-client~=0.0.3
ovos-bus-client~=0.0.3
gpiozero~=2.0

0 comments on commit 48f98b8

Please sign in to comment.