Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bluetooth remote control via GPIO #101

Draft
wants to merge 15 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ RUN install_packages \
# Copy sounds
COPY sounds /usr/src/sounds

# Copy bluetooth-control script
COPY bluetooth-control /usr/src/
RUN chmod +x /usr/src/bluetooth-control

# Setup udev rules - this lets us play the connect/disconnect sound,
# turn off discover/pairing when a client is connected
# and also run a python script
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ RUN install_packages \
# Copy sounds
COPY sounds /usr/src/sounds

# Copy bluetooth-control script
COPY bluetooth-control /usr/src/
RUN chmod +x /usr/src/bluetooth-control

# Setup udev rules - this lets us play the connect/disconnect sound,
# turn off discover/pairing when a client is connected
# and also run a python script
Expand Down
File renamed without changes.
160 changes: 160 additions & 0 deletions bluetooth/bluetooth-control
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#!/usr/bin/env bash

# Set up variables
VOLUME_UP_GPIO=$(</usr/src/volume_up_gpio)

BLUETOOTH_GPIO=$(</usr/src/bluetooth_gpio)

VOLUME_DOWN_GPIO=$(</usr/src/volume_down_gpio)

NEXT_GPIO=$(</usr/src/next_gpio)

PREVIOUS_GPIO=$(</usr/src/previous_gpio)

OUTPUT_GPIO=$(</usr/src/output_gpio)
Comment on lines +4 to +14
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, the other script writes the values into these files, and then this scripts reads the values.
Are the files used anywhere else? Can't we just have all done here and avoid the files alltogether?


TIMER="0"

SKIP_STOP="0"

BLUETOOTH_DISCOVERABLE="0"

# Set up + volume
if [[ ! -d /sys/class/gpio/gpio$VOLUME_UP_GPIO ]]; then
echo "$VOLUME_UP_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$VOLUME_UP_GPIO/direction

# Set up bluetooth
if [[ ! -d /sys/class/gpio/gpio$BLUETOOTH_GPIO ]]; then
echo "$BLUETOOTH_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$BLUETOOTH_GPIO/direction

# Set up - volume
if [[ ! -d /sys/class/gpio/gpio$VOLUME_DOWN_GPIO ]]; then
echo "$VOLUME_DOWN_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$VOLUME_DOWN_GPIO/direction

# Set up next
if [[ ! -d /sys/class/gpio/gpio$NEXT_GPIO ]]; then
echo "$NEXT_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$NEXT_GPIO/direction

# Set up previous
if [[ ! -d /sys/class/gpio/gpio$PREVIOUS_GPIO ]]; then
echo "$PREVIOUS_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$PREVIOUS_GPIO/direction

# Set up utput gpio (there is one energy input missing)
if [[ ! -d /sys/class/gpio/gpio$OUTPUT_GPIO ]]; then
echo "$OUTPUT_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "out" > /sys/class/gpio/gpio$OUTPUT_GPIO/direction
Comment on lines +22 to +62
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could eliminate a lot of code using a function here. Haven't tested it, but this should be ok:

Suggested change
# Set up + volume
if [[ ! -d /sys/class/gpio/gpio$VOLUME_UP_GPIO ]]; then
echo "$VOLUME_UP_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$VOLUME_UP_GPIO/direction
# Set up bluetooth
if [[ ! -d /sys/class/gpio/gpio$BLUETOOTH_GPIO ]]; then
echo "$BLUETOOTH_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$BLUETOOTH_GPIO/direction
# Set up - volume
if [[ ! -d /sys/class/gpio/gpio$VOLUME_DOWN_GPIO ]]; then
echo "$VOLUME_DOWN_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$VOLUME_DOWN_GPIO/direction
# Set up next
if [[ ! -d /sys/class/gpio/gpio$NEXT_GPIO ]]; then
echo "$NEXT_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$NEXT_GPIO/direction
# Set up previous
if [[ ! -d /sys/class/gpio/gpio$PREVIOUS_GPIO ]]; then
echo "$PREVIOUS_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "in" > /sys/class/gpio/gpio$PREVIOUS_GPIO/direction
# Set up utput gpio (there is one energy input missing)
if [[ ! -d /sys/class/gpio/gpio$OUTPUT_GPIO ]]; then
echo "$OUTPUT_GPIO" > /sys/class/gpio/export
sleep 1
fi
echo "out" > /sys/class/gpio/gpio$OUTPUT_GPIO/direction
function configure_gpio() {
local GPIO_PIN="$1"
local DIRECTION="$2"
if [[ ! -d /sys/class/gpio/gpio$GPIO_PIN ]]; then
echo "$GPIO_PIN" > /sys/class/gpio/export
sleep 1
fi
echo "$DIRECTION" > /sys/class/gpio/gpio$GPIO_PIN/direction
}
configure_gpio "$VOLUME_UP_GPIO" "in"
configure_gpio "$BLUETOOTH_GPIO" "in"
configure_gpio "$VOLUME_DOWN_GPIO" "in"
configure_gpio "$NEXT_GPIO" "in"
configure_gpio "$PREVIOUS_GPIO" "in"
configure_gpio "$OUTPUT_GPIO" "out"


