feat: add firmware versioning and device_type support (NebuleAir/ModuleAir)
- Add VERSION file (1.0.0) and changelog.json for firmware tracking - Add device_type config param (nebuleair_pro default, backward compatible via INSERT OR IGNORE) - Add device_type select in admin.html Protected Settings - Add version badge and changelog modal in Updates section - Add get_firmware_version and get_changelog PHP endpoints - Display firmware version in update_firmware.sh after git pull Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
21
changelog.json
Normal file
21
changelog.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"date": "2026-02-11",
|
||||
"changes": {
|
||||
"features": [
|
||||
"Support multi-device : NebuleAir Pro / ModuleAir Pro",
|
||||
"Systeme de versioning firmware",
|
||||
"Changelog viewer dans l'interface web"
|
||||
],
|
||||
"improvements": [],
|
||||
"fixes": [],
|
||||
"compatibility": [
|
||||
"Les capteurs existants sont automatiquement configures en 'nebuleair_pro'"
|
||||
]
|
||||
},
|
||||
"notes": "Premiere version tracee. Les capteurs anterieurs recevront device_type=nebuleair_pro par defaut lors de la mise a jour."
|
||||
}
|
||||
]
|
||||
}
|
||||
163
html/admin.html
163
html/admin.html
@@ -174,6 +174,13 @@
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="device_type" class="form-label">Device Type</label>
|
||||
<select class="form-select protected-checkbox" id="device_type" onchange="update_config_sqlite('device_type', this.value)" disabled>
|
||||
<option value="nebuleair_pro">NebuleAir Pro</option>
|
||||
<option value="moduleair_pro">ModuleAir Pro</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3" id="sondes_envea_div"></div>
|
||||
|
||||
@@ -219,7 +226,11 @@
|
||||
<!-- UPDATE-->
|
||||
|
||||
<div class="col-lg-4 col-12">
|
||||
<h3 class="mt-4">Updates</h3>
|
||||
<div class="d-flex align-items-center mt-4 mb-2">
|
||||
<h3 class="mb-0 me-2">Updates</h3>
|
||||
<span id="firmwareVersionBadge" class="badge bg-secondary">Version...</span>
|
||||
<button type="button" class="btn btn-sm btn-outline-info ms-2" onclick="showChangelogModal()">Changelog</button>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" onclick="updateFirmware()" id="updateBtn">
|
||||
<span id="updateBtnText">Update firmware</span>
|
||||
@@ -334,6 +345,28 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Changelog Modal -->
|
||||
<div class="modal fade" id="changelogModal" tabindex="-1" aria-labelledby="changelogModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="changelogModalLabel">Changelog</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="changelogModalBody">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
@@ -437,6 +470,12 @@ window.onload = function() {
|
||||
checkbox_aircarto.checked = response["send_aircarto"];
|
||||
checkbox_miotiq.checked = response["send_miotiq"];
|
||||
|
||||
// Set device type
|
||||
const device_type_select = document.getElementById("device_type");
|
||||
if (response["device_type"]) {
|
||||
device_type_select.value = response["device_type"];
|
||||
}
|
||||
|
||||
// Set CPU power mode
|
||||
const cpu_power_mode_select = document.getElementById("cpu_power_mode");
|
||||
if (response["cpu_power_mode"]) {
|
||||
@@ -555,7 +594,10 @@ window.onload = function() {
|
||||
|
||||
// Load services on page load
|
||||
refreshServices();
|
||||
|
||||
|
||||
// Load firmware version
|
||||
loadFirmwareVersion();
|
||||
|
||||
} //end window.onload
|
||||
|
||||
|
||||
@@ -1644,6 +1686,123 @@ function toggleProtectedSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
__ __ _ _
|
||||
\ \ / /__ _ __ ___(_) ___ _ __ (_)_ __ __ _
|
||||
\ \ / / _ \ '__/ __| |/ _ \| '_ \| | '_ \ / _` |
|
||||
\ V / __/ | \__ \ | (_) | | | | | | | | (_| |
|
||||
\_/ \___|_| |___/_|\___/|_| |_|_|_| |_|\__, |
|
||||
|___/
|
||||
*/
|
||||
|
||||
function loadFirmwareVersion() {
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=get_firmware_version',
|
||||
dataType: 'json',
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
success: function(response) {
|
||||
const badge = document.getElementById('firmwareVersionBadge');
|
||||
if (response.success) {
|
||||
badge.textContent = 'v' + response.version;
|
||||
badge.className = 'badge bg-primary';
|
||||
} else {
|
||||
badge.textContent = 'Version unknown';
|
||||
badge.className = 'badge bg-secondary';
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
const badge = document.getElementById('firmwareVersionBadge');
|
||||
badge.textContent = 'Version unknown';
|
||||
badge.className = 'badge bg-secondary';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showChangelogModal() {
|
||||
const modal = new bootstrap.Modal(document.getElementById('changelogModal'));
|
||||
modal.show();
|
||||
|
||||
// Load changelog data
|
||||
$.ajax({
|
||||
url: 'launcher.php?type=get_changelog',
|
||||
dataType: 'json',
|
||||
method: 'GET',
|
||||
cache: false,
|
||||
success: function(response) {
|
||||
if (response.success && response.changelog) {
|
||||
displayChangelog(response.changelog);
|
||||
} else {
|
||||
document.getElementById('changelogModalBody').innerHTML =
|
||||
'<div class="alert alert-warning">Could not load changelog.</div>';
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
document.getElementById('changelogModalBody').innerHTML =
|
||||
'<div class="alert alert-danger">Failed to load changelog.</div>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function displayChangelog(data) {
|
||||
const container = document.getElementById('changelogModalBody');
|
||||
let html = '';
|
||||
|
||||
data.versions.forEach(function(version) {
|
||||
html += `<div class="card mb-3">`;
|
||||
html += `<div class="card-header d-flex justify-content-between align-items-center">`;
|
||||
html += `<h5 class="mb-0">v${version.version}</h5>`;
|
||||
html += `<span class="text-muted">${version.date}</span>`;
|
||||
html += `</div>`;
|
||||
html += `<div class="card-body">`;
|
||||
|
||||
// Features
|
||||
if (version.changes.features && version.changes.features.length > 0) {
|
||||
html += `<h6 class="text-success">Features</h6><ul>`;
|
||||
version.changes.features.forEach(function(f) {
|
||||
html += `<li>${f}</li>`;
|
||||
});
|
||||
html += `</ul>`;
|
||||
}
|
||||
|
||||
// Improvements
|
||||
if (version.changes.improvements && version.changes.improvements.length > 0) {
|
||||
html += `<h6 class="text-info">Improvements</h6><ul>`;
|
||||
version.changes.improvements.forEach(function(i) {
|
||||
html += `<li>${i}</li>`;
|
||||
});
|
||||
html += `</ul>`;
|
||||
}
|
||||
|
||||
// Fixes
|
||||
if (version.changes.fixes && version.changes.fixes.length > 0) {
|
||||
html += `<h6 class="text-danger">Fixes</h6><ul>`;
|
||||
version.changes.fixes.forEach(function(f) {
|
||||
html += `<li>${f}</li>`;
|
||||
});
|
||||
html += `</ul>`;
|
||||
}
|
||||
|
||||
// Compatibility
|
||||
if (version.changes.compatibility && version.changes.compatibility.length > 0) {
|
||||
html += `<div class="alert alert-warning mt-2 mb-0"><strong>Compatibility:</strong><ul class="mb-0">`;
|
||||
version.changes.compatibility.forEach(function(c) {
|
||||
html += `<li>${c}</li>`;
|
||||
});
|
||||
html += `</ul></div>`;
|
||||
}
|
||||
|
||||
// Notes
|
||||
if (version.notes) {
|
||||
html += `<p class="text-muted mt-2 mb-0"><em>${version.notes}</em></p>`;
|
||||
}
|
||||
|
||||
html += `</div></div>`;
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1515,6 +1515,47 @@ if ($type == "detect_envea_device") {
|
||||
|___/
|
||||
*/
|
||||
|
||||
// Get firmware version from VERSION file
|
||||
if ($type == "get_firmware_version") {
|
||||
$versionFile = '/var/www/nebuleair_pro_4g/VERSION';
|
||||
if (file_exists($versionFile)) {
|
||||
$version = trim(file_get_contents($versionFile));
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'version' => $version
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'version' => 'unknown'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get changelog from changelog.json
|
||||
if ($type == "get_changelog") {
|
||||
$changelogFile = '/var/www/nebuleair_pro_4g/changelog.json';
|
||||
if (file_exists($changelogFile)) {
|
||||
$changelog = json_decode(file_get_contents($changelogFile), true);
|
||||
if ($changelog !== null) {
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'changelog' => $changelog
|
||||
]);
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Invalid changelog format'
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'error' => 'Changelog file not found'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Get current CPU power mode
|
||||
if ($type == "get_cpu_power_mode") {
|
||||
try {
|
||||
|
||||
@@ -51,6 +51,7 @@ config_entries = [
|
||||
("MPPT", "0", "bool"),
|
||||
("NOISE", "0", "bool"),
|
||||
("modem_version", "XXX", "str"),
|
||||
("device_type", "nebuleair_pro", "str"),
|
||||
("language", "fr", "str"),
|
||||
("wifi_power_saving", "0", "bool"),
|
||||
("cpu_power_mode", "normal", "str")
|
||||
|
||||
@@ -57,6 +57,11 @@ fi
|
||||
git pull origin $(git branch --show-current)
|
||||
check_status "Git pull"
|
||||
|
||||
# Display firmware version
|
||||
if [ -f "/var/www/nebuleair_pro_4g/VERSION" ]; then
|
||||
print_status "Firmware version: $(cat /var/www/nebuleair_pro_4g/VERSION)"
|
||||
fi
|
||||
|
||||
# Step 2: Update database configuration
|
||||
print_status ""
|
||||
print_status "Step 2: Updating database configuration..."
|
||||
|
||||
Reference in New Issue
Block a user