Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
092697850d | ||
|
|
422e92dd89 | ||
|
|
a15c0fc91d | ||
|
|
358fa3ca9c | ||
|
|
10722fa217 | ||
|
|
7267fafb97 | ||
|
|
b5e95936dc | ||
|
|
047b38a41b | ||
|
|
a93fbb2ad3 | ||
|
|
0b927a3ef6 | ||
|
|
d35cf27de9 |
@@ -17,13 +17,14 @@ Moreover, the device running the **kiosk application** also offers several **Hom
|
|||||||
- [x] Configurable browser zoom and theme support.
|
- [x] Configurable browser zoom and theme support.
|
||||||
- [x] Extended touch screen wake-up functionality.
|
- [x] Extended touch screen wake-up functionality.
|
||||||
- [x] Remote controllable via MQTT.
|
- [x] Remote controllable via MQTT.
|
||||||
- [x] Manage kiosk window status.
|
|
||||||
- [x] Toggle the on-screen keyboard.
|
- [x] Toggle the on-screen keyboard.
|
||||||
- [x] Touch display power and brightness.
|
- [x] Touch display power and brightness.
|
||||||
|
- [x] Manage kiosk window status and zoom.
|
||||||
|
- [x] Show network interfaces and addresses.
|
||||||
|
- [x] List all available system package upgrades.
|
||||||
- [x] Multi-webpage switching and url navigation.
|
- [x] Multi-webpage switching and url navigation.
|
||||||
- [x] Monitor temperature, processor and memory usage.
|
- [x] Monitor temperature, processor and memory usage.
|
||||||
- [x] Execute system reboot and shutdown commands.
|
- [x] Execute system reboot and shutdown commands.
|
||||||
- [x] Show available system package upgrades.
|
|
||||||
|
|
||||||
The kiosk application can be executed with command line arguments to load a **Home Assistant dashboard in fullscreen** mode.
|
The kiosk application can be executed with command line arguments to load a **Home Assistant dashboard in fullscreen** mode.
|
||||||
Additionally, a **MQTT endpoint** can be defined, allowing the application to provide controls and sensors for the Linux device and the connected Touch Display.
|
Additionally, a **MQTT endpoint** can be defined, allowing the application to provide controls and sensors for the Linux device and the connected Touch Display.
|
||||||
@@ -91,7 +92,8 @@ yarn build
|
|||||||
#### Update
|
#### Update
|
||||||
If you have already installed TouchKio and want to upgrade to the latest version, simply install the newer version over the existing one.
|
If you have already installed TouchKio and want to upgrade to the latest version, simply install the newer version over the existing one.
|
||||||
|
|
||||||
The [install.sh](https://github.com/leukipp/touchkio/blob/main/install.sh) script can also be run to update an existing installation to the **latest version**. The setup procedure can be skipped to use the existing default arguments from the configuration file:
|
The [install.sh](https://github.com/leukipp/touchkio/blob/main/install.sh) script can also be run to update an existing installation to the **latest version**.
|
||||||
|
The setup procedure can be skipped to use the existing default arguments from the configuration file:
|
||||||
```bash
|
```bash
|
||||||
bash <(wget -qO- https://raw.githubusercontent.com/leukipp/touchkio/main/install.sh) update
|
bash <(wget -qO- https://raw.githubusercontent.com/leukipp/touchkio/main/install.sh) update
|
||||||
```
|
```
|
||||||
@@ -249,9 +251,10 @@ Implementing stronger **security measures** would complicate the setup process a
|
|||||||
When using the kiosk application without initializing the default arguments, you will need to provide them with every command.
|
When using the kiosk application without initializing the default arguments, you will need to provide them with every command.
|
||||||
This means that the password may be stored as plain text in various files, such as `touchkio.service`, `~/.bash_history`, etc.
|
This means that the password may be stored as plain text in various files, such as `touchkio.service`, `~/.bash_history`, etc.
|
||||||
|
|
||||||
To resolve the issue where the first **touch** on a **turned-off screen** triggers a **click event** (which could inadvertently activate Home Assistant actions), a workaround needed to be implemented.
|
To address the problem where the first **touch** on a **turned-off screen** may trigger a **click event** (which could inadvertently activate Home Assistant actions), a workaround needed to be implemented.
|
||||||
When the screen **turns off** the **focus** is removed from the kiosk window.
|
When the screen **turns on/off**, the timestamps of these events are recorded.
|
||||||
This way, the first click only turns the screen on and focuses the window, allowing subsequent clicks to work as expected.
|
If a touch event is detected and the **timestamp** of the **last screen-off** is more recent than the **last screen-on** timestamp, the touch event is discarded and the screen is turned on instead.
|
||||||
|
From that point onward, subsequent touch interactions will function normally as expected.
|
||||||
|
|
||||||
Additionally, to address the problem that scrolling only works with the **web browser scrollbar** on the right, the application is configured to **simulate a touch device** using `Emulation.setEmitTouchEventsForMouse`.
|
Additionally, to address the problem that scrolling only works with the **web browser scrollbar** on the right, the application is configured to **simulate a touch device** using `Emulation.setEmitTouchEventsForMouse`.
|
||||||
This adjustment provides a user experience similar to that of a proper mobile device.
|
This adjustment provides a user experience similar to that of a proper mobile device.
|
||||||
@@ -259,7 +262,7 @@ This adjustment provides a user experience similar to that of a proper mobile de
|
|||||||
</div></details>
|
</div></details>
|
||||||
|
|
||||||
## Issues
|
## Issues
|
||||||
Please have a look into the [hardware](https://github.com/leukipp/touchkio/blob/main/HARDWARE.md) documentation if you ran into any issues.
|
Please review the [hardware](https://github.com/leukipp/touchkio/blob/main/HARDWARE.md) documentation first if you encounter any problems.
|
||||||
|
|
||||||
**Minimal features** are designed to run on any system without issues:
|
**Minimal features** are designed to run on any system without issues:
|
||||||
- A webview kiosk window launched in fullscreen mode and loading the specified `--web-url` website should not cause any problems.
|
- A webview kiosk window launched in fullscreen mode and loading the specified `--web-url` website should not cause any problems.
|
||||||
@@ -282,8 +285,10 @@ Please have a look into the [hardware](https://github.com/leukipp/touchkio/blob/
|
|||||||
- On the terminal you may see some *ERROR:gbm_wrapper.cc* messages.
|
- On the terminal you may see some *ERROR:gbm_wrapper.cc* messages.
|
||||||
- This appears to be a [known issue](https://github.com/electron/electron/issues/42322) that currently lacks a fix, but the webview still works.
|
- This appears to be a [known issue](https://github.com/electron/electron/issues/42322) that currently lacks a fix, but the webview still works.
|
||||||
|
|
||||||
For debugging, stop the service and run `touchkio` directly on the terminal to view the log outputs.
|
For debugging, stop the service and launch `touchkio` directly on the terminal to monitor the log output in real-time.
|
||||||
If you encounter any problems, please [create an issue](https://github.com/leukipp/touchkio/issues) and include the output of `touchkio --version` along with your system setup and any additional terminal logs.
|
This output is also written into `~/.config/touchkio/logs/main.log` for review.
|
||||||
|
|
||||||
|
If you encounter any problems, please [create an issue](https://github.com/leukipp/touchkio/issues) and include the output of `touchkio --version`, additional information's about your system (such as operating system, hardware specs, etc.) and any relevant log files.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
Thanks to Sebastian ([@pdsccode](https://github.com/pdsccode)) for his contributions on issues and [community](https://community.home-assistant.io/t/kiosk-mode-for-raspberry-pi-with-touch-display/821196) discussions.
|
Thanks to Sebastian ([@pdsccode](https://github.com/pdsccode)) for his contributions on issues and [community](https://community.home-assistant.io/t/kiosk-mode-for-raspberry-pi-with-touch-display/821196) discussions.
|
||||||
|
|||||||
+4
-4
@@ -62,13 +62,13 @@ module.exports = {
|
|||||||
for (const result of results) {
|
for (const result of results) {
|
||||||
const artifacts = [];
|
const artifacts = [];
|
||||||
for (const artifact of result.artifacts) {
|
for (const artifact of result.artifacts) {
|
||||||
// Currently disabled for zip files as it seems to corrupt them
|
if (artifact.includes(".zip")) {
|
||||||
if (artifact.includes(".zip") && false) {
|
|
||||||
const [name, platform, arch] = path.basename(artifact).split("-");
|
const [name, platform, arch] = path.basename(artifact).split("-");
|
||||||
const buildFile = path.join(`${name}-${platform}-${arch}`, "resources", "app", "build.json");
|
const buildFile = path.join(`${name}-${platform}-${arch}`, "resources", "app", "build.json");
|
||||||
const zip = await jszip.loadAsync(fs.readFileSync(artifact, "utf8"));
|
const options = { type: "nodebuffer", compression: "DEFLATE", compressionOptions: { level: 9 } };
|
||||||
|
const zip = await jszip.loadAsync(fs.readFileSync(artifact));
|
||||||
zip.file(buildFile, generateBuildFile(platform, arch, "zip"));
|
zip.file(buildFile, generateBuildFile(platform, arch, "zip"));
|
||||||
fs.writeFileSync(artifact, await zip.generateAsync({ type: "nodebuffer" }));
|
fs.writeFileSync(artifact, await zip.generateAsync(options));
|
||||||
}
|
}
|
||||||
if (artifact.includes("amd64")) {
|
if (artifact.includes("amd64")) {
|
||||||
const renamed = artifact.replace("amd64", "x64");
|
const renamed = artifact.replace("amd64", "x64");
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ const readline = require("readline/promises");
|
|||||||
const integration = require("./js/integration");
|
const integration = require("./js/integration");
|
||||||
const hardware = require("./js/hardware");
|
const hardware = require("./js/hardware");
|
||||||
const webview = require("./js/webview");
|
const webview = require("./js/webview");
|
||||||
|
const log = require("electron-log");
|
||||||
const { app } = require("electron");
|
const { app } = require("electron");
|
||||||
|
const Events = require("events");
|
||||||
|
|
||||||
global.APP = global.APP || {};
|
global.APP = global.APP || {};
|
||||||
global.ARGS = global.ARGS || {};
|
global.ARGS = global.ARGS || {};
|
||||||
|
global.EVENTS = global.EVENTS || new Events();
|
||||||
|
|
||||||
if (!process.env.DISPLAY) {
|
if (!process.env.DISPLAY) {
|
||||||
console.error(`\n$DISPLAY variable not set to run the GUI application, are you connected via SSH?\n`);
|
console.error(`\n$DISPLAY variable not set to run the GUI application, are you connected via SSH?\n`);
|
||||||
@@ -24,12 +27,16 @@ if (!process.env.DISPLAY) {
|
|||||||
* initialization tasks.
|
* initialization tasks.
|
||||||
*/
|
*/
|
||||||
app.whenReady().then(async () => {
|
app.whenReady().then(async () => {
|
||||||
if (!(await initApp()) || !(await initArgs())) {
|
if (!(await initApp()) || !(await initArgs()) || !(await initLog())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show used arguments
|
// Show used arguments
|
||||||
console.log(`Arguments: ${JSON.stringify(ARGS, null, 2)}`);
|
const args = Object.assign({}, ARGS);
|
||||||
|
if ("mqtt_password" in args) {
|
||||||
|
args.mqtt_password = "*".repeat((args.mqtt_password || "").length);
|
||||||
|
}
|
||||||
|
console.log(`Arguments: ${JSON.stringify(args, null, 2)}`);
|
||||||
|
|
||||||
// Chained init functions
|
// Chained init functions
|
||||||
const chained = [webview.init, hardware.init, integration.init];
|
const chained = [webview.init, hardware.init, integration.init];
|
||||||
@@ -58,6 +65,7 @@ const initApp = async () => {
|
|||||||
APP.version = app.getVersion();
|
APP.version = app.getVersion();
|
||||||
APP.path = app.getAppPath();
|
APP.path = app.getAppPath();
|
||||||
APP.config = app.getPath("userData");
|
APP.config = app.getPath("userData");
|
||||||
|
APP.log = path.join(app.getPath("logs"), "main.log");
|
||||||
|
|
||||||
// Set additional update infos
|
// Set additional update infos
|
||||||
APP.homepage = `https://github.com/${packageJson.author}/${packageJson.name}`;
|
APP.homepage = `https://github.com/${packageJson.author}/${packageJson.name}`;
|
||||||
@@ -133,6 +141,29 @@ const initArgs = async () => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the global log object.
|
||||||
|
*
|
||||||
|
* @returns {bool} Returns true if the initialization was successful.
|
||||||
|
*/
|
||||||
|
const initLog = async () => {
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(APP.log)) {
|
||||||
|
fs.unlinkSync(APP.log);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete log file:", error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite console log settings
|
||||||
|
log.transports.file.resolvePathFn = () => {
|
||||||
|
return APP.log;
|
||||||
|
};
|
||||||
|
Object.assign(console, log.functions);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses command-line arguments from the given process object.
|
* Parses command-line arguments from the given process object.
|
||||||
*
|
*
|
||||||
|
|||||||
+29
-26
@@ -3,13 +3,11 @@ const fs = require("fs");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fsp = require("fs/promises");
|
const fsp = require("fs/promises");
|
||||||
const cpr = require("child_process");
|
const cpr = require("child_process");
|
||||||
const Events = require("events");
|
|
||||||
|
|
||||||
global.HARDWARE = global.HARDWARE || {
|
global.HARDWARE = global.HARDWARE || {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
events: new Events(),
|
|
||||||
session: {},
|
|
||||||
support: {},
|
support: {},
|
||||||
|
session: {},
|
||||||
battery: {
|
battery: {
|
||||||
level: {
|
level: {
|
||||||
path: null,
|
path: null,
|
||||||
@@ -39,7 +37,7 @@ global.HARDWARE = global.HARDWARE || {
|
|||||||
*/
|
*/
|
||||||
const init = async () => {
|
const init = async () => {
|
||||||
if (!compatibleSystem()) {
|
if (!compatibleSystem()) {
|
||||||
console.warn("Operating system is not supported\n");
|
console.error("Operating system is not supported");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,33 +54,35 @@ const init = async () => {
|
|||||||
HARDWARE.initialized = true;
|
HARDWARE.initialized = true;
|
||||||
|
|
||||||
// Show supported features
|
// Show supported features
|
||||||
console.log(`\nSupported: ${JSON.stringify(HARDWARE.support, null, 2)}`);
|
process.stdout.write("\n");
|
||||||
|
console.log(`Supported: ${JSON.stringify(HARDWARE.support, null, 2)}`);
|
||||||
|
|
||||||
// Show session infos
|
// Show session infos
|
||||||
console.log("\nUser:", HARDWARE.session.user);
|
process.stdout.write("\n");
|
||||||
|
console.log("User:", HARDWARE.session.user);
|
||||||
console.log("Session:", HARDWARE.session.type);
|
console.log("Session:", HARDWARE.session.type);
|
||||||
console.log("Desktop:", HARDWARE.session.desktop);
|
console.log("Desktop:", HARDWARE.session.desktop);
|
||||||
|
|
||||||
// Show device infos
|
// Show device infos
|
||||||
console.log("\nModel:", getModel());
|
process.stdout.write("\n");
|
||||||
|
console.log("Model:", getModel());
|
||||||
console.log("Vendor:", getVendor());
|
console.log("Vendor:", getVendor());
|
||||||
console.log("Serial Number:", getSerialNumber());
|
console.log("Serial Number:", getSerialNumber());
|
||||||
console.log("Network Addresses:", getNetworkAddresses());
|
console.log("Network Addresses:", getNetworkAddresses());
|
||||||
console.log("Host Name:", getHostName());
|
console.log("Host Name:", getHostName());
|
||||||
|
|
||||||
// Show system infos
|
// Show system infos
|
||||||
console.log("\nUp Time:", getUpTime());
|
process.stdout.write("\n");
|
||||||
|
console.log("Up Time:", getUpTime());
|
||||||
console.log("Memory Size:", getMemorySize());
|
console.log("Memory Size:", getMemorySize());
|
||||||
console.log("Memory Usage:", getMemoryUsage());
|
console.log("Memory Usage:", getMemoryUsage());
|
||||||
console.log("Processor Usage:", getProcessorUsage());
|
console.log("Processor Usage:", getProcessorUsage());
|
||||||
console.log("Processor Temperature:", getProcessorTemperature());
|
console.log("Processor Temperature:", getProcessorTemperature());
|
||||||
|
|
||||||
// Show hardware infos
|
// Show hardware infos
|
||||||
|
process.stdout.write("\n");
|
||||||
const unsupported = "unsupported";
|
const unsupported = "unsupported";
|
||||||
console.log(
|
console.log(`Battery Level [${HARDWARE.battery.level.path || unsupported}]:`, `${getBatteryLevel() || unsupported}`);
|
||||||
`\nBattery Level [${HARDWARE.battery.level.path || unsupported}]:`,
|
|
||||||
`${getBatteryLevel() || unsupported}`,
|
|
||||||
);
|
|
||||||
console.log(
|
console.log(
|
||||||
`Display Status [${HARDWARE.display.status.path || unsupported}]:`,
|
`Display Status [${HARDWARE.display.status.path || unsupported}]:`,
|
||||||
`${getDisplayStatus() || unsupported} (${HARDWARE.display.status.command || unsupported})`,
|
`${getDisplayStatus() || unsupported} (${HARDWARE.display.status.command || unsupported})`,
|
||||||
@@ -93,10 +93,11 @@ const init = async () => {
|
|||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
`Keyboard Visibility [${HARDWARE.support.keyboardVisibility ? "squeekboard" : unsupported}]:`,
|
`Keyboard Visibility [${HARDWARE.support.keyboardVisibility ? "squeekboard" : unsupported}]:`,
|
||||||
`${getKeyboardVisibility() || unsupported}\n`,
|
`${getKeyboardVisibility() || unsupported}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check for keyboard visibility
|
// Check for keyboard visibility
|
||||||
|
process.stdout.write("\n");
|
||||||
setKeyboardVisibility("OFF", (reply, error) => {
|
setKeyboardVisibility("OFF", (reply, error) => {
|
||||||
if (!reply || error) {
|
if (!reply || error) {
|
||||||
return;
|
return;
|
||||||
@@ -106,12 +107,14 @@ const init = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HARDWARE.keyboard.visibility = property.Visible === "true";
|
HARDWARE.keyboard.visibility = property.Visible === "true";
|
||||||
HARDWARE.events.emit("updateKeyboard");
|
EVENTS.emit("updateKeyboard");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for display changes
|
// Check for display changes
|
||||||
interval(update, 1000);
|
setDisplayStatus("ON", () => {
|
||||||
|
interval(update, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@@ -130,7 +133,7 @@ const update = async () => {
|
|||||||
if (status !== HARDWARE.display.status.value) {
|
if (status !== HARDWARE.display.status.value) {
|
||||||
console.log("Update Display Status:", getDisplayStatus());
|
console.log("Update Display Status:", getDisplayStatus());
|
||||||
HARDWARE.display.status.value = status;
|
HARDWARE.display.status.value = status;
|
||||||
HARDWARE.events.emit("updateDisplay");
|
EVENTS.emit("updateDisplay");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +143,7 @@ const update = async () => {
|
|||||||
if (brightness !== HARDWARE.display.brightness.value) {
|
if (brightness !== HARDWARE.display.brightness.value) {
|
||||||
console.log("Update Display Brightness:", getDisplayBrightness());
|
console.log("Update Display Brightness:", getDisplayBrightness());
|
||||||
HARDWARE.display.brightness.value = brightness;
|
HARDWARE.display.brightness.value = brightness;
|
||||||
HARDWARE.events.emit("updateDisplay");
|
EVENTS.emit("updateDisplay");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -796,24 +799,24 @@ const execAsyncCommand = (cmd, args = [], callback = null) => {
|
|||||||
* @returns {Object} The spawned process object.
|
* @returns {Object} The spawned process object.
|
||||||
*/
|
*/
|
||||||
const execScriptCommand = (cmd, args = [], callback = null) => {
|
const execScriptCommand = (cmd, args = [], callback = null) => {
|
||||||
let progress = 10;
|
let progress = 1;
|
||||||
let proc = cpr.spawn(cmd, args);
|
let proc = cpr.spawn(cmd, args);
|
||||||
if (typeof callback === "function") callback(progress, null);
|
if (typeof callback === "function") callback(progress, null);
|
||||||
proc.stdout.on("data", (data) => {
|
proc.stdout.on("data", (data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
const lines = data.toString().trim();
|
const output = data.toString().trim();
|
||||||
const output = lines.replace(/\n+/g, "\n").replace(/^\n+|\n+$|\0/g, "");
|
const lines = output.replace(/\n+/g, "\n").replace(/^\n+|\n+$|\0/g, "");
|
||||||
if (output) {
|
for (const line of lines.split("\n").filter(Boolean)) {
|
||||||
console.log(output);
|
console.log(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
proc.stderr.on("data", (data) => {
|
proc.stderr.on("data", (data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
const lines = data.toString().trim();
|
const output = data.toString().trim();
|
||||||
const output = lines.replace(/\n+/g, "\n").replace(/^\n+|\n+$|\0/g, "");
|
const lines = output.replace(/\n+/g, "\n").replace(/^\n+|\n+$|\0/g, "");
|
||||||
if (output) {
|
for (const line of lines.split("\n").filter(Boolean)) {
|
||||||
const matches = output.match(/(\d{1,3})%/g);
|
const matches = line.match(/(\d{1,3})%/g);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
const match = Math.max(...matches.map((p) => parseInt(p)));
|
const match = Math.max(...matches.map((p) => parseInt(p)));
|
||||||
const percent = Math.floor(match / 10) * 10;
|
const percent = Math.floor(match / 10) * 10;
|
||||||
|
|||||||
+73
-64
@@ -1,11 +1,9 @@
|
|||||||
const mqtt = require("mqtt");
|
const mqtt = require("mqtt");
|
||||||
const hardware = require("./hardware");
|
const hardware = require("./hardware");
|
||||||
const { app } = require("electron");
|
const { app } = require("electron");
|
||||||
const Events = require("events");
|
|
||||||
|
|
||||||
global.INTEGRATION = global.INTEGRATION || {
|
global.INTEGRATION = global.INTEGRATION || {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
events: new Events(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,7 +57,8 @@ const init = async () => {
|
|||||||
// Client connected
|
// Client connected
|
||||||
INTEGRATION.client
|
INTEGRATION.client
|
||||||
.once("connect", () => {
|
.once("connect", () => {
|
||||||
console.log(`MQTT Connected: ${url.toString()}\n`);
|
console.log(`MQTT Connected: ${url.toString()}`);
|
||||||
|
process.stdout.write("\n");
|
||||||
|
|
||||||
// Init client controls
|
// Init client controls
|
||||||
initApp();
|
initApp();
|
||||||
@@ -96,8 +95,8 @@ const init = async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Update sensor states from events
|
// Update sensor states from events
|
||||||
HARDWARE.events.on("updateDisplay", updateDisplay);
|
EVENTS.on("updateDisplay", updateDisplay);
|
||||||
HARDWARE.events.on("updateKeyboard", updateKeyboard);
|
EVENTS.on("updateKeyboard", updateKeyboard);
|
||||||
|
|
||||||
// Update time sensors periodically (30s)
|
// Update time sensors periodically (30s)
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
@@ -207,10 +206,14 @@ const initApp = () => {
|
|||||||
.on("message", (topic, message) => {
|
.on("message", (topic, message) => {
|
||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
console.log("Update App...");
|
console.log("Update App...");
|
||||||
hardware.setDisplayStatus("ON");
|
hardware.setDisplayStatus("ON", () => {
|
||||||
const args = ["-c", `bash <(wget -qO- ${APP.scripts.install}) update`];
|
const args = ["-c", `bash <(wget -qO- ${APP.scripts.install}) update`];
|
||||||
hardware.execScriptCommand("bash", args, (progress, error) => {
|
hardware.execScriptCommand("bash", args, (progress, error) => {
|
||||||
updateApp(progress);
|
if (progress) {
|
||||||
|
console.log(`Progress: ${progress}%`);
|
||||||
|
}
|
||||||
|
updateApp(progress);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -257,8 +260,9 @@ const initShutdown = () => {
|
|||||||
.on("message", (topic, message) => {
|
.on("message", (topic, message) => {
|
||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
console.log("Shutdown system...");
|
console.log("Shutdown system...");
|
||||||
hardware.setDisplayStatus("ON");
|
hardware.setDisplayStatus("ON", () => {
|
||||||
hardware.shutdownSystem();
|
hardware.shutdownSystem();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -283,8 +287,9 @@ const initReboot = () => {
|
|||||||
.on("message", (topic, message) => {
|
.on("message", (topic, message) => {
|
||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
console.log("Rebooting system...");
|
console.log("Rebooting system...");
|
||||||
hardware.setDisplayStatus("ON");
|
hardware.setDisplayStatus("ON", () => {
|
||||||
hardware.rebootSystem();
|
hardware.rebootSystem();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -306,8 +311,9 @@ const initRefresh = () => {
|
|||||||
.on("message", (topic, message) => {
|
.on("message", (topic, message) => {
|
||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
console.log("Refreshing webview...");
|
console.log("Refreshing webview...");
|
||||||
hardware.setDisplayStatus("ON");
|
hardware.setDisplayStatus("ON", () => {
|
||||||
WEBVIEW.events.emit("reloadView");
|
EVENTS.emit("reloadView");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -333,31 +339,32 @@ const initKiosk = () => {
|
|||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
const status = message.toString();
|
const status = message.toString();
|
||||||
console.log("Set Kiosk Status:", status);
|
console.log("Set Kiosk Status:", status);
|
||||||
hardware.setDisplayStatus("ON");
|
hardware.setDisplayStatus("ON", () => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "Framed":
|
case "Framed":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.unmaximize();
|
WEBVIEW.window.unmaximize();
|
||||||
WEBVIEW.window.setFullScreen(false);
|
WEBVIEW.window.setFullScreen(false);
|
||||||
break;
|
break;
|
||||||
case "Fullscreen":
|
case "Fullscreen":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.unmaximize();
|
WEBVIEW.window.unmaximize();
|
||||||
WEBVIEW.window.setFullScreen(true);
|
WEBVIEW.window.setFullScreen(true);
|
||||||
break;
|
break;
|
||||||
case "Maximized":
|
case "Maximized":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.setFullScreen(false);
|
WEBVIEW.window.setFullScreen(false);
|
||||||
WEBVIEW.window.maximize();
|
WEBVIEW.window.maximize();
|
||||||
break;
|
break;
|
||||||
case "Minimized":
|
case "Minimized":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.setFullScreen(false);
|
WEBVIEW.window.setFullScreen(false);
|
||||||
WEBVIEW.window.minimize();
|
WEBVIEW.window.minimize();
|
||||||
break;
|
break;
|
||||||
case "Terminated":
|
case "Terminated":
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -368,7 +375,7 @@ const initKiosk = () => {
|
|||||||
* Updates the kiosk status via the mqtt connection.
|
* Updates the kiosk status via the mqtt connection.
|
||||||
*/
|
*/
|
||||||
const updateKiosk = async () => {
|
const updateKiosk = async () => {
|
||||||
const kiosk = WEBVIEW.status;
|
const kiosk = WEBVIEW.tracker.status;
|
||||||
publishState("kiosk", kiosk);
|
publishState("kiosk", kiosk);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -400,20 +407,20 @@ const initDisplay = () => {
|
|||||||
const status = message.toString();
|
const status = message.toString();
|
||||||
console.log("Set Display Status:", status);
|
console.log("Set Display Status:", status);
|
||||||
hardware.setDisplayStatus(status, (reply, error) => {
|
hardware.setDisplayStatus(status, (reply, error) => {
|
||||||
if (error) {
|
if (!error) {
|
||||||
console.warn("Failed:", error);
|
|
||||||
} else {
|
|
||||||
hardware.update();
|
hardware.update();
|
||||||
|
} else {
|
||||||
|
console.warn("Failed:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (topic === config.brightness_command_topic) {
|
} else if (topic === config.brightness_command_topic) {
|
||||||
const brightness = parseInt(message, 10);
|
const brightness = parseInt(message, 10);
|
||||||
console.log("Set Display Brightness:", brightness);
|
console.log("Set Display Brightness:", brightness);
|
||||||
hardware.setDisplayBrightness(brightness, (reply, error) => {
|
hardware.setDisplayBrightness(brightness, (reply, error) => {
|
||||||
if (error) {
|
if (!error) {
|
||||||
console.warn("Failed:", error);
|
|
||||||
} else {
|
|
||||||
hardware.update();
|
hardware.update();
|
||||||
|
} else {
|
||||||
|
console.warn("Failed:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -454,19 +461,21 @@ const initKeyboard = () => {
|
|||||||
if (topic === config.command_topic) {
|
if (topic === config.command_topic) {
|
||||||
const status = message.toString();
|
const status = message.toString();
|
||||||
console.log("Set Keyboard Visibility:", status);
|
console.log("Set Keyboard Visibility:", status);
|
||||||
hardware.setKeyboardVisibility(status);
|
hardware.setDisplayStatus("ON", () => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "OFF":
|
case "OFF":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.unmaximize();
|
WEBVIEW.window.unmaximize();
|
||||||
WEBVIEW.window.setFullScreen(true);
|
WEBVIEW.window.setFullScreen(true);
|
||||||
break;
|
break;
|
||||||
case "ON":
|
case "ON":
|
||||||
WEBVIEW.window.restore();
|
WEBVIEW.window.restore();
|
||||||
WEBVIEW.window.setFullScreen(false);
|
WEBVIEW.window.setFullScreen(false);
|
||||||
WEBVIEW.window.maximize();
|
WEBVIEW.window.maximize();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
hardware.setKeyboardVisibility(status);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -508,7 +517,7 @@ const initPageNumber = () => {
|
|||||||
const number = parseInt(message, 10);
|
const number = parseInt(message, 10);
|
||||||
console.log("Set Page Number:", number);
|
console.log("Set Page Number:", number);
|
||||||
WEBVIEW.viewActive = number || 1;
|
WEBVIEW.viewActive = number || 1;
|
||||||
WEBVIEW.events.emit("updateView");
|
EVENTS.emit("updateView");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -547,7 +556,7 @@ const initPageZoom = () => {
|
|||||||
const zoom = parseInt(message, 10);
|
const zoom = parseInt(message, 10);
|
||||||
console.log("Set Page Zoom:", zoom);
|
console.log("Set Page Zoom:", zoom);
|
||||||
WEBVIEW.views[WEBVIEW.viewActive || 1].webContents.setZoomFactor(zoom / 100.0);
|
WEBVIEW.views[WEBVIEW.viewActive || 1].webContents.setZoomFactor(zoom / 100.0);
|
||||||
WEBVIEW.events.emit("updateView");
|
EVENTS.emit("updateView");
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.subscribe(config.command_topic);
|
.subscribe(config.command_topic);
|
||||||
@@ -946,8 +955,8 @@ const initLastActive = () => {
|
|||||||
*/
|
*/
|
||||||
const updateLastActive = async () => {
|
const updateLastActive = async () => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const then = WEBVIEW.pointer.time;
|
const then = WEBVIEW.tracker.pointer.time;
|
||||||
const lastActive = Math.abs(now - then) / (1000 * 60);
|
const lastActive = (now - then) / (1000 * 60);
|
||||||
publishState("last_active", lastActive);
|
publishState("last_active", lastActive);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+64
-49
@@ -3,15 +3,16 @@ const axios = require("axios");
|
|||||||
const hardware = require("./hardware");
|
const hardware = require("./hardware");
|
||||||
const integration = require("./integration");
|
const integration = require("./integration");
|
||||||
const { app, nativeTheme, globalShortcut, ipcMain, session, BaseWindow, WebContentsView } = require("electron");
|
const { app, nativeTheme, globalShortcut, ipcMain, session, BaseWindow, WebContentsView } = require("electron");
|
||||||
const Events = require("events");
|
|
||||||
|
|
||||||
global.WEBVIEW = global.WEBVIEW || {
|
global.WEBVIEW = global.WEBVIEW || {
|
||||||
initialized: false,
|
initialized: false,
|
||||||
events: new Events(),
|
tracker: {
|
||||||
status: null,
|
pointer: {
|
||||||
locked: false,
|
position: {},
|
||||||
pointer: {
|
time: new Date(),
|
||||||
time: new Date(),
|
},
|
||||||
|
display: {},
|
||||||
|
status: null,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -49,8 +50,6 @@ const init = async () => {
|
|||||||
WEBVIEW.navigationTheme = theme;
|
WEBVIEW.navigationTheme = theme;
|
||||||
WEBVIEW.navigationEnabled = widget;
|
WEBVIEW.navigationEnabled = widget;
|
||||||
nativeTheme.themeSource = WEBVIEW.viewTheme;
|
nativeTheme.themeSource = WEBVIEW.viewTheme;
|
||||||
WEBVIEW.events.on("reloadView", reloadView);
|
|
||||||
WEBVIEW.events.on("updateView", updateView);
|
|
||||||
|
|
||||||
// Init global root window
|
// Init global root window
|
||||||
WEBVIEW.window = new BaseWindow({
|
WEBVIEW.window = new BaseWindow({
|
||||||
@@ -117,7 +116,17 @@ const init = async () => {
|
|||||||
WEBVIEW.window.contentView.addChildView(WEBVIEW.navigation);
|
WEBVIEW.window.contentView.addChildView(WEBVIEW.navigation);
|
||||||
WEBVIEW.navigation.webContents.loadFile(path.join(APP.path, "html", "navigation.html"));
|
WEBVIEW.navigation.webContents.loadFile(path.join(APP.path, "html", "navigation.html"));
|
||||||
|
|
||||||
// Register events
|
// Register global events
|
||||||
|
EVENTS.on("reloadView", reloadView);
|
||||||
|
EVENTS.on("updateView", updateView);
|
||||||
|
EVENTS.on("updateDisplay", () => {
|
||||||
|
const status = hardware.getDisplayStatus();
|
||||||
|
if (status) {
|
||||||
|
WEBVIEW.tracker.display[status.toLowerCase()] = new Date();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register local events
|
||||||
await windowEvents();
|
await windowEvents();
|
||||||
await widgetEvents();
|
await widgetEvents();
|
||||||
await navigationEvents();
|
await navigationEvents();
|
||||||
@@ -135,15 +144,15 @@ const update = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update windows status
|
// Update window status
|
||||||
if (WEBVIEW.window.isFullScreen()) {
|
if (WEBVIEW.window.isFullScreen()) {
|
||||||
WEBVIEW.status = "Fullscreen";
|
WEBVIEW.tracker.status = "Fullscreen";
|
||||||
} else if (WEBVIEW.window.isMinimized()) {
|
} else if (WEBVIEW.window.isMinimized()) {
|
||||||
WEBVIEW.status = "Minimized";
|
WEBVIEW.tracker.status = "Minimized";
|
||||||
} else if (WEBVIEW.window.isMaximized()) {
|
} else if (WEBVIEW.window.isMaximized()) {
|
||||||
WEBVIEW.status = "Maximized";
|
WEBVIEW.tracker.status = "Maximized";
|
||||||
} else {
|
} else {
|
||||||
WEBVIEW.status = "Framed";
|
WEBVIEW.tracker.status = "Framed";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update widget status
|
// Update widget status
|
||||||
@@ -153,7 +162,7 @@ const update = async () => {
|
|||||||
updateNavigation();
|
updateNavigation();
|
||||||
|
|
||||||
// Update integration sensor
|
// Update integration sensor
|
||||||
console.log("Update Kiosk Status:", WEBVIEW.status);
|
console.log("Update Kiosk Status:", WEBVIEW.tracker.status);
|
||||||
integration.update();
|
integration.update();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -433,21 +442,6 @@ const windowEvents = async () => {
|
|||||||
WEBVIEW.window.on("resize", resizeView);
|
WEBVIEW.window.on("resize", resizeView);
|
||||||
resizeView();
|
resizeView();
|
||||||
|
|
||||||
// Handle window focus events
|
|
||||||
WEBVIEW.window.on("focus", () => {
|
|
||||||
if (WEBVIEW.locked) {
|
|
||||||
hardware.setDisplayStatus("ON");
|
|
||||||
WEBVIEW.window.blur();
|
|
||||||
}
|
|
||||||
WEBVIEW.locked = false;
|
|
||||||
});
|
|
||||||
HARDWARE.events.on("updateDisplay", () => {
|
|
||||||
WEBVIEW.locked = hardware.getDisplayStatus() === "OFF";
|
|
||||||
if (WEBVIEW.locked) {
|
|
||||||
WEBVIEW.window.blur();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle window status updates
|
// Handle window status updates
|
||||||
WEBVIEW.window.on("minimize", update);
|
WEBVIEW.window.on("minimize", update);
|
||||||
WEBVIEW.window.on("restore", update);
|
WEBVIEW.window.on("restore", update);
|
||||||
@@ -479,8 +473,8 @@ const windowEvents = async () => {
|
|||||||
// Check for window touch events (1s)
|
// Check for window touch events (1s)
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const then = WEBVIEW.pointer.time;
|
const then = WEBVIEW.tracker.pointer.time;
|
||||||
const delta = Math.abs(now - then) / 1000;
|
const delta = (now - then) / 1000;
|
||||||
|
|
||||||
// Auto-hide navigation
|
// Auto-hide navigation
|
||||||
if (delta > 60) {
|
if (delta > 60) {
|
||||||
@@ -740,18 +734,38 @@ const viewEvents = async () => {
|
|||||||
// Handle webview mouse events
|
// Handle webview mouse events
|
||||||
view.webContents.on("before-mouse-event", (e, mouse) => {
|
view.webContents.on("before-mouse-event", (e, mouse) => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const then = WEBVIEW.pointer.time;
|
const then = WEBVIEW.tracker.pointer.time;
|
||||||
const delta = Math.abs(now - then) / 1000;
|
const delta = (now - then) / 1000;
|
||||||
WEBVIEW.pointer.time = now;
|
|
||||||
switch (mouse.type) {
|
switch (mouse.type) {
|
||||||
case "mouseMove":
|
case "mouseMove":
|
||||||
if (delta > 30) {
|
const posNew = { x: mouse.globalX, y: mouse.globalY };
|
||||||
console.log("Update Last Active");
|
if (posNew.x < 0 || posNew.y < 0) {
|
||||||
integration.update();
|
break;
|
||||||
|
}
|
||||||
|
// Update last active on pointer position change
|
||||||
|
const posOld = WEBVIEW.tracker.pointer.position;
|
||||||
|
if (posOld.x !== posNew.x || posOld.y !== posNew.y) {
|
||||||
|
WEBVIEW.tracker.pointer.time = now;
|
||||||
|
WEBVIEW.tracker.pointer.position = posNew;
|
||||||
|
if (delta > 30) {
|
||||||
|
console.log("Update Last Active");
|
||||||
|
integration.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "mouseDown":
|
case "mouseDown":
|
||||||
switch (mouse.button) {
|
switch (mouse.button) {
|
||||||
|
case "left":
|
||||||
|
// Ignore touch event if display was off
|
||||||
|
if (WEBVIEW.tracker.display.off > WEBVIEW.tracker.display.on) {
|
||||||
|
console.log("Display Touch Event: Ignored");
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
// Turn display on if it was off
|
||||||
|
if (hardware.getDisplayStatus() === "OFF") {
|
||||||
|
hardware.setDisplayStatus("ON");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "back":
|
case "back":
|
||||||
historyBackward();
|
historyBackward();
|
||||||
break;
|
break;
|
||||||
@@ -769,13 +783,6 @@ const viewEvents = async () => {
|
|||||||
* Register app events and handler.
|
* Register app events and handler.
|
||||||
*/
|
*/
|
||||||
const appEvents = async () => {
|
const appEvents = async () => {
|
||||||
// Handle signal and exit events
|
|
||||||
process.on("SIGINT", app.quit);
|
|
||||||
app.on("before-quit", () => {
|
|
||||||
WEBVIEW.status = "Terminated";
|
|
||||||
integration.update();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle multiple instances
|
// Handle multiple instances
|
||||||
app.on("second-instance", () => {
|
app.on("second-instance", () => {
|
||||||
if (WEBVIEW.window.isMinimized()) {
|
if (WEBVIEW.window.isMinimized()) {
|
||||||
@@ -784,14 +791,22 @@ const appEvents = async () => {
|
|||||||
WEBVIEW.window.focus();
|
WEBVIEW.window.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle signal and exit events
|
||||||
|
app.on("before-quit", () => {
|
||||||
|
WEBVIEW.tracker.status = "Terminated";
|
||||||
|
console.warn(`${APP.title} Terminated`);
|
||||||
|
integration.update();
|
||||||
|
});
|
||||||
|
process.on("SIGINT", app.quit);
|
||||||
|
|
||||||
|
// Webview initialized
|
||||||
|
WEBVIEW.initialized = true;
|
||||||
|
|
||||||
// Check for latest release infos (2h)
|
// Check for latest release infos (2h)
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
latestRelease();
|
latestRelease();
|
||||||
}, 7200 * 1000);
|
}, 7200 * 1000);
|
||||||
await latestRelease();
|
await latestRelease();
|
||||||
|
|
||||||
// Webview initialized
|
|
||||||
WEBVIEW.initialized = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -799,7 +814,7 @@ const appEvents = async () => {
|
|||||||
*/
|
*/
|
||||||
const latestRelease = async () => {
|
const latestRelease = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${APP.releases.url}/latest`);
|
const response = await axios.get(`${APP.releases.url}/latest`, { timeout: 10000 });
|
||||||
const data = response ? response.data : null;
|
const data = response ? response.data : null;
|
||||||
if (!data || data.draft || data.prerelease) {
|
if (!data || data.draft || data.prerelease) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,7 @@
|
|||||||
"description": "Home Assistant Touch Kiosk",
|
"description": "Home Assistant Touch Kiosk",
|
||||||
"homepage": "https://github.com/leukipp/touchkio",
|
"homepage": "https://github.com/leukipp/touchkio",
|
||||||
"author": "leukipp",
|
"author": "leukipp",
|
||||||
"version": "1.3.0",
|
"version": "1.3.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
|
"electron-log": "^5.4.3",
|
||||||
"mqtt": "^5.14.1"
|
"mqtt": "^5.14.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -664,9 +664,9 @@ ansi-regex@^5.0.1:
|
|||||||
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
|
||||||
|
|
||||||
ansi-regex@^6.0.1:
|
ansi-regex@^6.0.1:
|
||||||
version "6.2.0"
|
version "6.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.0.tgz#2f302e7550431b1b7762705fffb52cf1ffa20447"
|
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.2.2.tgz#60216eea464d864597ce2832000738a0589650c1"
|
||||||
integrity sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==
|
integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==
|
||||||
|
|
||||||
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
||||||
version "4.3.0"
|
version "4.3.0"
|
||||||
@@ -676,9 +676,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
ansi-styles@^6.0.0, ansi-styles@^6.1.0:
|
ansi-styles@^6.0.0, ansi-styles@^6.1.0:
|
||||||
version "6.2.1"
|
version "6.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
|
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041"
|
||||||
integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
|
integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==
|
||||||
|
|
||||||
asynckit@^0.4.0:
|
asynckit@^0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
@@ -1164,6 +1164,11 @@ electron-installer-debian@^3.2.0:
|
|||||||
word-wrap "^1.2.3"
|
word-wrap "^1.2.3"
|
||||||
yargs "^16.0.2"
|
yargs "^16.0.2"
|
||||||
|
|
||||||
|
electron-log@^5.4.3:
|
||||||
|
version "5.4.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/electron-log/-/electron-log-5.4.3.tgz#02a90baf4256950ca416095db6e5745268584d20"
|
||||||
|
integrity sha512-sOUsM3LjZdugatazSQ/XTyNcw8dfvH1SYhXWiJyfYodAAKOZdHs0txPiLDXFzOZbhXgAgshQkshH2ccq0feyLQ==
|
||||||
|
|
||||||
electron@^38.0.0:
|
electron@^38.0.0:
|
||||||
version "38.0.0"
|
version "38.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-38.0.0.tgz#e51803f62c8d4c368f77642a1b1b05444c687fba"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-38.0.0.tgz#e51803f62c8d4c368f77642a1b1b05444c687fba"
|
||||||
@@ -2861,9 +2866,9 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
|||||||
ansi-regex "^5.0.1"
|
ansi-regex "^5.0.1"
|
||||||
|
|
||||||
strip-ansi@^7.0.1:
|
strip-ansi@^7.0.1:
|
||||||
version "7.1.0"
|
version "7.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
|
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba"
|
||||||
integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
|
integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex "^6.0.1"
|
ansi-regex "^6.0.1"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user