Add auto-update for missing configuration settings

Implemented automatic config file updates to add missing settings
with default values on startup. This eliminates manual config
editing when upgrading to newer versions.

Features:
- Auto-updates config.json with missing settings
- Auto-updates user_config.json with missing user preferences
- Console logging shows which settings were added
- Preserves existing values - only adds missing keys
- Writes updated config back to file automatically
- Graceful error handling if write fails

System config (config.json):
- Comprehensive defaults for all sections
- GPIO, audio, paths, backup, web, system settings
- New settings like volume_greeting, volume_button, volume_beep

User config (user_config.json):
- Loop-based checking against default_config
- Automatic save when updates are detected
- Error logging for troubleshooting

Benefits:
- Seamless upgrades without manual config edits
- No breaking changes when new features are added
- Users see exactly what was added in console
- Backward compatible with old config files

Example console output:
  [CONFIG] Added missing setting: system.volume_beep = 70
  [CONFIG] Updated config.json with missing defaults
  [USER_CONFIG] Added missing setting: volume_button = 70
  [USER_CONFIG] Updated user_config.json with missing defaults

Updated README.md to document auto-update feature.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-10-27 16:02:50 +07:00
parent b219619f24
commit 1b1a40b094
2 changed files with 104 additions and 18 deletions

View File

@@ -491,6 +491,18 @@ rotary_phone_data/ # Default location (configurable)
All configuration is done via the `config.json` file. **No need to edit Python code!**
### Auto-Update Feature
The system automatically adds missing configuration settings with default values when it starts:
- **config.json** - System configuration is auto-updated with any missing settings
- **user_config.json** - User settings are auto-updated with new defaults
- Console shows which settings were added: `[CONFIG] Added missing setting: system.volume_beep = 70`
- Original config is preserved - only missing keys are added
- No manual editing required when upgrading to newer versions
This means you can upgrade the code and your old config files will work automatically!
### Configuration File Structure
The `config.json` file contains all system settings:

View File

@@ -24,7 +24,7 @@ import io
# Load configuration
def load_system_config():
"""Load system configuration from config.json"""
"""Load system configuration from config.json and auto-update with missing defaults"""
config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.json')
# Check if config exists, otherwise use example
@@ -39,7 +39,77 @@ def load_system_config():
sys.exit(1)
with open(config_path, 'r') as f:
return json.load(f)
config = json.load(f)
# Default values for all settings
defaults = {
'gpio': {
'hook_pin': 17,
'hook_pressed_state': 'LOW',
'extra_button_enabled': False,
'extra_button_pin': 27,
'extra_button_pressed_state': 'LOW'
},
'audio': {
'device_index': 1,
'chunk_size': 1024,
'format': 'paInt16',
'channels': 1,
'sample_rate': 48000,
'max_record_seconds': 300
},
'paths': {
'base_dir': './rotary_phone_data',
'recordings_dir': 'recordings',
'sounds_dir': 'sounds'
},
'backup': {
'enabled': True,
'usb_paths': ['/media/usb0', '/media/usb1'],
'verify_crc': True,
'backup_on_write': True
},
'web': {
'port': 8080,
'max_upload_size_mb': 50
},
'system': {
'active_greeting': 'dialtone.wav',
'extra_button_sound': 'button_sound.wav',
'beep_sound': 'beep.wav',
'beep_enabled': True,
'greeting_delay_seconds': 0,
'volume': 70,
'volume_greeting': 70,
'volume_button': 70,
'volume_beep': 70
}
}
# Check if any defaults are missing and add them
updated = False
for section, section_defaults in defaults.items():
if section not in config:
config[section] = section_defaults
updated = True
print(f"[CONFIG] Added missing section: {section}")
else:
for key, default_value in section_defaults.items():
if key not in config[section]:
config[section][key] = default_value
updated = True
print(f"[CONFIG] Added missing setting: {section}.{key} = {default_value}")
# Save updated config if changes were made
if updated:
try:
with open(config_path, 'w') as f:
json.dump(config, f, indent=2)
print(f"[CONFIG] Updated config.json with missing defaults")
except Exception as e:
print(f"[CONFIG] Warning: Could not save updated config: {e}")
return config
# Load system configuration
SYS_CONFIG = load_system_config()
@@ -274,23 +344,27 @@ class RotaryPhone:
try:
with open(USER_CONFIG_FILE, 'r') as f:
config = json.load(f)
# Ensure required keys exist
if "volume" not in config:
config["volume"] = SYS_CONFIG['system']['volume']
if "volume_greeting" not in config:
config["volume_greeting"] = SYS_CONFIG['system'].get('volume_greeting', 70)
if "volume_button" not in config:
config["volume_button"] = SYS_CONFIG['system'].get('volume_button', 70)
if "volume_beep" not in config:
config["volume_beep"] = SYS_CONFIG['system'].get('volume_beep', 70)
if "greeting_delay" not in config:
config["greeting_delay"] = SYS_CONFIG['system'].get('greeting_delay_seconds', 0)
if "beep_enabled" not in config:
config["beep_enabled"] = SYS_CONFIG['system'].get('beep_enabled', True)
if "beep_sound" not in config:
config["beep_sound"] = SYS_CONFIG['system'].get('beep_sound', 'beep.wav')
# Check for missing keys and add defaults
updated = False
for key, default_value in default_config.items():
if key not in config:
config[key] = default_value
updated = True
print(f"[USER_CONFIG] Added missing setting: {key} = {default_value}")
# Save updated config if changes were made
if updated:
try:
with open(USER_CONFIG_FILE, 'w') as fw:
json.dump(config, fw, indent=2)
print(f"[USER_CONFIG] Updated user_config.json with missing defaults")
except Exception as e:
print(f"[USER_CONFIG] Warning: Could not save updated config: {e}")
return config
except:
except Exception as e:
print(f"[USER_CONFIG] Error loading user config: {e}, using defaults")
pass
return default_config