Hi here all
While mocking up an bluetooth (ESP32) transmitter/reciever for my moOde player, i need some way of toggling play&pause from within a Python script.
(The bluetooth remote uses CamillaDSP's volume control for volume)
Snip of cdsp .yml config ::
Code:
filters:
Gain_L:
parameters:
gain: -3
inverted: false
mute: false
type: Gain
Gain_R:
parameters:
gain: -3
inverted: false
mute: false
type: Gain
Vol_L:
parameters:
ramp_time: 200
type: Volume
Vol_R:
parameters:
ramp_time: 200
type: Volume
pipeline:
- channel: 0
names:
- Gain_L
- Vol_L
type: Filter
- channel: 1
names:
- Gain_R
- Vol_R
type: Filter
...
I found that mpc toggle can do the trick very easily, so thats good. But camillaDSP goes offline every time i pause the player causing the python script to crash.
Well maybe (i guess) i could let the when done systemctl script restart the Python, but i don't like it this way.
Soo quistion is: Is there a way to avoid CamillaDSP to go offline when pausing the player ?
Rgds; Jesper
I will btw. post additional info about my project later on in the process.
So i tried different.
The bluetooth remote don't like restart's and script are getting lacky when running - So my own idea to restart at crash is a nogo
So, i could maybe use mpc commands to control volume this way, but the hole idea is to use Camilladsp's, so nogo too
My python3 script (Reciever end - connected with usb to RaspberryPi)
Only ekstra lib installed for this is ::
Quote:sudo -H pip3 install pyserial
Code:
#!/usr/bin/python3
#################################################
# #
# SuperPlayer Bluetooth (BLE) remote controller #
# #
# Build with help from different sources (www) #
# #
# Jesper Lykke [user :: Lykkedk @ diyaudio.com] #
# #
#################################################
from camilladsp import CamillaConnection
import io
import os
import stat
import subprocess
import sys
from subprocess import call
import time
import serial
cdsp = CamillaConnection("127.0.0.1", 1234)
GO = int(1) # Go through loop = (1)
MUTE = int(0) # Mute = (1) / Unmute = (0)
# CamillaDSP '--gain <gain>': Must be a number between -120 and +20
volume = int(-0) # We start with volume at -0dB
MIN_volume = int(-110) # Lower limit with some proof
MAX_volume = int(-0) # Upper limit without 'clipping'
CN = int(-0) # Set volume default for Unmute / Mute
OLD_value = int(100000) # The same value as encoder is given at start
LONG_press = int(25000) # 25000 = long pressed
DOUBLE_press = int(50000) # 50000 = double pressed
SLEEP_trigger = int(125000) # Value recieved here, just before SuperPlayer-Controller goes to sleep
newline = "\r\n" # To send "newline" serial signal
def SEGMENT_TRIGGER():
CNN=abs(CN) # Convert CN [Volume from CamillaDSP / cdsp.get_volume()]
CNNN = (CNN/10) # Divide to fit segment display
CN_STRING = (str(CNNN)) # Convert to string
ser.write(CN_STRING.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
ser.write(newline.encode('utf-8')) # Encode to utf-8 (Arduino) and send this "newline"
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1) # Setup serial connection
while 1:
serialdata = ser.readline()[:-2]
if serialdata:
data = (serialdata.decode('utf-8'))
raw = int(data)
if (MUTE == 0):
if (raw < OLD_value):
volume = (volume -1)
cdsp.connect()
CN=cdsp.get_volume()
if (CN <= MIN_volume):
volume = int(MIN_volume)
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
print ("Volume DOWN :", CN)
SEGMENT_TRIGGER()
OLD_value = raw
if (MUTE == 0):
if (raw > OLD_value):
volume = (volume +1)
cdsp.connect()
CN=cdsp.get_volume()
if (CN >= MAX_volume):
volume = int(MAX_volume)
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
print ("Volume UP :", CN)
SEGMENT_TRIGGER()
OLD_value = raw
if (raw == LONG_press):
# Option : Trigger play / pause
print ("Pause / Play")
subprocess.call(['mpc', 'toggle' ])
raw = OLD_value
time.sleep(1.00)
if (raw == DOUBLE_press):
print ("Double press")
MUTE = (MUTE + 1) % 2
if (MUTE == 0):
print ("<> Unmute system <>")
cdsp.connect()
cdsp.set_volume(CN)
time.sleep(1.00)
if (MUTE == 1):
print ("<> Mute system <>")
cdsp.connect()
CN=cdsp.get_volume()
cdsp.set_volume(MIN_volume)
time.sleep(1.00)
if (raw == SLEEP_trigger):
print ("ESP32 Controller sleep state detected")
Sleep = int(250) # Value tells ESP32 reciever to display sleep state
Sleep_String = (str(Sleep)) # Convert to string
ser.write(Sleep_String.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
ser.write(newline.encode('utf-8')) # Encode to utf-8 (Arduino) and send this "newline"
time.sleep(2.00)
time.sleep(0.1)
I see that duo to ressources, sighup is send to Camilla everytime mpd is paused, stopped etc... good idea offcause, but not so good for my project through
I really hope there is a way to avoid this ? - I sure miss my remotecontroller listning to music with my beautifull MoOdeAudio player
Rgds; Jesper.
@
lykkedk nope you can not prevent camilladsp going offlin and it will also happen when the audio format changes.
But that shouldn't be issue to handle for you code. Just accept that it camilladsp can be offline (there can always happing some unexpected) and handle it that by making your script a little bit more robust by adding try/except exception handling (see the pycamilladsp example on the pycamilladsp site).
Below is an example of main loop that automatic tries to reconnect in case of problems:
Code:
while 1:
connected = cdsp.is_connected()
if not connected:
print('trying connect')
try:
cdsp.connect()
connected = cdsp.is_connected()
print('connected')
except ConnectionRefusedError as e:
connected = False
time.sleep(2.00)
if connected:
try:
print( cdsp.get_volume())
time.sleep(2.00)
except IOError as e:
print('lost connection')
pass
Only now you have another issue when camilladsp is restart volume will be on the 0db until your script updates the volume after a reconnect.
You can prevent this by adding -m or -g option to camilladsp startups command of alsa_cdsp.
And keep also in mind that not all moOde audio source can use camilladsp, an overview f what suppports what can be found here
https://www.bitlab.nl/page_id=872 .
Bitlab; thank's a lot for putting me in the right direction
I haven't thought of the try: / except: solution.
I still need some polish to get there, and a systemctl or some daemon which restart's my script if it by any chance will crash.
I still need to dig into how you suggested the try: / except: as i normally use it more "plain"
Also i need to preserve my volume level and restore it when reconnected as you also explained...
My script is working very OK now, so it's a good start.
Rgds; Jesper.
Code:
#!/usr/bin/python3
#################################################
# #
# SuperPlayer Bluetooth (BLE) remote controller #
# #
# Build with help from different sources (www) #
# #
# Jesper Lykke [user :: Lykkedk @ diyaudio.com] #
# #
#################################################
from camilladsp import CamillaConnection
import io
import os
import stat
import subprocess
import sys
from subprocess import call
import time
import serial
cdsp = CamillaConnection("127.0.0.1", 1234)
MUTE = int(0) # Mute = (1) / Unmute = (0)
# CamillaDSP '--gain <gain>': Must be a number between -120 and +20
volume = int(-0) # We start with volume at -0dB
MIN_volume = int(-110) # Lower limit with some proof
MAX_volume = int(-0) # Upper limit without 'clipping'
CN = int(-0) # Set volume default for Unmute / Mute
OLD_value = int(100000) # The same value as encoder is given at start
LONG_press = int(25000) # 25000 = long pressed
DOUBLE_press = int(50000) # 50000 = double pressed
SLEEP_trigger = int(125000) # Value recieved here, just before SuperPlayer-Controller goes to sleep
newline = "\r\n" # To send "newline" serial signal
connected = True
def SEGMENT_TRIGGER():
CNN=abs(CN) # Convert CN [Volume from CamillaDSP / cdsp.get_volume()]
CNNN = (CNN/10) # Divide to fit segment display
CN_STRING = (str(CNNN)) # Convert to string
ser.write(CN_STRING.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
ser.write(newline.encode('utf-8')) # Encode to utf-8 (Arduino) and send this "newline"
ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1) # Setup serial connection
while 1:
connected = cdsp.is_connected()
if not connected:
print("Trying to connect")
try:
cdsp.connect()
connected = cdsp.is_connected()
#print("CamillaDSP is connected")
serialdata = ser.readline()[:-2]
if serialdata:
data = (serialdata.decode('utf-8'))
raw = int(data)
if (MUTE == 0):
if (raw < OLD_value):
volume = (volume -1)
cdsp.connect()
CN=cdsp.get_volume()
if (CN <= MIN_volume):
volume = int(MIN_volume)
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
print ("Volume DOWN :", CN)
SEGMENT_TRIGGER()
OLD_value = raw
if (MUTE == 0):
if (raw > OLD_value):
volume = (volume +1)
cdsp.connect()
CN=cdsp.get_volume()
if (CN >= MAX_volume):
volume = int(MAX_volume)
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
cdsp.connect()
cdsp.set_volume(volume)
CN=cdsp.get_volume()
print ("Volume UP :", CN)
SEGMENT_TRIGGER()
OLD_value = raw
if (raw == LONG_press):
subprocess.call(['mpc', 'pause' ])
raw = OLD_value
if (raw == DOUBLE_press):
print ("Double press")
MUTE = (MUTE + 1) % 2
if (MUTE == 0):
print ("<> Unmute system <>")
cdsp.connect()
cdsp.set_volume(CN)
if (MUTE == 1):
print ("<> Mute system <>")
cdsp.connect()
CN=cdsp.get_volume()
cdsp.set_volume(MIN_volume)
if (raw == SLEEP_trigger):
print ("ESP32 Controller sleep state detected")
Sleep = int(250) # Value tells ESP32 reciever to display sleep state
Sleep_String = (str(Sleep)) # Convert to string
ser.write(Sleep_String.encode('utf-8')) # Encode to utf-8 (Arduino) and send through serial
ser.write(newline.encode('utf-8')) # Encode to utf-8 (Arduino) and send this "newline"
except:
connected = False
serialdata = ser.readline()[:-2]
if serialdata:
data = (serialdata.decode('utf-8'))
raw = int(data)
if (raw == LONG_press):
subprocess.call(['mpc', 'play' ])
raw = OLD_value
time.sleep(2.00)
time.sleep(0.1)