feat: add mqtt error diagnostic #91
This commit is contained in:
+25
-25
@@ -59,47 +59,47 @@ const init = async () => {
|
||||
|
||||
// Show supported features
|
||||
process.stdout.write("\n");
|
||||
console.log(`Supported: ${JSON.stringify(HARDWARE.support, null, 2)}`);
|
||||
console.info(`Supported: ${JSON.stringify(HARDWARE.support, null, 2)}`);
|
||||
|
||||
// Show session infos
|
||||
process.stdout.write("\n");
|
||||
console.log("User:", HARDWARE.session.user);
|
||||
console.log("Session:", HARDWARE.session.type);
|
||||
console.log("Desktop:", HARDWARE.session.desktop);
|
||||
console.info("User:", HARDWARE.session.user);
|
||||
console.info("Session:", HARDWARE.session.type);
|
||||
console.info("Desktop:", HARDWARE.session.desktop);
|
||||
|
||||
// Show device infos
|
||||
process.stdout.write("\n");
|
||||
console.log("Model:", getModel());
|
||||
console.log("Vendor:", getVendor());
|
||||
console.log("Serial Number:", getSerialNumber());
|
||||
console.log("Network Addresses:", getNetworkAddresses());
|
||||
console.log("Host Name:", getHostName());
|
||||
console.info("Model:", getModel());
|
||||
console.info("Vendor:", getVendor());
|
||||
console.info("Serial Number:", getSerialNumber());
|
||||
console.info("Network Addresses:", getNetworkAddresses());
|
||||
console.info("Host Name:", getHostName());
|
||||
|
||||
// Show system infos
|
||||
process.stdout.write("\n");
|
||||
console.log("Up Time:", getUpTime());
|
||||
console.log("Memory Size:", getMemorySize());
|
||||
console.log("Memory Usage:", getMemoryUsage());
|
||||
console.log("Processor Usage:", getProcessorUsage());
|
||||
console.log("Processor Temperature:", getProcessorTemperature());
|
||||
console.info("Up Time:", getUpTime());
|
||||
console.info("Memory Size:", getMemorySize());
|
||||
console.info("Memory Usage:", getMemoryUsage());
|
||||
console.info("Processor Usage:", getProcessorUsage());
|
||||
console.info("Processor Temperature:", getProcessorTemperature());
|
||||
|
||||
// Show hardware infos
|
||||
process.stdout.write("\n");
|
||||
const unsupported = "unsupported";
|
||||
console.log(`Battery Level [${HARDWARE.battery.level.path || unsupported}]:`, `${getBatteryLevel() || unsupported}`);
|
||||
console.log(
|
||||
console.info(`Battery Level [${HARDWARE.battery.level.path || unsupported}]:`, `${getBatteryLevel() || unsupported}`);
|
||||
console.info(
|
||||
`Display Status [${HARDWARE.display.status.path || unsupported}]:`,
|
||||
`${getDisplayStatus() || unsupported} (${HARDWARE.display.status.command || unsupported})`,
|
||||
);
|
||||
console.log(
|
||||
console.info(
|
||||
`Display Brightness [${HARDWARE.display.brightness.path || unsupported}]:`,
|
||||
`${getDisplayBrightness() || unsupported}`,
|
||||
);
|
||||
console.log(
|
||||
console.info(
|
||||
`Audio Volume [${HARDWARE.support.audioVolume ? HARDWARE.audio.device : unsupported}]:`,
|
||||
`${getAudioVolume() || unsupported}`,
|
||||
);
|
||||
console.log(
|
||||
console.info(
|
||||
`Keyboard Visibility [${HARDWARE.support.keyboardVisibility ? "squeekboard" : unsupported}]:`,
|
||||
`${getKeyboardVisibility() || unsupported}`,
|
||||
);
|
||||
@@ -112,7 +112,7 @@ const init = async () => {
|
||||
return;
|
||||
}
|
||||
if (reply.includes("'change' on sink")) {
|
||||
console.log("Update Audio Volume:", getAudioVolume());
|
||||
console.info("Update Audio Volume:", getAudioVolume());
|
||||
EVENTS.emit("updateVolume");
|
||||
}
|
||||
});
|
||||
@@ -129,7 +129,7 @@ const init = async () => {
|
||||
return;
|
||||
}
|
||||
HARDWARE.keyboard.visibility = property.Visible === "true";
|
||||
console.log("Update Keyboard Visibility:", getKeyboardVisibility());
|
||||
console.info("Update Keyboard Visibility:", getKeyboardVisibility());
|
||||
EVENTS.emit("updateKeyboard");
|
||||
});
|
||||
});
|
||||
@@ -155,7 +155,7 @@ const update = async () => {
|
||||
if (HARDWARE.support.displayStatus) {
|
||||
const status = (await fsp.readFile(`${HARDWARE.display.status.path}/dpms`, "utf8")).trim();
|
||||
if (status !== HARDWARE.display.status.value) {
|
||||
console.log("Update Display Status:", getDisplayStatus());
|
||||
console.info("Update Display Status:", getDisplayStatus());
|
||||
HARDWARE.display.status.value = status;
|
||||
EVENTS.emit("updateDisplay");
|
||||
}
|
||||
@@ -165,7 +165,7 @@ const update = async () => {
|
||||
if (HARDWARE.support.displayBrightness) {
|
||||
const brightness = (await fsp.readFile(`${HARDWARE.display.brightness.path}/brightness`, "utf8")).trim();
|
||||
if (brightness !== HARDWARE.display.brightness.value) {
|
||||
console.log("Update Display Brightness:", getDisplayBrightness());
|
||||
console.info("Update Display Brightness:", getDisplayBrightness());
|
||||
HARDWARE.display.brightness.value = brightness;
|
||||
EVENTS.emit("updateDisplay");
|
||||
}
|
||||
@@ -891,7 +891,7 @@ const execScriptCommand = (cmd, args, callback = null) => {
|
||||
const output = data.toString().trim();
|
||||
const lines = output.replace(/\n+/g, "\n").replace(/^\n+|\n+$|\0/g, "");
|
||||
for (const line of lines.split("\n").filter(Boolean)) {
|
||||
console.log(line);
|
||||
console.info(line);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -917,7 +917,7 @@ const execScriptCommand = (cmd, args, callback = null) => {
|
||||
console.error(`Script exited with error code (${code}).`);
|
||||
if (typeof callback === "function") callback(null, code);
|
||||
} else {
|
||||
console.log("Script exited successfully.");
|
||||
console.info("Script exited successfully.");
|
||||
if (typeof callback === "function") callback(100, null);
|
||||
}
|
||||
});
|
||||
|
||||
+96
-53
@@ -55,14 +55,14 @@ const init = async () => {
|
||||
options.rejectUnauthorized = !("ignore_certificate_errors" in ARGS);
|
||||
|
||||
// Client connect
|
||||
console.log("MQTT Connecting:", `${user}:${masked}@${url.toString()}`);
|
||||
console.info("MQTT Connecting:", `${user}:${masked}@${url.toString()}`);
|
||||
INTEGRATION.client = mqtt.connect(url.toString(), options);
|
||||
INTEGRATION.client.setMaxListeners(20);
|
||||
|
||||
// Client connected
|
||||
INTEGRATION.client
|
||||
.once("connect", () => {
|
||||
console.log(`MQTT Connected: ${url.toString()}`);
|
||||
console.info(`MQTT Connected: ${url.toString()}`);
|
||||
process.stdout.write("\n");
|
||||
|
||||
// Init client controls
|
||||
@@ -91,30 +91,35 @@ const init = async () => {
|
||||
initProcessorTemperature();
|
||||
initBatteryLevel();
|
||||
initPackageUpgrades();
|
||||
initHeartbeat();
|
||||
initLastActive();
|
||||
|
||||
// Init client diagnostic
|
||||
initHeartbeat();
|
||||
initErrors();
|
||||
|
||||
// Integration initialized
|
||||
INTEGRATION.initialized = true;
|
||||
|
||||
// Register global events
|
||||
EVENTS.on("updateStatus", updateKiosk);
|
||||
EVENTS.on("updateTheme", updateTheme);
|
||||
EVENTS.on("updateDisplay", updateDisplay);
|
||||
EVENTS.on("updateVolume", updateVolume);
|
||||
EVENTS.on("updateKeyboard", updateKeyboard);
|
||||
EVENTS.on("consoleLog", updateErrors);
|
||||
})
|
||||
.on("error", (error) => {
|
||||
console.error("MQTT", error.message);
|
||||
});
|
||||
|
||||
// Update sensor states from events
|
||||
EVENTS.on("updateStatus", updateKiosk);
|
||||
EVENTS.on("updateTheme", updateTheme);
|
||||
EVENTS.on("updateDisplay", updateDisplay);
|
||||
EVENTS.on("updateVolume", updateVolume);
|
||||
EVENTS.on("updateKeyboard", updateKeyboard);
|
||||
|
||||
// Update time sensors periodically (30s)
|
||||
setInterval(() => {
|
||||
if (APP.exiting) {
|
||||
return;
|
||||
}
|
||||
updateHeartbeat();
|
||||
updateLastActive();
|
||||
updateHeartbeat();
|
||||
updateErrors();
|
||||
}, 30 * 1000);
|
||||
|
||||
// Update system sensors periodically (1min)
|
||||
@@ -240,12 +245,12 @@ const initApp = () => {
|
||||
publishConfig("update", config)
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
console.log("Update App...");
|
||||
console.info("Update App...");
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
const args = ["-c", `bash <(wget -qO- ${APP.scripts.install}) update`];
|
||||
hardware.execScriptCommand("bash", args, (progress, error) => {
|
||||
if (progress) {
|
||||
console.log(`Progress: ${progress}%`);
|
||||
console.info(`Progress: ${progress}%`);
|
||||
}
|
||||
updateApp(progress);
|
||||
});
|
||||
@@ -296,7 +301,7 @@ const initShutdown = () => {
|
||||
publishConfig("button", config)
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
console.log("Shutdown system...");
|
||||
console.verbose("Shutdown system...");
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
hardware.shutdownSystem();
|
||||
});
|
||||
@@ -324,7 +329,7 @@ const initReboot = () => {
|
||||
publishConfig("button", config)
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
console.log("Rebooting system...");
|
||||
console.verbose("Rebooting system...");
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
hardware.rebootSystem();
|
||||
});
|
||||
@@ -348,7 +353,7 @@ const initRefresh = () => {
|
||||
publishConfig("button", config)
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
console.log("Refreshing webview...");
|
||||
console.verbose("Refreshing webview...");
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
EVENTS.emit("reloadView");
|
||||
});
|
||||
@@ -376,7 +381,7 @@ const initKiosk = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const status = message.toString();
|
||||
console.log("Set Kiosk Status:", status);
|
||||
console.verbose("Set Kiosk Status:", status);
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
WEBVIEW.window.setStatus(status);
|
||||
});
|
||||
@@ -390,7 +395,7 @@ const initKiosk = () => {
|
||||
* Updates the kiosk status via the mqtt connection.
|
||||
*/
|
||||
const updateKiosk = async () => {
|
||||
const kiosk = WEBVIEW.tracker.status;
|
||||
const kiosk = WEBVIEW.tracker.window.status;
|
||||
publishState("kiosk", kiosk);
|
||||
};
|
||||
|
||||
@@ -413,7 +418,7 @@ const initTheme = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const theme = message.toString();
|
||||
console.log("Set Application Theme:", theme);
|
||||
console.verbose("Set Application Theme:", theme);
|
||||
WEBVIEW.theme.set(theme);
|
||||
}
|
||||
})
|
||||
@@ -456,7 +461,7 @@ const initDisplay = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const status = message.toString();
|
||||
console.log("Set Display Status:", status);
|
||||
console.verbose("Set Display Status:", status);
|
||||
hardware.setDisplayStatus(status, (reply, error) => {
|
||||
if (!error) {
|
||||
hardware.update();
|
||||
@@ -466,7 +471,7 @@ const initDisplay = () => {
|
||||
});
|
||||
} else if (topic === config.brightness_command_topic) {
|
||||
const brightness = parseInt(message, 10);
|
||||
console.log("Set Display Brightness:", brightness);
|
||||
console.verbose("Set Display Brightness:", brightness);
|
||||
hardware.setDisplayBrightness(brightness, (reply, error) => {
|
||||
if (!error) {
|
||||
hardware.update();
|
||||
@@ -517,7 +522,7 @@ const initVolume = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const volume = parseInt(message, 10);
|
||||
console.log("Set Audio Volume:", volume);
|
||||
console.verbose("Set Audio Volume:", volume);
|
||||
hardware.setAudioVolume(volume);
|
||||
}
|
||||
})
|
||||
@@ -554,7 +559,7 @@ const initKeyboard = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const status = message.toString();
|
||||
console.log("Set Keyboard Visibility:", status);
|
||||
console.verbose("Set Keyboard Visibility:", status);
|
||||
hardware.setDisplayStatus("ON", () => {
|
||||
hardware.setKeyboardVisibility(status);
|
||||
});
|
||||
@@ -598,7 +603,7 @@ const initPageNumber = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const number = parseInt(message, 10);
|
||||
console.log("Set Page Number:", number);
|
||||
console.verbose("Set Page Number:", number);
|
||||
WEBVIEW.viewActive = number || 1;
|
||||
EVENTS.emit("updateView");
|
||||
}
|
||||
@@ -638,7 +643,7 @@ const initPageZoom = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const zoom = parseInt(message, 10);
|
||||
console.log("Set Page Zoom:", zoom);
|
||||
console.verbose("Set Page Zoom:", zoom);
|
||||
WEBVIEW.views[WEBVIEW.viewActive || 1].webContents.setZoomFactor(zoom / 100.0);
|
||||
EVENTS.emit("updateView");
|
||||
}
|
||||
@@ -674,7 +679,7 @@ const initPageUrl = () => {
|
||||
.on("message", (topic, message) => {
|
||||
if (topic === config.command_topic) {
|
||||
const url = message.toString();
|
||||
console.log("Set Page Url:", url);
|
||||
console.verbose("Set Page Url:", url);
|
||||
WEBVIEW.views[WEBVIEW.viewActive || 1].webContents.loadURL(url);
|
||||
}
|
||||
})
|
||||
@@ -990,33 +995,6 @@ const updatePackageUpgrades = async () => {
|
||||
publishAttributes("package_upgrades", upgrades);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the heartbeat sensor.
|
||||
*/
|
||||
const initHeartbeat = () => {
|
||||
const root = `${INTEGRATION.root}/heartbeat`;
|
||||
const config = {
|
||||
name: "Heartbeat",
|
||||
unique_id: `${INTEGRATION.node}_heartbeat`,
|
||||
state_topic: `${root}/state`,
|
||||
value_template: "{{ value }}",
|
||||
icon: "mdi:heart-flash",
|
||||
device: INTEGRATION.device,
|
||||
};
|
||||
publishConfig("sensor", config);
|
||||
updateHeartbeat();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the heartbeat sensor via the mqtt connection.
|
||||
*/
|
||||
const updateHeartbeat = async () => {
|
||||
const now = new Date();
|
||||
const local = new Date(now.getTime() - now.getTimezoneOffset() * 60 * 1000);
|
||||
const heartbeat = local.toISOString().replace(/\.\d{3}Z$/, "");
|
||||
publishState("heartbeat", heartbeat);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the last active sensor.
|
||||
*/
|
||||
@@ -1047,6 +1025,71 @@ const updateLastActive = async () => {
|
||||
publishAttributes("last_active", WEBVIEW.tracker.pointer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the heartbeat sensor.
|
||||
*/
|
||||
const initHeartbeat = () => {
|
||||
const root = `${INTEGRATION.root}/heartbeat`;
|
||||
const config = {
|
||||
name: "Heartbeat",
|
||||
unique_id: `${INTEGRATION.node}_heartbeat`,
|
||||
state_topic: `${root}/state`,
|
||||
value_template: "{{ value }}",
|
||||
entity_category: "diagnostic",
|
||||
icon: "mdi:heart-flash",
|
||||
device: INTEGRATION.device,
|
||||
};
|
||||
publishConfig("sensor", config);
|
||||
updateHeartbeat();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the heartbeat sensor via the mqtt connection.
|
||||
*/
|
||||
const updateHeartbeat = async () => {
|
||||
const now = new Date();
|
||||
const local = new Date(now.getTime() - now.getTimezoneOffset() * 60 * 1000);
|
||||
const heartbeat = local.toISOString().replace(/\.\d{3}Z$/, "");
|
||||
publishState("heartbeat", heartbeat);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the error log sensor.
|
||||
*/
|
||||
const initErrors = () => {
|
||||
const root = `${INTEGRATION.root}/errors`;
|
||||
const config = {
|
||||
name: "Errors",
|
||||
unique_id: `${INTEGRATION.node}_errors`,
|
||||
state_topic: `${root}/state`,
|
||||
json_attributes_topic: `${root}/attributes`,
|
||||
value_template: "{{ value | int }}",
|
||||
entity_category: "diagnostic",
|
||||
icon: "mdi:alert-circle",
|
||||
device: INTEGRATION.device,
|
||||
};
|
||||
publishConfig("sensor", config);
|
||||
updateErrors();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the error log sensor via the mqtt connection.
|
||||
*/
|
||||
const updateErrors = async () => {
|
||||
const logs = APP.logs.slice().reverse();
|
||||
const errors = logs.filter((log) => log.level === "error");
|
||||
const history = logs.reduce((acc, log) => {
|
||||
const time = log.time.toISOString().slice(0, 16);
|
||||
if (!acc[time]) {
|
||||
acc[time] = [];
|
||||
}
|
||||
acc[time].push({ [log.level.toUpperCase()]: log.text });
|
||||
return acc;
|
||||
}, {});
|
||||
publishState("errors", errors.length);
|
||||
publishAttributes("errors", history);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
init,
|
||||
update,
|
||||
|
||||
+26
-5
@@ -209,9 +209,12 @@ const updateView = () => {
|
||||
const url = WEBVIEW.views[WEBVIEW.viewActive].webContents.getURL();
|
||||
const host = url.startsWith("data:") ? "whoopsie" : new URL(url).host;
|
||||
const title = `${APP.title} - ${host} (${WEBVIEW.viewActive})`;
|
||||
const previous = WEBVIEW.window.getTitle();
|
||||
|
||||
// Update window title
|
||||
console.log(`Update View: ${title}`);
|
||||
if (previous !== title) {
|
||||
console.info(`Update View: ${title}`);
|
||||
}
|
||||
WEBVIEW.status.webContents.send("text-content", { id: "title", content: title });
|
||||
WEBVIEW.window.setTitle(title);
|
||||
|
||||
@@ -226,6 +229,9 @@ const updateView = () => {
|
||||
* Updates the window status.
|
||||
*/
|
||||
const updateStatus = () => {
|
||||
const previous = WEBVIEW.tracker.status;
|
||||
|
||||
// Set window status
|
||||
if (WEBVIEW.window.isFullScreen()) {
|
||||
WEBVIEW.tracker.status = "Fullscreen";
|
||||
} else if (WEBVIEW.window.isMinimized()) {
|
||||
@@ -237,7 +243,9 @@ const updateStatus = () => {
|
||||
}
|
||||
|
||||
// Update window status
|
||||
console.log("Update Kiosk Status:", WEBVIEW.tracker.status);
|
||||
if (previous !== WEBVIEW.tracker.status) {
|
||||
console.info(`Update Kiosk Status: ${WEBVIEW.tracker.status}`);
|
||||
}
|
||||
EVENTS.emit("updateStatus");
|
||||
};
|
||||
|
||||
@@ -456,6 +464,9 @@ const homeView = () => {
|
||||
const defaultUrl = WEBVIEW.viewUrls[WEBVIEW.viewActive];
|
||||
const currentUrl = view.webContents.getURL();
|
||||
|
||||
// Reset log history
|
||||
APP.logs = [];
|
||||
|
||||
// Reload the default url or refresh the page
|
||||
if (currentUrl != defaultUrl) {
|
||||
view.webContents.loadURL(defaultUrl);
|
||||
@@ -479,6 +490,9 @@ const reloadView = () => {
|
||||
const defaultUrl = WEBVIEW.viewUrls[WEBVIEW.viewActive];
|
||||
const currentUrl = view.webContents.getURL();
|
||||
|
||||
// Reset log history
|
||||
APP.logs = [];
|
||||
|
||||
// Reload the default url or refresh the page
|
||||
if (currentUrl.startsWith("data:")) {
|
||||
view.webContents.loadURL(defaultUrl);
|
||||
@@ -897,7 +911,14 @@ const viewEvents = async () => {
|
||||
if (WEBVIEW.viewActive === 0 && ready.length === WEBVIEW.views.length) {
|
||||
nextView();
|
||||
}
|
||||
view.webContents.loadURL(errorHtml(code, text, url, WEBVIEW.theme.get()));
|
||||
switch (code) {
|
||||
case -3:
|
||||
console.warn(`Load Warning: ${url}, ERR_ABORTED (${code})`);
|
||||
break;
|
||||
default:
|
||||
console.error(`Load Error: ${url}, ${text} (${code})`);
|
||||
view.webContents.loadURL(errorHtml(code, text, url, WEBVIEW.theme.get()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -928,7 +949,7 @@ const viewEvents = async () => {
|
||||
WEBVIEW.tracker.pointer.time = now;
|
||||
WEBVIEW.tracker.pointer.position = posNew;
|
||||
if (delta > 30) {
|
||||
console.log("Update Last Active");
|
||||
console.info("Update Last Active");
|
||||
integration.update();
|
||||
}
|
||||
}
|
||||
@@ -938,7 +959,7 @@ const viewEvents = async () => {
|
||||
case "left":
|
||||
// Ignore touch event if display was off
|
||||
if (WEBVIEW.tracker.display.off > WEBVIEW.tracker.display.on) {
|
||||
console.log("Display Touch Event: Ignored");
|
||||
console.verbose("Display Touch Event: Ignored");
|
||||
e.preventDefault();
|
||||
}
|
||||
// Turn display on if it was off
|
||||
|
||||
Reference in New Issue
Block a user