while : ; do

while [[ "$(cat /sys/class/gpio/gpio$BLUETOOTH_GPIO/value)" == 1 ]]; do
if [[ "$TIMER" < 3 ]]; then
TIMER=$((TIMER+1))
sleep 1
fi
done

if [[ "$TIMER" == 3 ]]; then
if [[ ! -a /usr/src/is_discoverable ]]; then
printf "Making the device for 3 min discoverable. \n"
printf "discoverable on\npairable on\nexit\n" | bluetoothctl > /dev/null
touch /usr/src/is_discoverable
(sleep 180 ; printf "Closing bluetooth discovery. \n" ; printf "discoverable off\npairable off\nexit\n" | bluetoothctl > /dev/null ; rm /usr/src/is_discoverable) &
else
printf "The device is already discoverable. \n"
fi
fi

if [ -a /var/cache/bluetooth/reconnect_device ]; then

# Get the alsa name of the connected device
DEVICE="$(echo "$(amixer -D bluealsa scontrols)" | sed -n " s,[^']*'\([^']*\).*,\1,p ")"

# Get and parse the MAC Adress of the connected device
MAC="$(cat /var/cache/bluetooth/reconnect_device)"
MAC_PARSED="$(echo ${MAC//:/_})"
# PLAYER_ADDRESS="$(echo "$(dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED org.freedesktop.DBus.Properties.Get string:org.bluez.MediaControl1 string:Player)" | cut -d'"' -f 2)"

if [[ ! -z "$(echo "$(amixer -D bluealsa scontrols)" | sed -n " s,[^']*'\([^']*\).*,\1,p ")" ]]; then

# Volume up
if [[ "$(cat /sys/class/gpio/gpio$VOLUME_UP_GPIO/value)" == 1 ]]; then
printf "Setting volume higher. \n"
amixer -D bluealsa sset "$DEVICE" 10%+
sleep 0.5
fi

if [[ "$TIMER" == 1 ]]; then
if [[ "$(dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.freedesktop.DBus.Properties.Get string:org.bluez.MediaPlayer1 string:Status | cut -d'"' -f 2)" == *"playing"* ]]; then
printf "Stoping music playback. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Pause
else
printf "Starting music playback. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Play
fi
fi

if [[ "$TIMER" == 2 ]]; then
if [[ "$(dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.freedesktop.DBus.Properties.Get string:org.bluez.MediaPlayer1 string:Status | cut -d'"' -f 2)" == *"playing"* ]]; then
printf "Stoping music playback. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Pause
else
printf "Starting music playback. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Play
fi
fi

# Volume down
if [[ "$(cat /sys/class/gpio/gpio$VOLUME_DOWN_GPIO/value)" == 1 ]]; then
printf "Setting volume lower. \n"
amixer -D bluealsa sset "$DEVICE" 10%-
sleep 0.5
fi

# Next track
while [[ "$(cat /sys/class/gpio/gpio$NEXT_GPIO/value)" == 1 ]]; do
if [[ "$SKIP_STOP" == 0 ]]; then
printf "Playing the next track. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Next
sleep 0.5
fi
SKIP_STOP="1"
done

SKIP_STOP="0"

# Previous track
while [[ "$(cat /sys/class/gpio/gpio$PREVIOUS_GPIO/value)" == 1 ]]; do
if [[ "$SKIP_STOP" == 0 ]]; then
printf "Playing the previous track. \n"
dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0/dev_$MAC_PARSED/player0 org.bluez.MediaPlayer1.Previous
sleep 0.5
fi
SKIP_STOP="1"
done
Comment on lines +131 to +150
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, if the code is nearly identical we should try and use functions to reduce code (also easier maintenance!)


SKIP_STOP="0"

fi

TIMER="0"

fi

done
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#!/usr/bin/python
# This sript runs, when your pi connects to a bluetooth device and BLUETOOTH_CONNECT is set to anything.
# This sript runs, when your pi connects to a bluetooth device and BLUETOOTH_SCRIPTS is set to true.
# You can add your own code. BalenaSound has gpiozero installed so you can work with it.
# Here is a example:

# from gpiozero import LED
# from time import sleep

# led = LED(17)
# led = LED(16)

# led.off()
# sleep(1)

# sleep(1)
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/python
# This sript runs, when your pi disconnects from a bluetooth device and BLUETOOTH_DISCONNECT is set to anything.
# This sript runs, when your pi disconnects from a bluetooth device and BLUETOOTH_SCRIPTS is set to true.
# You can add your own code. BalenaSound has gpiozero installed so you can work with it.
# Here is a example:

# from gpiozero import LED
# from time import sleep

# led = LED(17)
# led = LED(16)

# led.off()
# sleep(1)
# sleep(1)
6 changes: 4 additions & 2 deletions bluetooth-audio/bluetooth-udev → bluetooth/bluetooth-udev
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/bin/bash
#!/usr/bin/env bash

export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket

name=$(sed 's/\"//g' <<< $NAME)
Expand Down Expand Up @@ -26,12 +27,13 @@ add)
fi
;;
remove)
printf "discoverable off\npairable off\nexit\n" | bluetoothctl

amixer -M sset PCM,0 $CONNECTION_NOTIFY_VOLUME% > /dev/null &
amixer -M sset Digital,0 $CONNECTION_NOTIFY_VOLUME% > /dev/null &

aplay -D hw:0,0 /usr/src/sounds/disconnect.wav > /dev/null 2>&1

printf "discoverable on\npairable on\nexit\n" | bluetoothctl
amixer -M sset PCM,0 $SYSTEM_OUTPUT_VOLUME% > /dev/null &
amixer -M sset Digital,0 $SYSTEM_OUTPUT_VOLUME% > /dev/null &
if [[ -z "$BLUETOOTH_SCRIPTS" ]]; then
Expand Down
File renamed without changes.
File renamed without changes.
45 changes: 42 additions & 3 deletions bluetooth-audio/start.sh → bluetooth/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,12 @@ fi

sleep 2
rm -rf /var/run/bluealsa/
/usr/bin/bluealsa -i hci0 -p a2dp-sink &
/usr/bin/bluealsa -i hci0 -p a2dp-sink --a2dp-volume &

hciconfig hci1 down > /dev/null 2>&1 # Disable onboard bluetooth if using a bluetooth dongle (onboard interface gets remapped to hci1)

hciconfig hci0 up

hciconfig hci0 name "$DEVICE_NAME"

if ! [ -z "$BLUETOOTH_PIN_CODE" ] && [[ $BLUETOOTH_PIN_CODE -gt 1 ]] && [[ $BLUETOOTH_PIN_CODE -lt 1000000 ]]; then
Expand All @@ -66,6 +68,10 @@ else
printf "Starting bluetooth agent in Secure Simple Pairing Mode (SSPM) - No PIN code provided or invalid\n"
fi

if [[ ! -z "$DISABLE_AUTO_DISCOVERY" ]]; then
printf "discoverable off\npairable off\nexit\n" | bluetoothctl > /dev/null
fi

# Reconnect if there is a known device
sleep 2
if [ -f "/var/cache/bluetooth/reconnect_device" ]; then
Expand All @@ -74,7 +80,40 @@ if [ -f "/var/cache/bluetooth/reconnect_device" ]; then
printf "connect %s\nexit\n" "$TRUSTED_MAC_ADDRESS" | bluetoothctl > /dev/null
fi

# Start gpio bluetooth control service
if [[ -z "$DISABLE_BLUETOOTH_CONTROL" ]]; then
VOLUME_UP_GPIO="${VOLUME_UP_GPIO:-17}"
echo $VOLUME_UP_GPIO > /usr/src/volume_up_gpio
printf "Volume up button input is on GPIO$VOLUME_UP_GPIO \n"

BLUETOOTH_GPIO="${BLUETOOTH_GPIO:-27}"
echo $BLUETOOTH_GPIO > /usr/src/bluetooth_gpio
printf "Bluetooth button input is on GPIO$BLUETOOTH_GPIO \n"

VOLUME_DOWN_GPIO="${VOLUME_DOWN_GPIO:-22}"
echo $VOLUME_DOWN_GPIO > /usr/src/volume_down_gpio
printf "Volume down button input is on GPIO$VOLUME_DOWN_GPIO \n"

NEXT_GPIO="${NEXT_GPIO:-10}"
echo $NEXT_GPIO > /usr/src/next_gpio
printf "Next track button input is on GPIO$NEXT_GPIO \n"

PREVIOUS_GPIO="${PREVIOUS_GPIO:-9}"
echo $PREVIOUS_GPIO > /usr/src/previous_gpio
printf "Previous track button input is on GPIO$PREVIOUS_GPIO \n"

OUTPUT_GPIO="${OUTPUT_GPIO:-11}"
echo $OUTPUT_GPIO > /usr/src/output_gpio
printf "A extra energy output is on GPIO$OUTPUT_GPIO \n"

if [[ ! -z "CLOSE_DISCOVERY" ]]; then
touch /usr/src/close_discovery
printf "Bluetooth discovery will be deactivated if the device connects and bluetooth discovery got activated via gpio. \n"
fi

bash /usr/src/bluetooth-control &
fi

sleep 2
printf "Device is discoverable as \"%s\"\n" "$DEVICE_NAME"
exec /usr/bin/bluealsa-aplay --pcm-buffer-time=1000000 00:00:00:00:00:00

exec /usr/bin/bluealsa-aplay --profile-a2dp 00:00:00:00:00:00
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '2'
services:
bluetooth-audio:
build: ./bluetooth-audio
bluetooth:
build: ./bluetooth
restart: on-failure
network_mode: host
privileged: true
Expand Down
Binary file added images/gpio-pins.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions repo.yml
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
type: balena
upstream:
- repo: balena-sound
url: https://github.com/balenalabs/balena-sound