250 lines
11 KiB
JavaScript
250 lines
11 KiB
JavaScript
const scriptLocation = "/usr/local/echopilot/";
|
|
const confLocation = "/etc/wifibroadcast.cfg";
|
|
const encryptionFileLocation = "/etc/drone.key"; // Destination for encryption key
|
|
|
|
// Elements
|
|
const version = document.getElementById("version");
|
|
const file_location = document.getElementById("file_location");
|
|
const wifiChannel = document.getElementById("wifiChannel");
|
|
const wifiRegion = document.getElementById("wifiRegion");
|
|
const wifiTxPower = document.getElementById("wifiTxPower");
|
|
const tempInterval = document.getElementById("tempInterval");
|
|
const tempWarning = document.getElementById("tempWarning");
|
|
const droneMavlinkFwmark = document.getElementById("droneMavlinkFwmark");
|
|
const droneMavlinkType = document.getElementById("droneMavlinkType");
|
|
const droneMavlinkIP = document.getElementById("droneMavlinkIP");
|
|
const droneMavlinkPort = document.getElementById("droneMavlinkPort");
|
|
const droneVideoFwmark = document.getElementById("droneVideoFwmark");
|
|
const droneVideoType = document.getElementById("droneVideoType");
|
|
const droneVideoIP = document.getElementById("droneVideoIP");
|
|
const droneVideoPort = document.getElementById("droneVideoPort");
|
|
const injectRssi = document.getElementById("injectRssi");
|
|
const mavlinkSysId = document.getElementById("mavlinkSysId");
|
|
const mavlinkCompId = document.getElementById("mavlinkCompId");
|
|
const mavlinkTcpPort = document.getElementById("mavlinkTcpPort");
|
|
|
|
// Load initial settings
|
|
document.onload = InitPage();
|
|
// Save file button
|
|
document.getElementById("save").addEventListener("click", SaveSettings);
|
|
// Apply encryption file button
|
|
document.getElementById("applyEncryptionFile").addEventListener("click", ApplyEncryptionFile);
|
|
|
|
// Function to initialize the page
|
|
function InitPage() {
|
|
cockpit.script(scriptLocation + "cockpitScript.sh -v")
|
|
file_location.innerHTML = confLocation;
|
|
|
|
cockpit.file(confLocation)
|
|
.read()
|
|
.then((content) => {
|
|
console.log("Configuration file content:", content);
|
|
SuccessReadFile(content);
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to read configuration file:", error);
|
|
FailureReadFile(error);
|
|
});
|
|
}
|
|
|
|
// Load configuration values from the configuration file
|
|
function SuccessReadFile(content) {
|
|
try {
|
|
// WiFi Configuration
|
|
wifiChannel.value = getValueByKey(content, "common", "wifi_channel");
|
|
console.log("wifi_channel:", wifiChannel.value);
|
|
|
|
// Remove surrounding quotes from wifi_region value if present
|
|
wifiRegion.value = getValueByKey(content, "common", "wifi_region").replace(/^['"]|['"]$/g, "");
|
|
console.log("wifi_region:", wifiRegion.value);
|
|
|
|
// Handle "None" value for wifi_txpower
|
|
const txPowerValue = getValueByKey(content, "common", "wifi_txpower");
|
|
wifiTxPower.value = txPowerValue === "None" ? "" : txPowerValue;
|
|
console.log("wifi_txpower:", wifiTxPower.value);
|
|
|
|
tempInterval.value = getValueByKey(content, "common", "temp_measurement_interval");
|
|
console.log("temp_measurement_interval:", tempInterval.value);
|
|
|
|
tempWarning.value = getValueByKey(content, "common", "temp_overheat_warning");
|
|
console.log("temp_overheat_warning:", tempWarning.value);
|
|
|
|
// Drone MAVLink Configuration
|
|
droneMavlinkFwmark.value = getValueByKey(content, "drone_mavlink", "fwmark");
|
|
console.log("drone_mavlink_fwmark:", droneMavlinkFwmark.value);
|
|
|
|
const droneMavlinkPeer = getValueByKey(content, "drone_mavlink", "peer");
|
|
console.log("drone_mavlink_peer:", droneMavlinkPeer);
|
|
if (droneMavlinkPeer) {
|
|
parsePeer(droneMavlinkPeer, droneMavlinkType, droneMavlinkIP, droneMavlinkPort);
|
|
}
|
|
|
|
// Drone Video Configuration
|
|
droneVideoFwmark.value = getValueByKey(content, "drone_video", "fwmark");
|
|
console.log("drone_video_fwmark:", droneVideoFwmark.value);
|
|
|
|
const droneVideoPeer = getValueByKey(content, "drone_video", "peer");
|
|
console.log("drone_video_peer:", droneVideoPeer);
|
|
if (droneVideoPeer) {
|
|
parsePeer(droneVideoPeer, droneVideoType, droneVideoIP, droneVideoPort);
|
|
}
|
|
|
|
// MAVLink Configuration
|
|
injectRssi.checked = getValueByKey(content, "mavlink", "inject_rssi") === "True";
|
|
console.log("inject_rssi:", injectRssi.checked);
|
|
|
|
mavlinkSysId.value = getValueByKey(content, "mavlink", "mavlink_sys_id");
|
|
console.log("mavlink_sys_id:", mavlinkSysId.value);
|
|
|
|
mavlinkCompId.value = getValueByKey(content, "mavlink", "mavlink_comp_id");
|
|
console.log("mavlink_comp_id:", mavlinkCompId.value);
|
|
|
|
const tcpPortValue = getValueByKey(content, "mavlink", "mavlink_tcp_port");
|
|
mavlinkTcpPort.value = tcpPortValue === "None" ? "" : tcpPortValue;
|
|
console.log("mavlink_tcp_port:", mavlinkTcpPort.value);
|
|
} catch (e) {
|
|
console.error("Error parsing configuration file:", e);
|
|
FailureReadFile(e);
|
|
}
|
|
}
|
|
|
|
// Save configuration values to the configuration file
|
|
function SaveSettings() {
|
|
try {
|
|
cockpit.file(confLocation)
|
|
.read()
|
|
.then((content) => {
|
|
// WiFi Configuration
|
|
content = setValueByKey(content, "[common]", "wifi_channel", wifiChannel.value);
|
|
content = setValueByKey(content, "[common]", "wifi_region", wifiRegion.value);
|
|
content = setValueByKey(content, "[common]", "wifi_txpower", wifiTxPower.value === "" ? "None" : wifiTxPower.value);
|
|
content = setValueByKey(content, "[common]", "temp_measurement_interval", tempInterval.value);
|
|
content = setValueByKey(content, "[common]", "temp_overheat_warning", tempWarning.value);
|
|
|
|
// Drone MAVLink Configuration
|
|
const droneMavlinkPeer = `${droneMavlinkType.value}://${droneMavlinkIP.value}:${droneMavlinkPort.value}`;
|
|
content = setValueByKey(content, "[drone_mavlink]", "fwmark", droneMavlinkFwmark.value);
|
|
content = setValueByKey(content, "[drone_mavlink]", "peer", droneMavlinkPeer);
|
|
|
|
// Drone Video Configuration
|
|
const droneVideoPeer = `${droneVideoType.value}://${droneVideoIP.value}:${droneVideoPort.value}`;
|
|
content = setValueByKey(content, "[drone_video]", "fwmark", droneVideoFwmark.value);
|
|
content = setValueByKey(content, "[drone_video]", "peer", droneVideoPeer);
|
|
|
|
// MAVLink Configuration
|
|
content = setValueByKey(content, "[mavlink]", "inject_rssi", injectRssi.checked ? "True" : "False");
|
|
content = setValueByKey(content, "[mavlink]", "mavlink_sys_id", mavlinkSysId.value);
|
|
content = setValueByKey(content, "[mavlink]", "mavlink_comp_id", mavlinkCompId.value);
|
|
content = setValueByKey(content, "[mavlink]", "mavlink_tcp_port", mavlinkTcpPort.value === "" ? "None" : mavlinkTcpPort.value);
|
|
|
|
cockpit.file(confLocation, { superuser: "try" }).replace(content)
|
|
.then(() => {
|
|
console.log("Configuration saved successfully.");
|
|
RestartWifibroadcastService();
|
|
Success();
|
|
})
|
|
.catch((error) => {
|
|
console.error("Failed to save configuration:", error);
|
|
Fail(error);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to read configuration file:", error);
|
|
FailureReadFile(error);
|
|
});
|
|
} catch (e) {
|
|
console.error("Error during save operation:", e);
|
|
FailureReadFile(e);
|
|
}
|
|
}
|
|
|
|
// Apply encryption file from base station
|
|
function ApplyEncryptionFile() {
|
|
const command = `
|
|
/usr/bin/sshpass -p 'spirifriend' scp -o StrictHostKeyChecking=no spiri@spiri-base.local:/home/spiri/drone.key /tmp/drone.key &&
|
|
/usr/bin/sudo /bin/mv /tmp/drone.key ${encryptionFileLocation} &&
|
|
/usr/bin/sudo /bin/systemctl restart wifibroadcast@drone
|
|
`;
|
|
|
|
cockpit.spawn(["bash", "-c", command], { superuser: "require" })
|
|
.then(() => {
|
|
console.log("Encryption key applied and wifibroadcast service restarted.");
|
|
Success();
|
|
})
|
|
.catch((error) => {
|
|
console.error("Failed to apply encryption key or restart service:", error);
|
|
Fail(error);
|
|
});
|
|
}
|
|
|
|
|
|
// Restart wifibroadcast service
|
|
function RestartWifibroadcastService() {
|
|
cockpit.spawn(["systemctl", "restart", "wifibroadcast@drone"], { superuser: "require" })
|
|
.then(() => {
|
|
console.log("wifibroadcast@drone service restarted.");
|
|
})
|
|
.catch((error) => {
|
|
console.error("Failed to restart wifibroadcast@drone service:", error);
|
|
});
|
|
}
|
|
|
|
// Success handler
|
|
function Success() {
|
|
result.style.color = "green";
|
|
result.innerHTML = "Success, settings saved.";
|
|
setTimeout(() => result.innerHTML = "", 5000);
|
|
}
|
|
|
|
// Failure handler
|
|
function Fail(error) {
|
|
result.style.color = "red";
|
|
result.innerHTML = error.message;
|
|
}
|
|
|
|
// Parse Peer configuration (type, IP, port)
|
|
function parsePeer(peer, typeElement, ipElement, portElement) {
|
|
if (!peer) {
|
|
console.warn("Peer value is empty or undefined.");
|
|
return; // Skip if peer is empty
|
|
}
|
|
|
|
const regex = /(listen|connect):\/\/([\d.]+):(\d+)/;
|
|
const match = peer.match(regex);
|
|
if (match) {
|
|
typeElement.value = match[1];
|
|
ipElement.value = match[2];
|
|
portElement.value = match[3];
|
|
} else {
|
|
console.error("Failed to parse peer:", peer);
|
|
}
|
|
}
|
|
|
|
// Get value by key from configuration content
|
|
function getValueByKey(content, section, key) {
|
|
const sectionRegex = new RegExp(`\\[${section}\\][\\s\\S]*?^${key}\\s*=\\s*(.*)`, "m");
|
|
const match = content.match(sectionRegex);
|
|
if (match) {
|
|
let value = match[1].trim();
|
|
console.log(`Found key [${key}] in section [${section}]:`, value);
|
|
return value;
|
|
} else {
|
|
console.warn(`Key [${key}] not found in section [${section}]`);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// Set value by key in configuration content
|
|
function setValueByKey(content, section, key, value) {
|
|
const regex = new RegExp(`(${section}[\\s\\S]*?)(${key}\\s*=\\s*)(.*)`, "m");
|
|
if (content.match(regex)) {
|
|
return content.replace(regex, `$1$2${value}`);
|
|
} else {
|
|
// Add key if not found
|
|
const sectionRegex = new RegExp(`(${section}[\\s\\S]*?)\\n`, "m");
|
|
return content.match(sectionRegex)
|
|
? content.replace(sectionRegex, `$1\n${key} = ${value}\n`)
|
|
: `${content}\n${section}\n${key} = ${value}\n`;
|
|
}
|
|
}
|