2019-11-21 20:06:13 +01:00
|
|
|
import logging
|
|
|
|
|
|
|
|
import pykka
|
|
|
|
from mopidy import core
|
|
|
|
|
2021-03-13 16:38:15 +01:00
|
|
|
from .rotencoder import RotEncoder
|
|
|
|
|
2019-11-21 20:06:13 +01:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
class RaspberryGPIOFrontend(pykka.ThreadingActor, core.CoreListener):
|
|
|
|
def __init__(self, config, core):
|
|
|
|
super().__init__()
|
|
|
|
import RPi.GPIO as GPIO
|
|
|
|
|
|
|
|
self.core = core
|
|
|
|
self.config = config["raspberry-gpio"]
|
|
|
|
self.pin_settings = {}
|
2021-03-13 14:54:59 +01:00
|
|
|
self.rot_encoders = {}
|
2019-11-21 20:06:13 +01:00
|
|
|
|
|
|
|
GPIO.setwarnings(False)
|
|
|
|
GPIO.setmode(GPIO.BCM)
|
|
|
|
|
|
|
|
# Iterate through any bcmN pins in the config
|
|
|
|
# and set them up as inputs with edge detection
|
|
|
|
for key in self.config:
|
|
|
|
if key.startswith("bcm"):
|
|
|
|
pin = int(key.replace("bcm", ""))
|
|
|
|
settings = self.config[key]
|
|
|
|
if settings is None:
|
|
|
|
continue
|
|
|
|
|
|
|
|
pull = GPIO.PUD_UP
|
|
|
|
edge = GPIO.FALLING
|
|
|
|
if settings.active == "active_high":
|
|
|
|
pull = GPIO.PUD_DOWN
|
|
|
|
edge = GPIO.RISING
|
|
|
|
|
2021-03-13 14:54:59 +01:00
|
|
|
if 'rotenc_id' in settings.options:
|
|
|
|
edge = GPIO.BOTH
|
2021-03-13 16:38:15 +01:00
|
|
|
rotenc_id = settings.options['rotenc_id']
|
2021-03-13 14:54:59 +01:00
|
|
|
encoder = None
|
2021-03-13 16:38:15 +01:00
|
|
|
if rotenc_id in self.rot_encoders.keys():
|
2021-03-13 14:54:59 +01:00
|
|
|
encoder = self.rot_encoders[rotenc_id]
|
|
|
|
else:
|
|
|
|
encoder = RotEncoder(rotenc_id)
|
|
|
|
self.rot_encoders[rotenc_id] = encoder
|
|
|
|
encoder.add_pin(pin, settings.event)
|
|
|
|
|
2019-11-21 20:06:13 +01:00
|
|
|
GPIO.setup(pin, GPIO.IN, pull_up_down=pull)
|
|
|
|
|
|
|
|
GPIO.add_event_detect(
|
|
|
|
pin,
|
|
|
|
edge,
|
|
|
|
callback=self.gpio_event,
|
|
|
|
bouncetime=settings.bouncetime,
|
|
|
|
)
|
|
|
|
|
|
|
|
self.pin_settings[pin] = settings
|
|
|
|
|
2021-03-13 14:54:59 +01:00
|
|
|
# TODO validate all self.rot_encoders have two pins
|
|
|
|
|
2021-03-13 16:38:15 +01:00
|
|
|
def find_pin_rotenc(self, pin):
|
|
|
|
for encoder in self.rot_encoders.values():
|
|
|
|
if pin in encoder.pins:
|
|
|
|
return encoder
|
|
|
|
|
2019-11-21 20:06:13 +01:00
|
|
|
def gpio_event(self, pin):
|
|
|
|
settings = self.pin_settings[pin]
|
2021-03-13 14:54:59 +01:00
|
|
|
event = settings.event
|
2021-03-13 16:38:15 +01:00
|
|
|
encoder = self.find_pin_rotenc (pin)
|
|
|
|
if encoder:
|
|
|
|
event = encoder.get_event()
|
2021-03-13 14:54:59 +01:00
|
|
|
|
|
|
|
if event:
|
|
|
|
self.dispatch_input(event, settings.options)
|
2019-11-21 20:06:13 +01:00
|
|
|
|
2021-03-13 14:54:59 +01:00
|
|
|
def dispatch_input(self, event, options):
|
|
|
|
handler_name = f"handle_{event}"
|
2019-11-21 20:06:13 +01:00
|
|
|
try:
|
2021-03-13 14:54:59 +01:00
|
|
|
getattr(self, handler_name)(options)
|
2019-11-21 20:06:13 +01:00
|
|
|
except AttributeError:
|
|
|
|
raise RuntimeError(
|
2021-03-13 14:54:59 +01:00
|
|
|
f"Could not find input handler for event: {event}"
|
2019-11-21 20:06:13 +01:00
|
|
|
)
|
|
|
|
|
2020-03-25 12:42:57 +01:00
|
|
|
def handle_play_pause(self, config):
|
2020-01-23 13:37:36 +01:00
|
|
|
if self.core.playback.get_state().get() == core.PlaybackState.PLAYING:
|
2019-11-21 20:06:13 +01:00
|
|
|
self.core.playback.pause()
|
|
|
|
else:
|
|
|
|
self.core.playback.play()
|
2020-07-14 15:50:24 +02:00
|
|
|
|
2020-07-14 13:15:49 +02:00
|
|
|
def handle_play_stop(self, config):
|
|
|
|
if self.core.playback.get_state().get() == core.PlaybackState.PLAYING:
|
|
|
|
self.core.playback.stop()
|
|
|
|
else:
|
|
|
|
self.core.playback.play()
|
2019-11-21 20:06:13 +01:00
|
|
|
|
2020-03-25 12:42:57 +01:00
|
|
|
def handle_next(self, config):
|
2019-11-21 20:06:13 +01:00
|
|
|
self.core.playback.next()
|
|
|
|
|
2020-03-25 12:42:57 +01:00
|
|
|
def handle_prev(self, config):
|
2019-11-21 20:06:13 +01:00
|
|
|
self.core.playback.previous()
|
|
|
|
|
2020-03-25 12:42:57 +01:00
|
|
|
def handle_volume_up(self, config):
|
|
|
|
step = int(config.get("step", 5))
|
2020-01-23 13:37:36 +01:00
|
|
|
volume = self.core.mixer.get_volume().get()
|
2020-03-25 12:42:57 +01:00
|
|
|
volume += step
|
2019-11-21 20:06:13 +01:00
|
|
|
volume = min(volume, 100)
|
2020-01-23 13:37:36 +01:00
|
|
|
self.core.mixer.set_volume(volume)
|
2019-11-21 20:06:13 +01:00
|
|
|
|
2020-03-25 12:42:57 +01:00
|
|
|
def handle_volume_down(self, config):
|
|
|
|
step = int(config.get("step", 5))
|
2020-01-23 13:37:36 +01:00
|
|
|
volume = self.core.mixer.get_volume().get()
|
2020-03-25 12:42:57 +01:00
|
|
|
volume -= step
|
2019-11-21 20:06:13 +01:00
|
|
|
volume = max(volume, 0)
|
2020-01-23 13:37:36 +01:00
|
|
|
self.core.mixer.set_volume(volume)
|