This repository was archived by the owner on Aug 16, 2026. It is now read-only.
Description Device / version
Miyoo Mini Flip
SprigUI v1.3.1 (68504009)
Also present on current development (63c7b338)
Reproduction
Open Home → Settings → Volume.
Press Right repeatedly. The displayed value stops at 10.
Use the physical side volume buttons; that path can reach 20.
With the side-button value at 20, press Left once in Settings.
Actual behavior
Home Settings is capped at 10.
A Settings adjustment can apply two hardware levels for one displayed step.
Pressing Left from a side-button value of 20 can collapse it to 10 instead of 19.
PyUI startup can rewrite stored values 11–20 back to 10.
Expected behavior
Settings and the side buttons should use the same 0–20 range.
Each input should change one stored/hardware level.
20 → Left should produce 19.
Stored values 11–20 should survive PyUI startup.
Root cause
The rest of Sprig uses a stored/hardware range of 0–20:
SystemConfig.get_volume() maps stored volume to PyUI with * 5, and set_volume() maps it back with // 5:
def get_volume (self ):
return self .config .get ("vol" , 0 ) * 5
def set_volume (self , value ):
if (value == 0 ):
self .config ["mute" ] = 1
else :
self .config ["mute" ] = 0
self .config ["vol" ] = value // 5
The generic Settings row changes PyUI volume by 5 and displays get_volume() // 5:
def volume_adjust (self , input : ControllerInput ):
if (ControllerInput .DPAD_LEFT == input ):
Device .change_volume (- 5 )
elif (ControllerInput .L1 == input ):
Device .change_volume (- 5 )
elif (ControllerInput .DPAD_RIGHT == input ):
Device .change_volume (+ 5 )
elif (ControllerInput .R1 == input ):
Device .change_volume (+ 5 )
if (Device .supports_volume ()):
option_list .append (
GridOrListEntry (
primary_text = Language .volume (),
value_text = "< " + str (Device .get_volume ()// 5 ) + " >" ,
image_path = None ,
image_path_selected = None ,
description = None ,
icon = None ,
value = self .volume_adjust
)
The shell/side-button path directly uses stored levels 0–20:
# ######### VOLUME CONTROL ##########
MIN_RAW_VOLUME=-60
MAX_RAW_VOLUME=30
MAX_VOLUME=20
# Set volume level (0-20)
# Usage: set_volume 15
set_volume () {
local volume=" $1 "
# Clamp volume between 0 and MAX_VOLUME
[ " $volume " -lt 0 ] && volume=0
[ " $volume " -gt " $MAX_VOLUME " ] && volume=" $MAX_VOLUME "
# Save volume to config
set_pyui_config_value " .vol" " $volume "
# Calculate raw volume using logarithmic curve
local volume_raw=0
if [ " $volume " -ne 0 ]; then
# Using integer arithmetic: volume_raw = round(48 * log10(1 + volume))
# Approximation using lookup table for integer math
case " $volume " in
1) volume_raw=-44 ;;
2) volume_raw=-37 ;;
3) volume_raw=-32 ;;
4) volume_raw=-29 ;;
5) volume_raw=-26 ;;
6) volume_raw=-24 ;;
7) volume_raw=-22 ;;
8) volume_raw=-20 ;;
9) volume_raw=-18 ;;
10) volume_raw=-17 ;;
11) volume_raw=-15 ;;
12) volume_raw=-14 ;;
13) volume_raw=-13 ;;
14) volume_raw=-12 ;;
15) volume_raw=-11 ;;
16) volume_raw=-10 ;;
17) volume_raw=-9 ;;
18) volume_raw=-8 ;;
19) volume_raw=-7 ;;
20) volume_raw=-6 ;;
* ) volume_raw=" $MIN_RAW_VOLUME " ;;
esac
else
volume_raw=" $MIN_RAW_VOLUME "
fi
# Apply volume using hardware interface
set_volume_raw " $volume_raw "
log_message " Volume set to $volume (raw: ${volume_raw} dB)" -v
}
# Set raw hardware volume
# Usage: set_volume_raw -20
set_volume_raw () {
local volume_raw=" $1 "
# Clamp to hardware limits
[ " $volume_raw " -lt " $MIN_RAW_VOLUME " ] && volume_raw=" $MIN_RAW_VOLUME "
[ " $volume_raw " -gt " $MAX_RAW_VOLUME " ] && volume_raw=" $MAX_RAW_VOLUME "
# Set volume via hardware interface
if [ -e /proc/mi_modules/mi_ao/mi_ao0 ]; then
echo " set_ao_volume 0 ${volume_raw} dB" > /proc/mi_modules/mi_ao/mi_ao0 2> /dev/null
echo " set_ao_volume 1 ${volume_raw} dB" > /proc/mi_modules/mi_ao/mi_ao0 2> /dev/null
# Handle mute state
if [ " $volume_raw " -le " $MIN_RAW_VOLUME " ]; then
echo " set_ao_mute 1" > /proc/mi_modules/mi_ao/mi_ao0 2> /dev/null
else
echo " set_ao_mute 0" > /proc/mi_modules/mi_ao/mi_ao0 2> /dev/null
fi
fi
}
# Increase volume
# Usage: volume_up
volume_up () {
local current_volume
current_volume=$( get_pyui_config_value " .vol" 10)
local new_volume=$(( current_volume + 1 ))
set_volume " $new_volume "
}
# Decrease volume
# Usage: volume_down
volume_down () {
local current_volume
current_volume=$( get_pyui_config_value " .vol" 10)
local new_volume=$(( current_volume - 1 ))
set_volume " $new_volume "
Only SprigMiyooMiniCommon clamps PyUI to 0–50 and rescales that to hardware 0–20:
def change_volume (self , amount ):
"""Override to handle Sprig's 0-50 volume range (displays as 0-10)"""
from display .display import Display
# Get current volume (0-50 range for display as 0-10)
volume = self .get_volume () + amount
# Clamp to 0-50 for Sprig
if volume < 0 :
volume = 0
elif volume > 50 :
volume = 50
self ._set_volume (volume )
Display .volume_changed (self .get_volume ())
PyUiLogger .get_logger ().info (f"Volume changed by { amount } to { volume } " )
def _set_volume (self , volume : int ) -> int :
"""Set volume using direct hardware control for instant feedback"""
try :
# Clamp volume between 0 and 50 (displays as 0-10)
volume = max (0 , min (50 , volume ))
# Scale from 0-50 to 0-20 for hardware
volume_hw = int (volume * 20 / 50 ) # Maps 0-50 to 0-20
# Hardware volume mapping (same as helperFunctions.sh)
volume_map = {
0 : - 60 , 1 : - 44 , 2 : - 37 , 3 : - 32 , 4 : - 29 , 5 : - 26 ,
6 : - 24 , 7 : - 22 , 8 : - 20 , 9 : - 18 , 10 : - 17 , 11 : - 15 ,
12 : - 14 , 13 : - 13 , 14 : - 12 , 15 : - 11 , 16 : - 10 ,
17 : - 9 , 18 : - 8 , 19 : - 7 , 20 : - 6
}
volume_raw = volume_map .get (volume_hw , - 60 )
try :
with open ("/proc/mi_modules/mi_ao/mi_ao0" , "w" ) as f :
f .write (f"set_ao_volume 0 { volume_raw } dB\n " )
f .write (f"set_ao_volume 1 { volume_raw } dB\n " )
# Handle mute state
if volume_raw <= - 60 :
f .write ("set_ao_mute 1\n " )
else :
f .write ("set_ao_mute 0\n " )
except Exception as e :
PyUiLogger .get_logger ().warning (f"Direct hardware control failed, falling back to shell: { e } " )
# Fallback if hw access fails
subprocess .run ([
"/bin/sh" , "-c" ,
f". /mnt/SDCARD/sprig/helperFunctions.sh && set_volume { volume_hw } "
], check = False )
# Update system config
self .system_config .set_volume (volume )
self .system_config .save_config ()
PyUiLogger .get_logger ().info (f"Sprig volume set to { volume } (hw:{ volume_hw } , raw:{ volume_raw } dB)" )
That 0–50 adapter conflicts with the surrounding 0–100 PyUI ↔ 0–20 stored-volume contract.
Minimal fix
The fix can stay isolated to the Mini Flip adapter:
Clamp PyUI volume to 0–100 in change_volume() and _set_volume().
Convert PyUI to stored/hardware volume with volume_hw = volume // 5.
Keep the existing 0–20 hardware table, mute-at-zero behavior, and SystemConfig persistence.
I tested that one-file correction on hardware across all 21 levels, both clamps, 20 → 19, side-button/Settings interoperability, and persistence through a reboot. The next boot initialized at 20 as expected.
There are also two stale fallback paths in the same class: they source /mnt/SDCARD/sprig/helperFunctions.sh, while the installed helper is /mnt/SDCARD/sprig/scripts/helperFunctions.sh.
Reactions are currently unavailable
Device / version
68504009)development(63c7b338)Reproduction
Actual behavior
Expected behavior
Root cause
The rest of Sprig uses a stored/hardware range of 0–20:
SystemConfig.get_volume()maps stored volume to PyUI with* 5, andset_volume()maps it back with// 5:sprigUI/App/PyUI/main-ui/devices/miyoo/system_config.py
Lines 32 to 33 in 63c7b33
sprigUI/App/PyUI/main-ui/devices/miyoo/system_config.py
Lines 110 to 115 in 63c7b33
The generic Settings row changes PyUI volume by 5 and displays
get_volume() // 5:sprigUI/App/PyUI/main-ui/menus/settings/basic_settings_menu.py
Lines 42 to 50 in 63c7b33
sprigUI/App/PyUI/main-ui/menus/settings/basic_settings_menu.py
Lines 159 to 169 in 63c7b33
The shell/side-button path directly uses stored levels 0–20:
sprigUI/sprig/scripts/helperFunctions.sh
Lines 206 to 300 in 63c7b33
Only
SprigMiyooMiniCommonclamps PyUI to 0–50 and rescales that to hardware 0–20:sprigUI/App/PyUI/main-ui/devices/miyoo/mini/sprig_miyoo_mini_common.py
Lines 82 to 140 in 63c7b33
That 0–50 adapter conflicts with the surrounding 0–100 PyUI ↔ 0–20 stored-volume contract.
Minimal fix
The fix can stay isolated to the Mini Flip adapter:
change_volume()and_set_volume().volume_hw = volume // 5.SystemConfigpersistence.I tested that one-file correction on hardware across all 21 levels, both clamps, 20 → 19, side-button/Settings interoperability, and persistence through a reboot. The next boot initialized at 20 as expected.
There are also two stale fallback paths in the same class: they source
/mnt/SDCARD/sprig/helperFunctions.sh, while the installed helper is/mnt/SDCARD/sprig/scripts/helperFunctions.sh.