I’m having trouble finding the correct Python code to get this Piicodev POT to adjust the volume of my rPi5. Either master volume or VLC volume, whichever.
So far I have:
Watched numerous videos on this site and youtube.
Practived coding from those videos to ensure the POT is working (it is).
Searched this forum but didn’t find anything useful yet.
Used AI to write code for me. It didn’t work, but figured it would help me learn maybe how to make this work (attempted many things here without luck)
I would appreciate any direction. My coding is novice, but able to read and understand how most things function. Writing ground up is not my thing. Appreciate anything here!
Seems there’s a few different ways that you can achieve this end.
If found a stack overflow topic using a separate package python-alsaaudio which looks promising if you want fine-tuned control for eg. mixing.
This is a good article that I will use when I attempt to setup two buttons to skip and go back a track in the audio player. Though, nothing there for a potentiometer to do the same.
I do like the idea of the button triggering simple commands to adjust volume. If I can’t get these POT’s to do this, I may have two buttons move the volume.
These are called functions and you would call them like this.
if pot_is_all_the_way_to_the_right():
increase_volume() # does everything under the "increase_volume" definition.
elif pot_is_all_the_way_to_the_left():
decrease_volume() # does everything under the "decrease_volume" definition.
but we can do better.
### ** UNTESTED CODE **
##Code stolen from:
##https://core-electronics.com.au/guides/piicodev-potentiometer-getting-started-guide/
from PiicoDev_Potentiometer import PiicoDev_Potentiometer
from subprocess import Popen
pot = PiicoDev_Potentiometer() # Initialise the potentiometer
pot.maximum = 100 # set the range of output values
pot.minimum = 0 # if minimum or maximum are ommitted, they will default to 0 and 100 respectively
while true: #infinite loop
#prepending f in from of the string allows us to embed variables in a string
pot_value_as_percentage = f"{pot.value}%"
#set the volume to be whatever the pot's value.
Popen(['amixer', 'set', 'Speaker', pot_value_as_percentage])
You will need to expand on this code and integrate it to your OS environment. You might also consider using BASH not python just because bash is the right level above the metal for this task. That’s just taste.
I hope this gives you a flavour of how you might proceed.
Good luck.
Pix
P.S.
You might also like to have the code automatically run when the raspberry pi boots up.
I tackled this a few years ago and you can follow my steps towards the bottom of this article under the heading “software”.
P.P.S
@Michael can import the piicodev micropython modules in vanilla python like I have above? (or is there a better way?)
Excellent, thank you. In my mind I was going to take the Piicodev code for the led flash rate (which works) and kinda convert that to deal with volume instead, didn’t think it would be so difficult. Excited to conquer it though! (oh also! I do understand the code and what you are saying it does <3 )
3+ hours in playing with the scripts from all the links. Used Ai to fill in some gaps, or at least learn more of what the code is doing. Using THONNY Assistant to identify where errors are and corrected a few. I feel closer, but no dice quite yet. (got working the LED code to change flash rate and also a basic POT read printouts…so at least the hardware is in a working condition)
Currently sitting at this code, which seems quite straight forward in what it’s to be performing. Only seems a few things it’s not understanding due to defining, it appears.
# Read the PiicoDev Potentiometer value
from PiicoDev_Potentiometer import PiicoDev_Potentiometer
from PiicoDev_Unified import sleep_ms
from subprocess import Popen
pot = PiicoDev_Potentiometer() # Initialise the potentiometer
pot.maximum = 100 # set the range of output values
pot.minimum = 0 # if minimum or maximum are ommitted, they will default to 0 and 100 respectively
# while True:
# print(pot.value) # read the pot and print the result
# sleep_ms(100)
DEBUG = True
MIN_VOLUME = 1
MAX_VOLUME = 100
VOLUME_INCREMENT = 5
def increase_volume():
current_volume = int(get_current_volume())
new_volume = min(current_volume + VOLUME_INCREMENT, MAX_VOLUME)
set_volume(new_volume)
def decrease_volume():
current_volume = int(get_current_volume())
new_volume = max(current_volume - VOLUME_INCREMENT, MIN_VOLUME)
set_volume(new_volume)
def get_current_volume():
return Popen(['amixer', 'get', 'Master'], stdout=subprocess.PIPE).communicate()[0].split(' ')[5].strip('[]%')
def set_volume(volume):
Popen(['amixer', '-D', 'pulse', 'set', 'Master', str(volume) + '%'])
while True:
pot_value = pot.value
if pot_value == pot.maximum:
increase_volume()
elif pot_value == pot.minimum:
decrease_volume()
THONNY Assistant only gives me this last error: NameError: name ‘subprocess’ is not defined read.py, line 30 Python doesn’t know what subprocess stands for.
That would be this line: def get_current_volume():
return Popen([‘amixer’, ‘get’, ‘Master’], stdout=subprocess.PIPE).communicate()[0].split(’ ‘)[5].strip(’[]%')
You are importing the module Popen from the package subprocess, so the Pipe() module is not available. Either import the whole subprocess package (and change your references to Popen() to include the subprocess identifier) or import Pipe from subprocess (and change the Pipe() reference to remove the subprocess identifier).
You can avoid the need to get the current volume by setting the volume to some arbitrary value before starting the loop. If you then keep track of how this value changes by adjusting it as appropriate in the increase and decrease methods, then you will always know what the current volume is without the need to query it. Your current_volume variable will need to be declared at the global level so the value is accessible to all methods.
Good suggestions on a cleaner approach, appreciate that.
I’ve been using https://www.blackbox.ai/ to ask questions and solve a bunch of little errors and questions I had. Here is what has been updated:
1. defined current volume globally as suggested (have had a few versions of this)
2. imported subprocess as a whole and updated Popen calls (this fixed the Popen issues)
3. Added - set the volume 30% at start (for i know the code is working and able to test using the potentiometer)
I’ve got one step further! Now it starts the volume at 30%. I can turn the POT, but the volume doesn’t change…until I hit under ~5% or over ~95%, then the volume automatically jumps to zero (which is the error return value in current_value. I asked AI about this and it gave me a few def current_volume suggestions which aren’t working quite yet.
Everyone, I appreciate the direction! I come from a time where I built beige boxes to mess with payphones, so I appreciate you bearing with me.
That’s what the code is doing. In effect, it is “If the pot is turned to its maximum value, then increase the volume a bit. If the pot is set to its minimum value then decrease the volume a bit”. It appears to be based on switches rather than a pot. It is typical for a pot to hit the minimum and maximum values just short of the full rotation.
I would recommend adding a debug print statement into the main loop to continually show the value of the pot. Note the values you get at minimum and maximum rotation. Then change the rest of the main loop to:
Just got it working, sort of. It’s just as you said. If the POT is at 100%, the reading (volume) slowly climbs. And at 0% slowly goes down.
This is the return as it’s climbing/lowering
Simple mixer control ‘Master’,0
Capabilities: pvolume pswitch pswitch-joined
Playback channels: Front Left - Front Right
Limits: Playback 0 - 65536
Mono:
Front Left: Playback 28836 [44%] [on]
Front Right: Playback 28836 [44%] [on]
I was just thinking maybe it had to do with mono versus stereo, but suppose not.
compare if the current pot value is different from the last value
if the difference is large enough, update the volume
this won’t work flawlessly, there will be a little deadband around the current value, but it might be enough to get you over the line
# Read the PiicoDev Potentiometer value
from PiicoDev_Potentiometer import PiicoDev_Potentiometer
from PiicoDev_Unified import sleep_ms
from subprocess import Popen
pot = PiicoDev_Potentiometer() # Initialise the potentiometer
pot.maximum = 100 # set the range of output values
pot.minimum = 0 # if minimum or maximum are ommitted, they will default to 0 and 100 respectively
def set_volume(volume):
Popen(['amixer', '-D', 'pulse', 'set', 'Master', str(volume) + '%'])
last_value = pot.value
while True:
pot_value = pot.value
if abs(pot_value - last_value) > 2: # look for changes in the volume knob
new_volume = pot_value
last_value = pot_value
set_volume(new_volume)
this code is untested… good luck everybody
aside: no mapping should be necessary, because we get to initialise the potentiometer with whatever min/max values we like custom mapping is only required if you don’t want linear mapping between the max and min.
@Michael I used your simple idea of READ, COMPARE, IF DIFFERENCE and started over with AI help. It only took two tries.
As with many things, the simplest approach works quite well, though it can take a lot of work to figure out that “simple”. That’s just how it goes.
I truly appreciate all of you helping me learn coding that I knew nothing about 2 weeks ago. Through lots of trial and error (this took me 5 hours) I got this working!
Here is a link to the Old Radio Project I’m working on that I needed this coding for. It’s a rebuilding of an old radio from my fathers childhood that auto plays old radio shows and music. Excited to complete this and gift it to him!
Thank you kindly @Michael@Pixmusix Jeff105671 and cheers to Robert93820 (I’m new and it only allows me to tag 2 users )
Here is the working code:
# Read the PiicoDev Potentiometer value
from PiicoDev_Potentiometer import PiicoDev_Potentiometer
from subprocess import Popen
pot = PiicoDev_Potentiometer() # Initialise the potentiometer
pot.maximum = 100 # set the range of output values
pot.minimum = 0 # if minimum or maximum are ommitted, they will default to 0 and 100 respectively
def set_volume(volume):
try:
Popen(['amixer', '-D', 'pulse', 'set', 'Master', str(volume) + '%'])
except Exception as e:
print(f"Error setting volume: {e}")
last_value = pot.value
while True:
pot_value = pot.value
if abs(pot_value - last_value) > 2: # look for changes in the volume knob
new_volume = pot_value
last_value = pot_value
set_volume(new_volume)