add cpu power mode
This commit is contained in:
101
html/admin.html
101
html/admin.html
@@ -128,6 +128,20 @@
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="cpu_power_mode" class="form-label">CPU Power Mode</label>
|
||||
<select class="form-select" id="cpu_power_mode" onchange="set_cpu_power_mode(this.value)">
|
||||
<option value="normal">Normal (600-1500MHz dynamic)</option>
|
||||
<option value="powersave">Power Saving (600MHz fixed)</option>
|
||||
</select>
|
||||
<small class="form-text text-muted d-block">
|
||||
<span id="cpu_mode_status" class="text-success"></span>
|
||||
</small>
|
||||
<small class="form-text text-muted d-block">
|
||||
Power saving mode reduces CPU performance by ~30-40% but saves power.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<span class="fw-bold">Protected Settings</span>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="toggleProtectedSettings()" id="unlockBtn">
|
||||
@@ -423,6 +437,16 @@ window.onload = function() {
|
||||
checkbox_aircarto.checked = response["send_aircarto"];
|
||||
checkbox_miotiq.checked = response["send_miotiq"];
|
||||
|
||||
// Set CPU power mode
|
||||
const cpu_power_mode_select = document.getElementById("cpu_power_mode");
|
||||
if (response["cpu_power_mode"]) {
|
||||
cpu_power_mode_select.value = response["cpu_power_mode"];
|
||||
// Update status display
|
||||
const statusElement = document.getElementById('cpu_mode_status');
|
||||
statusElement.textContent = `Current: ${response["cpu_power_mode"]}`;
|
||||
statusElement.className = 'text-success';
|
||||
}
|
||||
|
||||
// If envea is enabled, show the envea sondes container
|
||||
if (response["envea"]) {
|
||||
add_sondeEnveaContainer();
|
||||
@@ -589,6 +613,83 @@ function update_config_sqlite(param, value){
|
||||
}
|
||||
|
||||
|
||||
function set_cpu_power_mode(mode) {
|
||||
console.log("Setting CPU power mode to:", mode);
|
||||
|
||||
const toastLiveExample = document.getElementById('liveToast');
|
||||
const toastBody = toastLiveExample.querySelector('.toast-body');
|
||||
const statusElement = document.getElementById('cpu_mode_status');
|
||||
|
||||
// Show loading status
|
||||
statusElement.textContent = 'Applying mode...';
|
||||
statusElement.className = 'text-warning';
|
||||
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=set_cpu_power_mode&mode=' + mode,
|
||||
dataType: 'json',
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
success: function(response) {
|
||||
console.log(response);
|
||||
|
||||
let formattedMessage;
|
||||
|
||||
if (response.success) {
|
||||
// Success message
|
||||
toastLiveExample.classList.remove('text-bg-danger');
|
||||
toastLiveExample.classList.add('text-bg-success');
|
||||
|
||||
formattedMessage = `
|
||||
<strong>Success!</strong><br>
|
||||
CPU mode set to: <strong>${mode}</strong><br>
|
||||
${response.description || ''}
|
||||
`;
|
||||
|
||||
// Update status
|
||||
statusElement.textContent = `Current: ${mode}`;
|
||||
statusElement.className = 'text-success';
|
||||
|
||||
} else {
|
||||
// Error message
|
||||
toastLiveExample.classList.remove('text-bg-success');
|
||||
toastLiveExample.classList.add('text-bg-danger');
|
||||
|
||||
formattedMessage = `
|
||||
<strong>Error!</strong><br>
|
||||
${response.error || 'Failed to set CPU power mode'}
|
||||
`;
|
||||
|
||||
// Reset status
|
||||
statusElement.textContent = 'Error setting mode';
|
||||
statusElement.className = 'text-danger';
|
||||
}
|
||||
|
||||
// Update the toast body with formatted content
|
||||
toastBody.innerHTML = formattedMessage;
|
||||
|
||||
// Show the toast
|
||||
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample);
|
||||
toastBootstrap.show();
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('AJAX request failed:', status, error);
|
||||
|
||||
// Show error in toast
|
||||
toastLiveExample.classList.remove('text-bg-success');
|
||||
toastLiveExample.classList.add('text-bg-danger');
|
||||
toastBody.innerHTML = `<strong>Error!</strong><br>Network error: ${error}`;
|
||||
|
||||
const toastBootstrap = bootstrap.Toast.getOrCreateInstance(toastLiveExample);
|
||||
toastBootstrap.show();
|
||||
|
||||
// Update status
|
||||
statusElement.textContent = 'Network error';
|
||||
statusElement.className = 'text-danger';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function update_config(param, value){
|
||||
console.log("Updating ",param," : ", value);
|
||||
$.ajax({
|
||||
|
||||
@@ -1423,3 +1423,95 @@ if ($type == "detect_envea_device") {
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
____ ____ _ _ ____ __ __ _
|
||||
/ ___| _ \| | | | | _ \ _____ _____ _ _| \/ | __ _ _ __ __ _ __ _ ___ _ __ ___ ___ _ __ | |_
|
||||
| | | |_) | | | | | |_) / _ \ \ /\ / / _ \ '__| |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '_ ` _ \ / _ \ '_ \| __|
|
||||
| |___| __/| |_| | | __/ (_) \ V V / __/ | | | | | (_| | | | | (_| | (_| | __/ | | | | | __/ | | | |_
|
||||
\____|_| \___/ |_| \___/ \_/\_/ \___|_| |_| |_|\__,_|_| |_|\__,_|\__, |\___|_| |_| |_|\___|_| |_|\__|
|
||||
|___/
|
||||
*/
|
||||
|
||||
// Get current CPU power mode
|
||||
if ($type == "get_cpu_power_mode") {
|
||||
try {
|
||||
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py get 2>&1';
|
||||
$output = shell_exec($command);
|
||||
|
||||
// Try to parse JSON output
|
||||
$result = json_decode($output, true);
|
||||
|
||||
if ($result && isset($result['success']) && $result['success']) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'mode' => $result['config_mode'] ?? 'unknown',
|
||||
'cpu_state' => $result['cpu_state'] ?? null
|
||||
], JSON_PRETTY_PRINT);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Failed to get CPU power mode',
|
||||
'output' => $output
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Script execution failed: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Set CPU power mode
|
||||
if ($type == "set_cpu_power_mode") {
|
||||
$mode = $_GET['mode'] ?? null;
|
||||
|
||||
if (empty($mode)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'No mode specified'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validate mode (whitelist)
|
||||
$allowedModes = ['normal', 'powersave'];
|
||||
|
||||
if (!in_array($mode, $allowedModes)) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Invalid mode. Allowed: normal, powersave'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// Execute the CPU power mode script
|
||||
$command = 'sudo /usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py ' . escapeshellarg($mode) . ' 2>&1';
|
||||
$output = shell_exec($command);
|
||||
|
||||
// Try to parse JSON output
|
||||
$result = json_decode($output, true);
|
||||
|
||||
if ($result && isset($result['success']) && $result['success']) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'mode' => $mode,
|
||||
'message' => "CPU power mode set to: $mode",
|
||||
'description' => $result['description'] ?? ''
|
||||
], JSON_PRETTY_PRINT);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => $result['error'] ?? 'Failed to set CPU power mode',
|
||||
'output' => $output
|
||||
]);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Script execution failed: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,11 +141,11 @@ if ! sudo visudo -c; then
|
||||
error "Sudoers file has syntax errors! Please fix manually with 'sudo visudo'"
|
||||
fi
|
||||
|
||||
# Open all UART serial ports and disable HDMI (avoid duplication)
|
||||
info "Configuring UART serial ports and disabling HDMI to save power..."
|
||||
# Open all UART serial ports and disable HDMI + Bluetooth (avoid duplication)
|
||||
info "Configuring UART serial ports and disabling HDMI/Bluetooth to save power..."
|
||||
if ! grep -q "enable_uart=1" /boot/firmware/config.txt; then
|
||||
echo -e "\nenable_uart=1\ndtoverlay=uart0\ndtoverlay=uart1\ndtoverlay=uart2\ndtoverlay=uart3\ndtoverlay=uart4\ndtoverlay=uart5\n\n# Disable HDMI to save power (~20-30mA)\nhdmi_blanking=2" | sudo tee -a /boot/firmware/config.txt > /dev/null
|
||||
success "UART configuration and HDMI disable added."
|
||||
echo -e "\nenable_uart=1\ndtoverlay=uart0\ndtoverlay=uart1\ndtoverlay=uart2\ndtoverlay=uart3\ndtoverlay=uart4\ndtoverlay=uart5\n\n# Disable HDMI to save power (~20-30mA)\nhdmi_blanking=2\n\n# Disable Bluetooth to save power (~20-30mA)\ndtoverlay=disable-bt" | sudo tee -a /boot/firmware/config.txt > /dev/null
|
||||
success "UART configuration, HDMI and Bluetooth disable added."
|
||||
else
|
||||
warning "UART configuration already set. Skipping."
|
||||
fi
|
||||
|
||||
71
power/apply_cpu_mode_from_db.py
Normal file
71
power/apply_cpu_mode_from_db.py
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Apply CPU Power Mode from Database at Boot
|
||||
|
||||
This script is called by systemd at boot to apply the CPU power mode
|
||||
stored in the database (cpu_power_mode config parameter).
|
||||
|
||||
Usage:
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/power/apply_cpu_mode_from_db.py
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
DB_PATH = "/var/www/nebuleair_pro_4g/sqlite/sensors.db"
|
||||
SET_MODE_SCRIPT = "/var/www/nebuleair_pro_4g/power/set_cpu_mode.py"
|
||||
|
||||
def get_cpu_mode_from_db():
|
||||
"""Read cpu_power_mode from database"""
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT value FROM config_table WHERE key = 'cpu_power_mode'")
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
return result[0] if result else None
|
||||
except sqlite3.Error as e:
|
||||
print(f"Database error: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
print("=== Applying CPU Power Mode from Database ===")
|
||||
|
||||
# Get mode from database
|
||||
mode = get_cpu_mode_from_db()
|
||||
|
||||
if mode is None:
|
||||
print("No cpu_power_mode found in database, using default: normal")
|
||||
mode = "normal"
|
||||
|
||||
print(f"CPU power mode from database: {mode}")
|
||||
|
||||
# Call set_cpu_mode.py to apply the mode
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["/usr/bin/python3", SET_MODE_SCRIPT, mode],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
print(f"Successfully applied CPU power mode: {mode}")
|
||||
print(result.stdout)
|
||||
return 0
|
||||
else:
|
||||
print(f"Failed to apply CPU power mode: {mode}", file=sys.stderr)
|
||||
print(result.stderr, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
print("Timeout while applying CPU power mode", file=sys.stderr)
|
||||
return 1
|
||||
except Exception as e:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
256
power/set_cpu_mode.py
Normal file
256
power/set_cpu_mode.py
Normal file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
____ ____ _ _ ____ __ __ _
|
||||
/ ___| _ \| | | | | _ \ _____ _____ _ _| \/ | ___ __| | ___
|
||||
| | | |_) | | | | | |_) / _ \ \ /\ / / _ \ '__| |\/| |/ _ \ / _` |/ _ \
|
||||
| |___| __/| |_| | | __/ (_) \ V V / __/ | | | | | (_) | (_| | __/
|
||||
\____|_| \___/ |_| \___/ \_/\_/ \___|_| |_| |_|\___/ \__,_|\___|
|
||||
|
||||
CPU Power Mode Management Script
|
||||
Switches between Normal and Power Saving CPU modes.
|
||||
|
||||
Modes:
|
||||
- normal: CPU governor ondemand (600MHz-1500MHz dynamic)
|
||||
- powersave: CPU governor powersave (600MHz fixed)
|
||||
|
||||
Usage:
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py <mode>
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py normal
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py powersave
|
||||
|
||||
Or get current mode:
|
||||
/usr/bin/python3 /var/www/nebuleair_pro_4g/power/set_cpu_mode.py get
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
import datetime
|
||||
import json
|
||||
|
||||
# Paths
|
||||
DB_PATH = "/var/www/nebuleair_pro_4g/sqlite/sensors.db"
|
||||
LOG_PATH = "/var/www/nebuleair_pro_4g/logs/app.log"
|
||||
|
||||
# Available modes
|
||||
MODES = {
|
||||
"normal": {
|
||||
"governor": "ondemand",
|
||||
"description": "Normal mode - CPU 600MHz-1500MHz dynamic",
|
||||
"min_freq": 600000, # 600 MHz in kHz
|
||||
"max_freq": 1500000 # 1500 MHz in kHz
|
||||
},
|
||||
"powersave": {
|
||||
"governor": "powersave",
|
||||
"description": "Power saving mode - CPU 600MHz fixed",
|
||||
"min_freq": 600000,
|
||||
"max_freq": 600000
|
||||
}
|
||||
}
|
||||
|
||||
def log_message(message):
|
||||
"""Write message to log file with timestamp"""
|
||||
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
log_entry = f"[{timestamp}] [CPU Power Mode] {message}\n"
|
||||
try:
|
||||
with open(LOG_PATH, "a") as log_file:
|
||||
log_file.write(log_entry)
|
||||
except Exception as e:
|
||||
print(f"Failed to write to log: {e}", file=sys.stderr)
|
||||
print(log_entry.strip())
|
||||
|
||||
def get_cpu_count():
|
||||
"""Get number of CPU cores"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
["nproc"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
return int(result.stdout.strip())
|
||||
except Exception as e:
|
||||
log_message(f"Failed to get CPU count: {e}")
|
||||
return 4 # Default to 4 cores for CM4
|
||||
|
||||
def set_cpu_governor(governor, cpu_id):
|
||||
"""Set CPU governor for specific CPU core"""
|
||||
try:
|
||||
with open(f"/sys/devices/system/cpu/cpu{cpu_id}/cpufreq/scaling_governor", "w") as f:
|
||||
f.write(governor)
|
||||
return True
|
||||
except Exception as e:
|
||||
log_message(f"Failed to set governor for CPU{cpu_id}: {e}")
|
||||
return False
|
||||
|
||||
def set_cpu_freq(min_freq, max_freq, cpu_id):
|
||||
"""Set CPU frequency limits for specific CPU core"""
|
||||
try:
|
||||
# Set min frequency
|
||||
with open(f"/sys/devices/system/cpu/cpu{cpu_id}/cpufreq/scaling_min_freq", "w") as f:
|
||||
f.write(str(min_freq))
|
||||
|
||||
# Set max frequency
|
||||
with open(f"/sys/devices/system/cpu/cpu{cpu_id}/cpufreq/scaling_max_freq", "w") as f:
|
||||
f.write(str(max_freq))
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
log_message(f"Failed to set frequency for CPU{cpu_id}: {e}")
|
||||
return False
|
||||
|
||||
def get_current_cpu_state():
|
||||
"""Get current CPU governor and frequencies"""
|
||||
try:
|
||||
with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r") as f:
|
||||
governor = f.read().strip()
|
||||
|
||||
with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r") as f:
|
||||
min_freq = int(f.read().strip())
|
||||
|
||||
with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", "r") as f:
|
||||
max_freq = int(f.read().strip())
|
||||
|
||||
with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq", "r") as f:
|
||||
cur_freq = int(f.read().strip())
|
||||
|
||||
return {
|
||||
"governor": governor,
|
||||
"min_freq_khz": min_freq,
|
||||
"max_freq_khz": max_freq,
|
||||
"current_freq_khz": cur_freq,
|
||||
"min_freq_mhz": min_freq / 1000,
|
||||
"max_freq_mhz": max_freq / 1000,
|
||||
"current_freq_mhz": cur_freq / 1000
|
||||
}
|
||||
except Exception as e:
|
||||
log_message(f"Failed to get current CPU state: {e}")
|
||||
return None
|
||||
|
||||
def update_config_db(mode):
|
||||
"""Update cpu_power_mode in database"""
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"UPDATE config_table SET value = ? WHERE key = 'cpu_power_mode'",
|
||||
(mode,)
|
||||
)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
except sqlite3.Error as e:
|
||||
log_message(f"Database error: {e}")
|
||||
return False
|
||||
|
||||
def get_config_from_db():
|
||||
"""Read cpu_power_mode from database"""
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT value FROM config_table WHERE key = 'cpu_power_mode'")
|
||||
result = cursor.fetchone()
|
||||
conn.close()
|
||||
return result[0] if result else None
|
||||
except sqlite3.Error as e:
|
||||
log_message(f"Database error: {e}")
|
||||
return None
|
||||
|
||||
def apply_mode(mode):
|
||||
"""Apply CPU power mode"""
|
||||
if mode not in MODES:
|
||||
log_message(f"Invalid mode: {mode}. Valid modes: {', '.join(MODES.keys())}")
|
||||
return False
|
||||
|
||||
mode_config = MODES[mode]
|
||||
log_message(f"Applying mode: {mode} - {mode_config['description']}")
|
||||
|
||||
cpu_count = get_cpu_count()
|
||||
log_message(f"Detected {cpu_count} CPU cores")
|
||||
|
||||
success = True
|
||||
|
||||
# Apply settings to all CPU cores
|
||||
for cpu_id in range(cpu_count):
|
||||
# Set frequency limits first
|
||||
if not set_cpu_freq(mode_config['min_freq'], mode_config['max_freq'], cpu_id):
|
||||
success = False
|
||||
|
||||
# Then set governor
|
||||
if not set_cpu_governor(mode_config['governor'], cpu_id):
|
||||
success = False
|
||||
|
||||
if success:
|
||||
log_message(f"Successfully applied {mode} mode to all {cpu_count} cores")
|
||||
|
||||
# Update database
|
||||
if update_config_db(mode):
|
||||
log_message(f"Updated database: cpu_power_mode = {mode}")
|
||||
else:
|
||||
log_message("Warning: Failed to update database")
|
||||
|
||||
# Log current state
|
||||
state = get_current_cpu_state()
|
||||
if state:
|
||||
log_message(f"Current CPU state: {state['governor']} governor, "
|
||||
f"{state['min_freq_mhz']:.0f}-{state['max_freq_mhz']:.0f} MHz "
|
||||
f"(current: {state['current_freq_mhz']:.0f} MHz)")
|
||||
else:
|
||||
log_message(f"Failed to apply {mode} mode completely")
|
||||
|
||||
return success
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: set_cpu_mode.py <mode>")
|
||||
print("Modes: normal, powersave")
|
||||
print("Or: set_cpu_mode.py get (to get current state)")
|
||||
return 1
|
||||
|
||||
command = sys.argv[1].lower()
|
||||
|
||||
# Handle "get" command to return current state
|
||||
if command == "get":
|
||||
state = get_current_cpu_state()
|
||||
db_mode = get_config_from_db()
|
||||
|
||||
if state:
|
||||
output = {
|
||||
"success": True,
|
||||
"cpu_state": state,
|
||||
"config_mode": db_mode
|
||||
}
|
||||
print(json.dumps(output))
|
||||
return 0
|
||||
else:
|
||||
output = {
|
||||
"success": False,
|
||||
"error": "Failed to read CPU state"
|
||||
}
|
||||
print(json.dumps(output))
|
||||
return 1
|
||||
|
||||
# Handle mode setting
|
||||
log_message("=== CPU Power Mode Script Started ===")
|
||||
|
||||
if apply_mode(command):
|
||||
log_message("=== CPU Power Mode Script Completed Successfully ===")
|
||||
output = {
|
||||
"success": True,
|
||||
"mode": command,
|
||||
"description": MODES[command]['description']
|
||||
}
|
||||
print(json.dumps(output))
|
||||
return 0
|
||||
else:
|
||||
log_message("=== CPU Power Mode Script Failed ===")
|
||||
output = {
|
||||
"success": False,
|
||||
"error": f"Failed to apply mode: {command}"
|
||||
}
|
||||
print(json.dumps(output))
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
15
services/nebuleair-cpu-power.service
Normal file
15
services/nebuleair-cpu-power.service
Normal file
@@ -0,0 +1,15 @@
|
||||
[Unit]
|
||||
Description=NebuleAir CPU Power Mode Service
|
||||
After=multi-user.target
|
||||
Wants=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/python3 /var/www/nebuleair_pro_4g/power/apply_cpu_mode_from_db.py
|
||||
User=root
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -270,6 +270,25 @@ Persistent=false
|
||||
WantedBy=timers.target
|
||||
EOL
|
||||
|
||||
# Create service file for CPU Power Mode (runs once at boot)
|
||||
cat > /etc/systemd/system/nebuleair-cpu-power.service << 'EOL'
|
||||
[Unit]
|
||||
Description=NebuleAir CPU Power Mode Service
|
||||
After=multi-user.target
|
||||
Wants=multi-user.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/python3 /var/www/nebuleair_pro_4g/power/apply_cpu_mode_from_db.py
|
||||
User=root
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOL
|
||||
|
||||
# Reload systemd to recognize new services
|
||||
systemctl daemon-reload
|
||||
|
||||
@@ -286,6 +305,11 @@ systemctl enable nebuleair-wifi-powersave.timer
|
||||
systemctl start nebuleair-wifi-powersave.timer
|
||||
echo "Started nebuleair-wifi-powersave timer"
|
||||
|
||||
# Enable and start CPU power mode service (runs once at boot)
|
||||
systemctl enable nebuleair-cpu-power.service
|
||||
systemctl start nebuleair-cpu-power.service
|
||||
echo "Started nebuleair-cpu-power service"
|
||||
|
||||
echo "Checking status of all timers..."
|
||||
systemctl list-timers | grep nebuleair
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ config_entries = [
|
||||
("NOISE", "0", "bool"),
|
||||
("modem_version", "XXX", "str"),
|
||||
("language", "fr", "str"),
|
||||
("wifi_power_saving", "0", "bool")
|
||||
("wifi_power_saving", "0", "bool"),
|
||||
("cpu_power_mode", "normal", "str")
|
||||
]
|
||||
|
||||
for key, value, value_type in config_entries:
|
||||
|
||||
Reference in New Issue
Block a user