From 9d8c6ccff95cbb11892b2229d3d2b345cb013709 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sat, 24 Apr 2021 15:18:43 +0200 Subject: [PATCH 01/74] Add support to render multiple lovelace tabs within the same instance --- README.md | 38 ++++++++++++++------------ config.js | 49 ++++++++++++++++++++++++--------- index.js | 81 ++++++++++++++++++++++++++++++++++--------------------- 3 files changed, 109 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 74637f7..e81efd2 100644 --- a/README.md +++ b/README.md @@ -22,26 +22,30 @@ You may simple set up the [sibbl/hass-lovelace-kindle-screensaver](https://hub.d Home Assistant related stuff: -- `HA_BASE_URL=https://your-hass-instance.com:8123` -- `HA_SCREENSHOT_URL=/lovelace/screensaver?kiosk` (I recommend the [kiosk mode](https://github.com/maykar/kiosk-mode) project) -- `HA_ACCESS_TOKEN=eyJ0...` (you need to create this token in Home Assistant first) -- `LANGUAGE=en` (language to use in Home Assistant frontend) -- `CRON_JOB=* * * * *` (how often to take screenshots, by default every minute) +| Env Var | Sample value | Required | Array?\* | Description | +| ------------------------- | ------------------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | +| `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/maykar/kiosk-mode) project) | +| `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | +| `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | +| `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | +| `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | +| `RENDERING_DELAY` | `0` | no | yes | how long to wait between navigating to the page and taking the screenshot, in milliseconds | +| `RENDERING_SCREEN_HEIGHT` | `800` | no | yes | Height of your kindle screen resolution | +| `RENDERING_SCREEN_WIDTH` | `600` | no | yes | Width of your kindle screen resolution | +| `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | +| `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | +| `GRAYSCALE_DEPTH` | `8` | no | yes | Ggrayscale bit depth your kindle supports | + +**\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. +If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. -Kindle related stuff: +You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. -- `RENDERING_TIMEOUT=10000` (timeout of render process, necessary if your HASS instance might be down, in milliseconds) -- `RENDERING_DELAY=0` (how long to wait between navigating to the page and taking the screenshot, in milliseconds) -- `RENDERING_SCREEN_HEIGHT=800` (height of your kindle screen resolution, see below) -- `RENDERING_SCREEN_WIDTH=600` (width of your kindle screen resolution, see below) -- `ROTATION=0` (rotation of image in degrees, i.e. use 90 or 270 to render in landscape) -- `SCALING=1` (scaling factor, i.e. 1.5 to zoom in or 0.75 to zoom out) -- `GRAYSCALE_DEPTH=8` (grayscale bit depth your kindle supports) +### Advanced configuration -Advanced stuff: +Some advanced variables for local usage which shouldn't be necessary when using Docker: -- `OUTPUT_PATH=./output.png` (destination of rendered image) +- `OUTPUT_PATH=./output.png` (destination of rendered image. `OUTPUT_2`, `OUTPUT_3`, ... is also supported) - `PORT=5000` (port of server, which returns the last image) - `USE_IMAGE_MAGICK=false` (use ImageMagick instead of GraphicsMagick) - -You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. diff --git a/config.js b/config.js index b9725a2..a3b588a 100644 --- a/config.js +++ b/config.js @@ -1,20 +1,45 @@ +function getEnvironmentVariable(key, suffix, fallbackValue) { + const value = process.env[key + suffix]; + if (value !== undefined) return value; + return fallbackValue || process.env[key]; +} + +function getPagesConfig() { + const pages = []; + let i = 0; + while (++i) { + const suffix = i === 1 ? "" : `_${i}`; + const screenShotUrl = process.env[`HA_SCREENSHOT_URL${suffix}`]; + if (!screenShotUrl) return pages; + pages.push({ + screenShotUrl, + outputPath: getEnvironmentVariable( + "OUTPUT_PATH", + suffix, + `output/cover${suffix}.png` + ), + renderingDelay: getEnvironmentVariable("RENDERING_DELAY", suffix) || 0, + renderingScreenSize: { + height: + getEnvironmentVariable("RENDERING_SCREEN_HEIGHT", suffix) || 800, + width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, + }, + grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, + rotation: getEnvironmentVariable("ROTATION", suffix) || 0, + scaling: getEnvironmentVariable("SCALING", suffix) || 1, + }); + } + return pages; +} + module.exports = { baseUrl: process.env.HA_BASE_URL, - screenShotUrl: process.env.HA_SCREENSHOT_URL || "", accessToken: process.env.HA_ACCESS_TOKEN, cronJob: process.env.CRON_JOB || "* * * * *", - outputPath: process.env.OUTPUT_PATH || "output/cover.png", - renderingTimeout: process.env.RENDERING_TIMEOUT || 10000, - renderingDelay: process.env.RENDERING_DELAY || 0, - renderingScreenSize: { - height: process.env.RENDERING_SCREEN_HEIGHT || 800, - width: process.env.RENDERING_SCREEN_WIDTH || 600, - }, - grayscaleDepth: process.env.GRAYSCALE_DEPTH || 8, useImageMagick: process.env.USE_IMAGE_MAGICK === "true", + pages: getPagesConfig(), port: process.env.PORT || 5000, + renderingTimeout: process.env.RENDERING_TIMEOUT || 10000, language: process.env.LANGUAGE || "en", - rotation: process.env.ROTATION || 0, - scaling: process.env.SCALING || 1, - debug: process.env.DEBUG === "true" + debug: process.env.DEBUG === "true", }; diff --git a/index.js b/index.js index f380b03..574f99d 100644 --- a/index.js +++ b/index.js @@ -8,13 +8,17 @@ const { CronJob } = require("cron"); const gm = require("gm"); (async () => { - if (config.rotation % 90 > 0) { - console.error("Invalid rotation value: " + config.rotation); - return; + if (config.pages.length === 0) { + return console.error("Please check your configuration"); + } + for (const i in config.pages) { + const pageConfig = config.pages[i]; + if (pageConfig.rotation % 90 > 0) { + return console.error( + `Invalid rotation value for entry ${i + 1}: ${pageConfig.rotation}` + ); + } } - - const outputDir = path.dirname(config.outputPath); - await fsExtra.ensureDir(outputDir); console.log("Starting browser..."); let browser = await puppeteer.launch({ @@ -63,10 +67,23 @@ const gm = require("gm"); }); } - const httpServer = http.createServer(async (_, response) => { + const httpServer = http.createServer(async (request, response) => { + const pageNumberStr = request.url; + const pageNumber = + pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); + if ( + isFinite(pageNumber) === false || + pageNumber.length > config.pages.length || + pageNumber < 1 + ) { + console.error('Invalid page requested: ' + pageNumber); + response.writeHead(400); + response.end('Invalid page'); + return; + } try { - const data = await fs.readFile(config.outputPath); - console.log("Image was accessed"); + const data = await fs.readFile(config.pages[pageNumber - 1].outputPath); + console.log(`Image ${pageNumber} was accessed`); response.setHeader("Content-Length", Buffer.byteLength(data)); response.writeHead(200, { "Content-Type": "image/png" }); response.end(data); @@ -84,22 +101,26 @@ const gm = require("gm"); })(); async function renderAndConvertAsync(browser) { - const url = `${config.baseUrl}${config.screenShotUrl}`; + for (const pageConfig of config.pages) { + const url = `${config.baseUrl}${pageConfig.screenShotUrl}`; + + const outputPath = pageConfig.outputPath; + await fsExtra.ensureDir(path.dirname(outputPath)); - const outputPath = config.outputPath; - const tempPath = outputPath + ".temp"; + const tempPath = outputPath + ".temp"; - console.log(`Rendering ${url} to image...`); - await renderUrlToImageAsync(browser, url, tempPath); + console.log(`Rendering ${url} to image...`); + await renderUrlToImageAsync(browser, pageConfig, url, tempPath); - console.log(`Converting rendered screenshot of ${url} to grayscale png...`); - await convertImageToKindleCompatiblePngAsync(tempPath, outputPath); + console.log(`Converting rendered screenshot of ${url} to grayscale png...`); + await convertImageToKindleCompatiblePngAsync(pageConfig, tempPath, outputPath); - fs.unlink(tempPath); - console.log(`Finished ${url}`); + fs.unlink(tempPath); + console.log(`Finished ${url}`); + } } -async function renderUrlToImageAsync(browser, url, path) { +async function renderUrlToImageAsync(browser, pageConfig, url, path) { let page; try { page = await browser.newPage(); @@ -111,11 +132,11 @@ async function renderUrlToImageAsync(browser, url, path) { ]); let size = { - width: Number(config.renderingScreenSize.width), - height: Number(config.renderingScreenSize.height) + width: Number(pageConfig.renderingScreenSize.width), + height: Number(pageConfig.renderingScreenSize.height), }; - if (config.rotation % 180 > 0) { + if (pageConfig.rotation % 180 > 0) { size = { width: size.height, height: size.width, @@ -131,16 +152,16 @@ async function renderUrlToImageAsync(browser, url, path) { await page.addStyleTag({ content: ` body { - width: calc(${config.renderingScreenSize.width}px / ${config.scaling}); - height: calc(${config.renderingScreenSize.height}px / ${config.scaling}); + width: calc(${pageConfig.renderingScreenSize.width}px / ${pageConfig.scaling}); + height: calc(${pageConfig.renderingScreenSize.height}px / ${pageConfig.scaling}); transform-origin: 0 0; - transform: scale(${config.scaling}); + transform: scale(${pageConfig.scaling}); overflow: hidden; }`, }); - if (config.renderingDelay > 0) { - await delay(config.renderingDelay); + if (pageConfig.renderingDelay > 0) { + await delay(pageConfig.renderingDelay); } await page.screenshot({ path, @@ -160,15 +181,15 @@ async function renderUrlToImageAsync(browser, url, path) { } } -function convertImageToKindleCompatiblePngAsync(inputPath, outputPath) { +function convertImageToKindleCompatiblePngAsync(pageConfig, inputPath, outputPath) { return new Promise((resolve, reject) => { gm(inputPath) .options({ imageMagick: config.useImageMagick === true, }) - .rotate("white", config.rotation) + .rotate("white", pageConfig.rotation) .type("GrayScale") - .bitdepth(config.grayscaleDepth) + .bitdepth(pageConfig.grayscaleDepth) .write(outputPath, (err) => { if (err) { reject(err); From c337122ccba3ee2ad40521bd7f5fa90707e893b2 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sat, 24 Apr 2021 15:22:17 +0200 Subject: [PATCH 02/74] Add option to ignore certificate errors #9 --- README.md | 1 + config.js | 2 ++ index.js | 19 ++++++++++++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e81efd2..4f3f55e 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,4 @@ Some advanced variables for local usage which shouldn't be necessary when using - `OUTPUT_PATH=./output.png` (destination of rendered image. `OUTPUT_2`, `OUTPUT_3`, ... is also supported) - `PORT=5000` (port of server, which returns the last image) - `USE_IMAGE_MAGICK=false` (use ImageMagick instead of GraphicsMagick) +- `UNSAFE_IGNORE_CERTIFICATE_ERRORS=true` (ignore certificate errors of e.g. self-signed certificates at your own risk) diff --git a/config.js b/config.js index a3b588a..322d8cc 100644 --- a/config.js +++ b/config.js @@ -42,4 +42,6 @@ module.exports = { renderingTimeout: process.env.RENDERING_TIMEOUT || 10000, language: process.env.LANGUAGE || "en", debug: process.env.DEBUG === "true", + ignoreCertificateErrors: + process.env.UNSAFE_IGNORE_CERTIFICATE_ERRORS === "true", }; diff --git a/index.js b/index.js index 574f99d..55e7140 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,8 @@ const gm = require("gm"); "--disable-dev-shm-usage", "--no-sandbox", `--lang=${config.language}`, - ], + config.ignoreCertificateErrors && "--ignore-certificate-errors", + ].filter((x) => x), headless: config.debug !== true, }); @@ -76,9 +77,9 @@ const gm = require("gm"); pageNumber.length > config.pages.length || pageNumber < 1 ) { - console.error('Invalid page requested: ' + pageNumber); + console.error("Invalid page requested: " + pageNumber); response.writeHead(400); - response.end('Invalid page'); + response.end("Invalid page"); return; } try { @@ -113,7 +114,11 @@ async function renderAndConvertAsync(browser) { await renderUrlToImageAsync(browser, pageConfig, url, tempPath); console.log(`Converting rendered screenshot of ${url} to grayscale png...`); - await convertImageToKindleCompatiblePngAsync(pageConfig, tempPath, outputPath); + await convertImageToKindleCompatiblePngAsync( + pageConfig, + tempPath, + outputPath + ); fs.unlink(tempPath); console.log(`Finished ${url}`); @@ -181,7 +186,11 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { } } -function convertImageToKindleCompatiblePngAsync(pageConfig, inputPath, outputPath) { +function convertImageToKindleCompatiblePngAsync( + pageConfig, + inputPath, + outputPath +) { return new Promise((resolve, reject) => { gm(inputPath) .options({ From ba812b9b6fdfbedf40e27a1fe19b98a1b9de8f91 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sat, 24 Apr 2021 18:04:12 +0200 Subject: [PATCH 03/74] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4f3f55e..280174d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Using my [own Kindle 4 setup guide](https://github.com/sibbl/hass-lovelace-kindl ## Usage -You may simple set up the [sibbl/hass-lovelace-kindle-screensaver](https://hub.docker.com/r/sibbl/hass-lovelace-kindle-screensaver) docker container. The container exposes a single port (5000 by default). You can access the image by doing a simple GET request to e.g. `http://localhost:5000/` to receive the most recent image. +You may simple set up the [sibbl/hass-lovelace-kindle-screensaver](https://hub.docker.com/r/sibbl/hass-lovelace-kindle-screensaver) docker container. The container exposes a single port (5000 by default). + +You can access the image by doing a simple GET request to e.g. `http://localhost:5000/` to receive the most recent image. Home Assistant related stuff: @@ -39,6 +41,7 @@ Home Assistant related stuff: **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. +You can access these additional images by making GET Requests `http://localhost:5000/2`, `http://localhost:5000/3` etc. You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. From 28df5684933d108c1408ed6b75bc9c2a28eea54e Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Wed, 30 Jun 2021 16:42:39 +0200 Subject: [PATCH 04/74] Use possibly swapped size/height for custom css added to body #11 --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 55e7140..04b1df1 100644 --- a/index.js +++ b/index.js @@ -157,8 +157,8 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { await page.addStyleTag({ content: ` body { - width: calc(${pageConfig.renderingScreenSize.width}px / ${pageConfig.scaling}); - height: calc(${pageConfig.renderingScreenSize.height}px / ${pageConfig.scaling}); + width: calc(${size.width}px / ${pageConfig.scaling}); + height: calc(${size.height}px / ${pageConfig.scaling}); transform-origin: 0 0; transform: scale(${pageConfig.scaling}); overflow: hidden; From 454df2eb6b049d7177602ad2b9b31e9a76c29bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Victor?= Date: Tue, 10 Aug 2021 10:07:51 +0200 Subject: [PATCH 05/74] Support for letting HA keep track of Kindle battery level Inspired by https://github.com/sibbl/hass-kindle-screensaver#optional-battery-level-entity --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ config.js | 1 + index.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 88 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 280174d..256b1b7 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Home Assistant related stuff: | `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | | `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/maykar/kiosk-mode) project) | | `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | +| `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | no | Webhook definied in HA which receives `level`: *percentage* as JSON and query parameters | `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | | `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | | `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | @@ -45,6 +46,44 @@ You can access these additional images by making GET Requests `http://localhost: You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. +### Webhook example + +The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: + +1. See [here](https://github.com/sibbl/hass-kindle-screensaver#optional-battery-level-entity) or below for a patch needed to make the Kindle Online Screensaver plugin provide the battery level. +1. Create a new `input_number` entity in Home Assistant, e.g. `input_number.kindle_battery_level`. You can use the "Helpers" on the HA Configuration page for this. +1. Add an automation to handle the webhook call; see below for an example. The name of the webhook could be an unpredictable one, e.g. the output of `openssl rand -hex 16`, or a readable, predictable (and thereby hackable) one, e.g. `set_kindle_battery_level`. See [the sparse docs](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger). +1. Define the environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. + +#### Webhook automation +``` +automation: + trigger: + - platform: webhook + webhook_id: set_kindle_battery_level + action: + - service: input_number.set_value + target: + entity_id: input_number.kindle_battery_level + data: + value: "{{ trigger.query.level }}" +``` + +#### Patch for Kinde Online Screensaver + +Modify the following lines in the Kindle Online Screensaver plugin's `bin/update.sh` (absolute path on device should be `/mnt/us/extensions/onlinescreensaver/bin/update.sh`): + +```diff +... +if [ 1 -eq $CONNECTED ]; then +- if wget -q $IMAGE_URI -O $TMPFILE; then ++ batt=`powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` ++ if wget -q "$IMAGE_URI?battery=$batt" -O $TMPFILE; then + mv $TMPFILE $SCREENSAVERFILE + logger "Screen saver image updated" +... +``` + ### Advanced configuration Some advanced variables for local usage which shouldn't be necessary when using Docker: diff --git a/config.js b/config.js index 322d8cc..93f5c53 100644 --- a/config.js +++ b/config.js @@ -35,6 +35,7 @@ function getPagesConfig() { module.exports = { baseUrl: process.env.HA_BASE_URL, accessToken: process.env.HA_ACCESS_TOKEN, + batteryWebHook: process.env.HA_BATTERY_WEBHOOK, cronJob: process.env.CRON_JOB || "* * * * *", useImageMagick: process.env.USE_IMAGE_MAGICK === "true", pages: getPagesConfig(), diff --git a/index.js b/index.js index 04b1df1..fe12f8c 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,9 @@ const puppeteer = require("puppeteer"); const { CronJob } = require("cron"); const gm = require("gm"); +// Record of current battery level +var battery = 0; + (async () => { if (config.pages.length === 0) { return console.error("Please check your configuration"); @@ -69,7 +72,13 @@ const gm = require("gm"); } const httpServer = http.createServer(async (request, response) => { - const pageNumberStr = request.url; + // Parse the request + const url = new URL(request.url, `http://${request.headers.host}`); + // Check the page number + const pageNumberStr = url.pathname; + // and get the battery level, if any + // (see https://github.com/sibbl/hass-kindle-screensaver for patch to generate it on Kindle) + const bttr = url.searchParams.get('battery'); const pageNumber = pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); if ( @@ -77,6 +86,7 @@ const gm = require("gm"); pageNumber.length > config.pages.length || pageNumber < 1 ) { + console.log("Invalid request: "+request.url); console.error("Invalid page requested: " + pageNumber); response.writeHead(400); response.end("Invalid page"); @@ -84,10 +94,21 @@ const gm = require("gm"); } try { const data = await fs.readFile(config.pages[pageNumber - 1].outputPath); - console.log(`Image ${pageNumber} was accessed`); + // Log when the page was accessed + const n = new Date() + console.log(`${n.toISOString()}: Image ${pageNumber} was accessed`); response.setHeader("Content-Length", Buffer.byteLength(data)); response.writeHead(200, { "Content-Type": "image/png" }); response.end(data); + if (!isNaN(bttr)) { + if (bttr != battery) { + console.log("New battery level: "+bttr); + } + battery = bttr; + } else { + console.log("No battery level found"); + battery = 0; + } } catch (e) { console.error(e); response.writeHead(404); @@ -110,10 +131,10 @@ async function renderAndConvertAsync(browser) { const tempPath = outputPath + ".temp"; - console.log(`Rendering ${url} to image...`); +// console.log(`Rendering ${url} to image...`); await renderUrlToImageAsync(browser, pageConfig, url, tempPath); - console.log(`Converting rendered screenshot of ${url} to grayscale png...`); +// console.log(`Converting rendered screenshot of ${url} to grayscale png...`); await convertImageToKindleCompatiblePngAsync( pageConfig, tempPath, @@ -121,10 +142,32 @@ async function renderAndConvertAsync(browser) { ); fs.unlink(tempPath); - console.log(`Finished ${url}`); +// console.log(`Finished ${url}`); + if (battery != 0 && config.batteryWebHook) { + await updateBatteryLevelinHA(battery); + } } } +async function updateBatteryLevelinHA(battery) { + // Let Home Assistant keep track of the battery level + const lv = JSON.stringify({'level': `${battery}`}); + const ops = { method: 'POST', + headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(lv) }}; + const burl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${battery}`; + + const breq = http.request(burl, ops, (res) => { + if (res.statusCode != 200) { + console.error(`Update ${burl} status ${res.statusCode}: ${res.statusMessage}`); + } + }); + breq.on('error', (e) => { + console.error(`Update ${burl} error: ${e.message}`); + }); + breq.write(lv); + breq.end(); +} + async function renderUrlToImageAsync(browser, pageConfig, url, path) { let page; try { From 7c07c4f52790242a8c3294a529711bdefbbae29b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Victor?= Date: Thu, 30 Sep 2021 15:47:35 +0200 Subject: [PATCH 06/74] Add support for charging state --- README.md | 20 ++++++++++++++++---- index.js | 22 ++++++++++++++++------ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 256b1b7..48d43e3 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,13 @@ You may also simply use the `docker-compose.yml` file inside this repository, co The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: -1. See [here](https://github.com/sibbl/hass-kindle-screensaver#optional-battery-level-entity) or below for a patch needed to make the Kindle Online Screensaver plugin provide the battery level. -1. Create a new `input_number` entity in Home Assistant, e.g. `input_number.kindle_battery_level`. You can use the "Helpers" on the HA Configuration page for this. +1. See below (inspired by [this](https://github.com/sibbl/hass-kindle-screensaver#optional-battery-level-entity)) for a patch needed to make the Kindle Online Screensaver plugin provide the battery level. +1. Create a new `input_number` entity in Home Assistant, e.g. `input_number.kindle_battery_level`, and a new `input_boolean` entity, e.g. `input_boolean.kindle_battery_charging`. You can use the "Helpers" on the HA Configuration page for this. 1. Add an automation to handle the webhook call; see below for an example. The name of the webhook could be an unpredictable one, e.g. the output of `openssl rand -hex 16`, or a readable, predictable (and thereby hackable) one, e.g. `set_kindle_battery_level`. See [the sparse docs](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger). 1. Define the environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. #### Webhook automation +Use the name of the webhook and of the `input_number` and `input_boolean` entities you defined above, ``` automation: trigger: @@ -67,6 +68,16 @@ automation: entity_id: input_number.kindle_battery_level data: value: "{{ trigger.query.level }}" + - service_template: >- + {% if trigger.query.charging == "1" %} + input_boolean.turn_on + {% elif trigger.query.charging == "0" %} + input_boolean.turn_off + {% else %} + input_boolean.fronk_{{ trigger.query.charging }} + {% endif %} + target: + entity_id: input_number.kindle_battery_charging ``` #### Patch for Kinde Online Screensaver @@ -77,8 +88,9 @@ Modify the following lines in the Kindle Online Screensaver plugin's `bin/update ... if [ 1 -eq $CONNECTED ]; then - if wget -q $IMAGE_URI -O $TMPFILE; then -+ batt=`powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` -+ if wget -q "$IMAGE_URI?battery=$batt" -O $TMPFILE; then ++ batt=`/usr/bin/powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` ++ charg=`/usr/bin/powerd_test -s | awk -F: '/Charging/ {print substr($2,2,length($2))}'` ++ if wget -q "$IMAGE_URI?battery=$batt&charging=$charg" -O $TMPFILE; then mv $TMPFILE $SCREENSAVERFILE logger "Screen saver image updated" ... diff --git a/index.js b/index.js index fe12f8c..268caee 100644 --- a/index.js +++ b/index.js @@ -7,8 +7,9 @@ const puppeteer = require("puppeteer"); const { CronJob } = require("cron"); const gm = require("gm"); -// Record of current battery level +// Record of current battery level and charging state var battery = 0; +var charging = 0; (async () => { if (config.pages.length === 0) { @@ -79,6 +80,7 @@ var battery = 0; // and get the battery level, if any // (see https://github.com/sibbl/hass-kindle-screensaver for patch to generate it on Kindle) const bttr = url.searchParams.get('battery'); + const chrg = url.searchParams.get('charging'); const pageNumber = pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); if ( @@ -102,13 +104,21 @@ var battery = 0; response.end(data); if (!isNaN(bttr)) { if (bttr != battery) { - console.log("New battery level: "+bttr); + console.log("New battery level: "+bttr+" (charging: "+chrg+")"); } battery = bttr; } else { console.log("No battery level found"); battery = 0; } + if (chrg != null) { + // translate to binary + if (chrg == "Yes") { + charging = 1; + } else if (chrg == "No") { + charging = 0; + } + } } catch (e) { console.error(e); response.writeHead(404); @@ -144,17 +154,17 @@ async function renderAndConvertAsync(browser) { fs.unlink(tempPath); // console.log(`Finished ${url}`); if (battery != 0 && config.batteryWebHook) { - await updateBatteryLevelinHA(battery); + await updateBatteryLevelinHA(battery,charging); } } } -async function updateBatteryLevelinHA(battery) { +async function updateBatteryLevelinHA(battery,chrging) { // Let Home Assistant keep track of the battery level - const lv = JSON.stringify({'level': `${battery}`}); + const lv = JSON.stringify({'level': `${battery}`, 'charging': `${chrging}`}); const ops = { method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(lv) }}; - const burl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${battery}`; + const burl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${battery}&charging=${chrging}`; const breq = http.request(burl, ops, (res) => { if (res.statusCode != 200) { From 630be797ad89692fb9cc1876527441ececcf0bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Victor?= Date: Thu, 30 Sep 2021 15:50:22 +0200 Subject: [PATCH 07/74] Untabify --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 48d43e3..339e530 100644 --- a/README.md +++ b/README.md @@ -60,15 +60,15 @@ Use the name of the webhook and of the `input_number` and `input_boolean` entiti ``` automation: trigger: - - platform: webhook - webhook_id: set_kindle_battery_level + - platform: webhook + webhook_id: set_kindle_battery_level action: - - service: input_number.set_value - target: - entity_id: input_number.kindle_battery_level - data: - value: "{{ trigger.query.level }}" - - service_template: >- + - service: input_number.set_value + target: + entity_id: input_number.kindle_battery_level + data: + value: "{{ trigger.query.level }}" + - service_template: >- {% if trigger.query.charging == "1" %} input_boolean.turn_on {% elif trigger.query.charging == "0" %} @@ -76,8 +76,8 @@ automation: {% else %} input_boolean.fronk_{{ trigger.query.charging }} {% endif %} - target: - entity_id: input_number.kindle_battery_charging + target: + entity_id: input_number.kindle_battery_charging ``` #### Patch for Kinde Online Screensaver From da983d801b16c2972df7f6d7abc04ca0c212d6d7 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 14:17:57 +0100 Subject: [PATCH 08/74] Bump Alpine docker version to use Node.js 16 LTS --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0dc7297..ac02178 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12-alpine +FROM node:16-alpine WORKDIR /app From f2fe8f8aa884b406a07c309786980490fb58b9d2 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 14:50:45 +0100 Subject: [PATCH 09/74] Update dependencies --- package-lock.json | 166 +++++++++++++++++++++++++--------------------- package.json | 4 +- 2 files changed, 91 insertions(+), 79 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93a9f5d..fb43a8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,28 +1,31 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.0", + "version": "1.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@types/node": { - "version": "14.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", - "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", + "version": "16.11.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.7.tgz", + "integrity": "sha512-QB5D2sqfSjCmTuWcBWyJ+/44bcjO7VbjSbOE0ucoVbAsSNQc4Lt6QkgkVXkTDwkL4z/beecZNDvVX15D4P8Jbw==", "optional": true }, "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz", + "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==", "optional": true, "requires": { "@types/node": "*" } }, "agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==" + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } }, "array-parallel": { "version": "0.1.3", @@ -34,15 +37,10 @@ "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", "integrity": "sha1-3103v8XC7wdV4qpPkv6ufUtaly8=" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "base64-js": { "version": "1.5.1", @@ -50,9 +48,9 @@ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, "bl": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", - "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "requires": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -110,17 +108,17 @@ } }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "requires": { "ms": "2.1.2" } }, "devtools-protocol": { - "version": "0.0.818844", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.818844.tgz", - "integrity": "sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg==" + "version": "0.0.901419", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz", + "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ==" }, "end-of-stream": { "version": "1.4.4", @@ -164,14 +162,13 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "fs-extra": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", - "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", "requires": { - "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", - "universalify": "^1.0.0" + "universalify": "^2.0.0" } }, "fs.realpath": { @@ -188,9 +185,9 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -222,16 +219,16 @@ } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" }, "https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "requires": { - "agent-base": "5", + "agent-base": "6", "debug": "4" } }, @@ -266,13 +263,6 @@ "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" - }, - "dependencies": { - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } } }, "locate-path": { @@ -324,9 +314,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "requires": { + "whatwg-url": "^5.0.0" + } }, "once": { "version": "1.4.0", @@ -405,22 +398,22 @@ } }, "puppeteer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-5.5.0.tgz", - "integrity": "sha512-OM8ZvTXAhfgFA7wBIIGlPQzvyEETzDjeRa4mZRCRHxYL+GNH5WAuYUQdja3rpWZvkX/JKqmuVgbsxDNsDFjMEg==", - "requires": { - "debug": "^4.1.0", - "devtools-protocol": "0.0.818844", - "extract-zip": "^2.0.0", - "https-proxy-agent": "^4.0.0", - "node-fetch": "^2.6.1", - "pkg-dir": "^4.2.0", - "progress": "^2.0.1", - "proxy-from-env": "^1.0.0", - "rimraf": "^3.0.2", - "tar-fs": "^2.0.0", - "unbzip2-stream": "^1.3.3", - "ws": "^7.2.3" + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-11.0.0.tgz", + "integrity": "sha512-6rPFqN1ABjn4shgOICGDBITTRV09EjXVqhDERBDKwCLz0UyBxeeBH6Ay0vQUJ84VACmlxwzOIzVEJXThcF3aNg==", + "requires": { + "debug": "4.3.2", + "devtools-protocol": "0.0.901419", + "extract-zip": "2.0.1", + "https-proxy-agent": "5.0.0", + "node-fetch": "2.6.5", + "pkg-dir": "4.2.0", + "progress": "2.0.3", + "proxy-from-env": "1.1.0", + "rimraf": "3.0.2", + "tar-fs": "2.1.1", + "unbzip2-stream": "1.4.3", + "ws": "8.2.3" } }, "readable-stream": { @@ -466,9 +459,9 @@ } }, "tar-stream": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", - "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "requires": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -482,6 +475,11 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, "unbzip2-stream": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", @@ -492,15 +490,29 @@ } }, "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -515,9 +527,9 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==" + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==" }, "yallist": { "version": "2.1.2", diff --git a/package.json b/package.json index 21f3221..b8c604a 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "license": "MIT", "dependencies": { "cron": "^1.8.2", - "fs-extra": "^9.0.1", + "fs-extra": "^10.0.0", "gm": "^1.23.1", - "puppeteer": "^5.5.0" + "puppeteer": "^11.0.0" } } From ff0b23c98e3cf48da57f2288e43d93ca209b2be3 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 14:51:00 +0100 Subject: [PATCH 10/74] Wait for "home-assistant" selector, add Last-Modified header, some cleanup --- index.js | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 04b1df1..781a2a6 100644 --- a/index.js +++ b/index.js @@ -31,7 +31,7 @@ const gm = require("gm"); headless: config.debug !== true, }); - console.log("Adding authentication entry to browser's local storage..."); + console.log(`Visiting '${config.baseUrl}' to login...`); let page = await browser.newPage(); await page.goto(config.baseUrl, { timeout: config.renderingTimeout, @@ -43,6 +43,7 @@ const gm = require("gm"); token_type: "Bearer", }; + console.log("Adding authentication entry to browser's local storage..."); await page.evaluate( (hassTokens, selectedLanguage) => { localStorage.setItem("hassTokens", hassTokens); @@ -74,19 +75,27 @@ const gm = require("gm"); pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); if ( isFinite(pageNumber) === false || - pageNumber.length > config.pages.length || + pageNumber > config.pages.length || pageNumber < 1 ) { - console.error("Invalid page requested: " + pageNumber); + console.error(`Invalid request to ${pageNumberStr}`); response.writeHead(400); - response.end("Invalid page"); + response.end("Invalid request"); return; } try { - const data = await fs.readFile(config.pages[pageNumber - 1].outputPath); console.log(`Image ${pageNumber} was accessed`); - response.setHeader("Content-Length", Buffer.byteLength(data)); - response.writeHead(200, { "Content-Type": "image/png" }); + + const data = await fs.readFile(config.pages[pageNumber - 1].outputPath); + const stat = await fs.stat(config.pages[pageNumber - 1].outputPath); + + const lastModifiedTime = new Date(stat.mtime).toUTCString(); + + response.writeHead(200, { + "Content-Type": "image/png", + "Content-Length": Buffer.byteLength(data), + "Last-Modified": lastModifiedTime, + }); response.end(data); } catch (e) { console.error(e); @@ -149,11 +158,17 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { } await page.setViewport(size); + const startTime = new Date().valueOf(); await page.goto(url, { waitUntil: ["domcontentloaded", "load", "networkidle0"], timeout: config.renderingTimeout, }); + const navigateTimespan = new Date().valueOf() - startTime; + await page.waitForSelector("home-assistant", { + timeout: Math.max(config.renderingTimeout - navigateTimespan, 1000), + }); + await page.addStyleTag({ content: ` body { @@ -166,7 +181,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { }); if (pageConfig.renderingDelay > 0) { - await delay(pageConfig.renderingDelay); + await page.waitForTimeout(pageConfig.renderingDelay); } await page.screenshot({ path, @@ -208,8 +223,3 @@ function convertImageToKindleCompatiblePngAsync( }); }); } -function delay(time) { - return new Promise((resolve) => { - setTimeout(resolve, time); - }); -} From 41c6b93043bff34ef4266a205c3b97e898b2d386 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 14:51:25 +0100 Subject: [PATCH 11/74] Update CI to use package.json version as git + docker tags --- .github/workflows/ci.yml | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5645fa7..54005f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,29 +2,27 @@ name: ci on: push: - branches: main + branches: + - main jobs: multi: runs-on: ubuntu-latest steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Set up QEMU + - name: Extract package version + run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 + - name: Login to Docker Hub + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Build and push + - name: Build and push to Docker uses: docker/build-push-action@v2 with: context: . @@ -32,4 +30,13 @@ jobs: platforms: linux/amd64,linux/arm/v7,linux/arm64 push: true tags: | + sibbl/hass-lovelace-kindle-screensaver:${{ env.PACKAGE_VERSION }}, sibbl/hass-lovelace-kindle-screensaver:latest + - name: Tag git commit + uses: pkgdeps/git-tag-action@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + github_repo: ${{ github.repository }} + version: ${{ env.PACKAGE_VERSION }} + git_commit_sha: ${{ github.sha }} + git_tag_prefix: "v" From b24379821fcde96473a78a4039a50e3db6ab8011 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 14:51:30 +0100 Subject: [PATCH 12/74] Bump to version 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b8c604a..18c971e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.0", + "version": "1.0.1", "description": "", "main": "index.js", "scripts": { From e5cfd7b6bcb130b21fcedc5d9e031cb4b078e6ab Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 9 Nov 2021 15:01:44 +0100 Subject: [PATCH 13/74] Specify Alpine version 3.11 to get armv7 compatibility --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index ac02178..7b19ed5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine +FROM node:16-alpine3.11 WORKDIR /app From fda528dbcbb1d52f2cd905f0708a29f4ba2f7c05 Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 10 Nov 2021 12:09:03 -0800 Subject: [PATCH 14/74] only copy needed files to container --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7b19ed5..45d25b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ COPY package*.json ./ RUN npm ci -COPY . . +COPY *.js ./ EXPOSE 5000 From b45c1981ccfcf39c71de3fda565eea844f391db1 Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 10 Nov 2021 12:14:02 -0800 Subject: [PATCH 15/74] add support for changing the color mode --- README.md | 1 + config.js | 1 + index.js | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 280174d..82c48be 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Home Assistant related stuff: | `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | | `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | | `GRAYSCALE_DEPTH` | `8` | no | yes | Ggrayscale bit depth your kindle supports | +| `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. diff --git a/config.js b/config.js index 322d8cc..8fcefe7 100644 --- a/config.js +++ b/config.js @@ -25,6 +25,7 @@ function getPagesConfig() { width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, }, grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, + colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, scaling: getEnvironmentVariable("SCALING", suffix) || 1, }); diff --git a/index.js b/index.js index 781a2a6..10f1901 100644 --- a/index.js +++ b/index.js @@ -212,7 +212,7 @@ function convertImageToKindleCompatiblePngAsync( imageMagick: config.useImageMagick === true, }) .rotate("white", pageConfig.rotation) - .type("GrayScale") + .type(pageConfig.colorMode) .bitdepth(pageConfig.grayscaleDepth) .write(outputPath, (err) => { if (err) { From dbf151325f054321301f48cbc1dbbc74e431c158 Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 10 Nov 2021 12:15:20 -0800 Subject: [PATCH 16/74] render image on startup before cron --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index 781a2a6..1e2b103 100644 --- a/index.js +++ b/index.js @@ -61,6 +61,8 @@ const gm = require("gm"); ); renderAndConvertAsync(browser); } else { + console.log("Starting first render..."); + renderAndConvertAsync(browser); console.log("Starting rendering cronjob..."); new CronJob({ cronTime: config.cronJob, From 9f3c68215838bcc2c4c164d4c6c836723f6b9d3c Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 10 Nov 2021 12:20:54 -0800 Subject: [PATCH 17/74] update dockerignore --- .dockerignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 1691176..1a3442a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,11 @@ node_modules/ +.github/ +.git/ .vscode/ assets/ config.*.js docker-compose.*.yml -output/ \ No newline at end of file +docker-compose.yml +output/ +LICENSE +*.md \ No newline at end of file From 96c413156dd41c74ac0d37e11f08b54093a5bed1 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 22 Nov 2021 09:54:08 +0100 Subject: [PATCH 18/74] Bump to version 1.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 18c971e..92a5762 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.1", + "version": "1.0.2", "description": "", "main": "index.js", "scripts": { From b1bb6bc0ec150fe309d3c478f9f7e08c865597f8 Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 1 Dec 2021 10:26:46 -0800 Subject: [PATCH 19/74] dither config --- README.md | 3 ++- config.js | 1 + index.js | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 82c48be..68c038d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,8 @@ Home Assistant related stuff: | `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | | `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | | `GRAYSCALE_DEPTH` | `8` | no | yes | Ggrayscale bit depth your kindle supports | -| `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | +| `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | +| `DITHER` | `false` | no | yes | Apply a dither to the images. | **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. diff --git a/config.js b/config.js index 8fcefe7..22cafef 100644 --- a/config.js +++ b/config.js @@ -25,6 +25,7 @@ function getPagesConfig() { width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, }, grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, + dither: getEnvironmentVariable("DITHER", suffix) || false, colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, scaling: getEnvironmentVariable("SCALING", suffix) || 1, diff --git a/index.js b/index.js index 392e870..270023b 100644 --- a/index.js +++ b/index.js @@ -213,6 +213,7 @@ function convertImageToKindleCompatiblePngAsync( .options({ imageMagick: config.useImageMagick === true, }) + .dither(ageConfig.dither) .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) .bitdepth(pageConfig.grayscaleDepth) From de16187b3e7f4ce5bc59ec023a7582db97b752db Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 1 Dec 2021 10:27:45 -0800 Subject: [PATCH 20/74] set quality to 100 by default --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 392e870..370374d 100644 --- a/index.js +++ b/index.js @@ -216,6 +216,7 @@ function convertImageToKindleCompatiblePngAsync( .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) .bitdepth(pageConfig.grayscaleDepth) + .quality(100) .write(outputPath, (err) => { if (err) { reject(err); From 26da1bd14556e58059b90e48de6b220ebb097410 Mon Sep 17 00:00:00 2001 From: Ian Foster Date: Wed, 1 Dec 2021 10:35:58 -0800 Subject: [PATCH 21/74] mend --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 270023b..699bd1c 100644 --- a/index.js +++ b/index.js @@ -213,7 +213,7 @@ function convertImageToKindleCompatiblePngAsync( .options({ imageMagick: config.useImageMagick === true, }) - .dither(ageConfig.dither) + .dither(pageConfig.dither) .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) .bitdepth(pageConfig.grayscaleDepth) From e7e71626068cd65086a20af71b8fed849e126512 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 13 Dec 2021 13:37:22 +0100 Subject: [PATCH 22/74] Bump version to 1.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 92a5762..dd585a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.2", + "version": "1.0.3", "description": "", "main": "index.js", "scripts": { From 46484e67bba24e4fc1b0c5833e1a51ddc50986a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Victor?= Date: Fri, 17 Dec 2021 13:26:05 +0100 Subject: [PATCH 23/74] Cleanup based on feedback from @sibbl --- index.js | 63 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/index.js b/index.js index 7506a79..a207218 100644 --- a/index.js +++ b/index.js @@ -8,8 +8,7 @@ const { CronJob } = require("cron"); const gm = require("gm"); // Record of current battery level and charging state -var battery = 0; -var charging = 0; +const batteryStore = { level: 0, charging: 0 }; (async () => { if (config.pages.length === 0) { @@ -82,8 +81,8 @@ var charging = 0; const pageNumberStr = url.pathname; // and get the battery level, if any // (see https://github.com/sibbl/hass-kindle-screensaver for patch to generate it on Kindle) - const bttr = url.searchParams.get('battery'); - const chrg = url.searchParams.get('charging'); + const level = parseInt(url.searchParams.get('battery'), 10); + const charging = url.searchParams.get('charging'); const pageNumber = pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); if ( @@ -91,8 +90,7 @@ var charging = 0; pageNumber > config.pages.length || pageNumber < 1 ) { - console.log("Invalid request: "+request.url); - console.error("Invalid page requested: " + pageNumber); + console.log("Invalid request: " + request.url + " page " + pageNumber); response.writeHead(400); response.end("Invalid request"); return; @@ -113,21 +111,21 @@ var charging = 0; "Last-Modified": lastModifiedTime, }); response.end(data); - if (!isNaN(bttr)) { - if (bttr != battery) { - console.log("New battery level: "+bttr+" (charging: "+chrg+")"); + if (!isNaN(level) && level >= 0) { + if (level !== batteryStore.level) { + console.log("New battery level: " + level + " (charging: " + charging + ")"); } - battery = bttr; + batteryStore.level = level; } else { - console.log("No battery level found"); - battery = 0; + console.log("No battery level found: " + level); + batteryStore.level = 0; } - if (chrg != null) { + if (charging !== null) { // translate to binary - if (chrg == "Yes") { - charging = 1; - } else if (chrg == "No") { - charging = 0; + if (charging == "Yes") { + batteryStore.charging = 1; + } else if (charging == "No") { + batteryStore.charging = 0; } } } catch (e) { @@ -164,29 +162,32 @@ async function renderAndConvertAsync(browser) { fs.unlink(tempPath); // console.log(`Finished ${url}`); - if (battery != 0 && config.batteryWebHook) { - await updateBatteryLevelinHA(battery,charging); + if (batteryStore.level != 0 && config.batteryWebHook) { + updateBatteryLevelinHA(); } } } -async function updateBatteryLevelinHA(battery,chrging) { +function updateBatteryLevelinHA() { // Let Home Assistant keep track of the battery level - const lv = JSON.stringify({'level': `${battery}`, 'charging': `${chrging}`}); - const ops = { method: 'POST', - headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(lv) }}; - const burl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${battery}&charging=${chrging}`; - - const breq = http.request(burl, ops, (res) => { + const batterystatus = JSON.stringify({'level': `${batteryStore.level}`, + 'charging': `${batteryStore.charging}`}); + const options = { method: 'POST', + headers: { 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(batterystatus) }}; + const baseurl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${batteryStore.level}&charging=${batteryStore.charging}`; + const url = new URL(baseurl); + const prot = url.protocol == 'https' ? https : http; + const updaterequest = prot.request(baseurl, options, (res) => { if (res.statusCode != 200) { - console.error(`Update ${burl} status ${res.statusCode}: ${res.statusMessage}`); + console.error(`Update ${baseurl} status ${res.statusCode}: ${res.statusMessage}`); } }); - breq.on('error', (e) => { - console.error(`Update ${burl} error: ${e.message}`); + updaterequest.on('error', (e) => { + console.error(`Update ${baseurl} error: ${e.message}`); }); - breq.write(lv); - breq.end(); + updaterequest.write(batterystatus); + updaterequest.end(); } async function renderUrlToImageAsync(browser, pageConfig, url, path) { From 771c7d04398613253ce9f556a597d597827b7123 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 18:16:50 +0100 Subject: [PATCH 24/74] Add multiple device support for battery webhook and unify naming, readd logging --- README.md | 6 +- config.js | 2 +- index.js | 165 ++++++++++++++++++++++++++++++++---------------------- 3 files changed, 103 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index 83eaa79..cb329f3 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,9 @@ Modify the following lines in the Kindle Online Screensaver plugin's `bin/update ... if [ 1 -eq $CONNECTED ]; then - if wget -q $IMAGE_URI -O $TMPFILE; then -+ batt=`/usr/bin/powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` -+ charg=`/usr/bin/powerd_test -s | awk -F: '/Charging/ {print substr($2,2,length($2))}'` -+ if wget -q "$IMAGE_URI?battery=$batt&charging=$charg" -O $TMPFILE; then ++ batteryLevel=`/usr/bin/powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` ++ isCharging=`/usr/bin/powerd_test -s | awk -F: '/Charging/ {print substr($2,2,length($2))}'` ++ if wget -q "$IMAGE_URI?batteryLevel=$batt&isCharging=$charg" -O $TMPFILE; then mv $TMPFILE $SCREENSAVERFILE logger "Screen saver image updated" ... diff --git a/config.js b/config.js index abd57bc..64306e4 100644 --- a/config.js +++ b/config.js @@ -29,6 +29,7 @@ function getPagesConfig() { colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, scaling: getEnvironmentVariable("SCALING", suffix) || 1, + batteryWebHook: getEnvironmentVariable("HA_BATTERY_WEBHOOK", suffix) || null, }); } return pages; @@ -37,7 +38,6 @@ function getPagesConfig() { module.exports = { baseUrl: process.env.HA_BASE_URL, accessToken: process.env.HA_ACCESS_TOKEN, - batteryWebHook: process.env.HA_BATTERY_WEBHOOK, cronJob: process.env.CRON_JOB || "* * * * *", useImageMagick: process.env.USE_IMAGE_MAGICK === "true", pages: getPagesConfig(), diff --git a/index.js b/index.js index 566f6b9..161d69e 100644 --- a/index.js +++ b/index.js @@ -1,14 +1,15 @@ const config = require("./config"); const path = require("path"); const http = require("http"); +const https = require("https"); const { promises: fs } = require("fs"); const fsExtra = require("fs-extra"); const puppeteer = require("puppeteer"); const { CronJob } = require("cron"); const gm = require("gm"); -// Record of current battery level and charging state -const batteryStore = { level: 0, charging: 0 }; +// keep state of current battery level and whether the device is charging +const batteryStore = {}; (async () => { if (config.pages.length === 0) { @@ -29,21 +30,21 @@ const batteryStore = { level: 0, charging: 0 }; "--disable-dev-shm-usage", "--no-sandbox", `--lang=${config.language}`, - config.ignoreCertificateErrors && "--ignore-certificate-errors", + config.ignoreCertificateErrors && "--ignore-certificate-errors" ].filter((x) => x), - headless: config.debug !== true, + headless: config.debug !== true }); console.log(`Visiting '${config.baseUrl}' to login...`); let page = await browser.newPage(); await page.goto(config.baseUrl, { - timeout: config.renderingTimeout, + timeout: config.renderingTimeout }); const hassTokens = { hassUrl: config.baseUrl, access_token: config.accessToken, - token_type: "Bearer", + token_type: "Bearer" }; console.log("Adding authentication entry to browser's local storage..."); @@ -70,7 +71,7 @@ const batteryStore = { level: 0, charging: 0 }; new CronJob({ cronTime: config.cronJob, onTick: () => renderAndConvertAsync(browser), - start: true, + start: true }); } @@ -80,9 +81,9 @@ const batteryStore = { level: 0, charging: 0 }; // Check the page number const pageNumberStr = url.pathname; // and get the battery level, if any - // (see https://github.com/sibbl/hass-kindle-screensaver for patch to generate it on Kindle) - const level = parseInt(url.searchParams.get('battery'), 10); - const charging = url.searchParams.get('charging'); + // (see https://github.com/sibbl/hass-lovelace-kindle-screensaver/README.md for patch to generate it on Kindle) + const batteryLevel = parseInt(url.searchParams.get("batteryLevel")); + const isCharging = url.searchParams.get("isCharging"); const pageNumber = pageNumberStr === "/" ? 1 : parseInt(pageNumberStr.substr(1)); if ( @@ -90,42 +91,55 @@ const batteryStore = { level: 0, charging: 0 }; pageNumber > config.pages.length || pageNumber < 1 ) { - console.log("Invalid request: " + request.url + " page " + pageNumber); + console.log(`Invalid request: ${request.url} for page ${pageNumber}`); response.writeHead(400); response.end("Invalid request"); return; } try { // Log when the page was accessed - const n = new Date() + const n = new Date(); console.log(`${n.toISOString()}: Image ${pageNumber} was accessed`); - const data = await fs.readFile(config.pages[pageNumber - 1].outputPath); - const stat = await fs.stat(config.pages[pageNumber - 1].outputPath); + const pageIndex = pageNumber - 1; + const configPage = config.pages[pageIndex]; + + const data = await fs.readFile(configPage.outputPath); + const stat = await fs.stat(configPage.outputPath); const lastModifiedTime = new Date(stat.mtime).toUTCString(); response.writeHead(200, { "Content-Type": "image/png", "Content-Length": Buffer.byteLength(data), - "Last-Modified": lastModifiedTime, + "Last-Modified": lastModifiedTime }); response.end(data); - if (!isNaN(level) && level >= 0) { - if (level !== batteryStore.level) { - console.log("New battery level: " + level + " (charging: " + charging + ")"); - } - batteryStore.level = level; - } else { - console.log("No battery level found: " + level); - batteryStore.level = 0; + + let pageBatteryStore = batteryStore[pageIndex]; + if (!pageBatteryStore) { + pageBatteryStore = batteryStore[pageIndex] = { + batteryLevel: null, + isCharging: false + }; } - if (charging !== null) { - // translate to binary - if (charging == "Yes") { - batteryStore.charging = 1; - } else if (charging == "No") { - batteryStore.charging = 0; + if (!isNaN(batteryLevel) && batteryLevel >= 0) { + if (batteryLevel !== pageBatteryStore.batteryLevel) { + pageBatteryStore.batteryLevel = batteryLevel; + console.log( + `New battery level: ${batteryLevel} for page ${pageNumber}` + ); + } + + if (isCharging === "Yes" && pageBatteryStore.isCharging !== true) { + pageBatteryStore.isCharging = true; + console.log(`Battery started charging for page ${pageNumber}`); + } else if ( + isCharging === "No" && + pageBatteryStore.isCharging !== false + ) { + console.log(`Battery stopped charging for page ${pageNumber}`); + pageBatteryStore.isCharging = false; } } } catch (e) { @@ -142,7 +156,10 @@ const batteryStore = { level: 0, charging: 0 }; })(); async function renderAndConvertAsync(browser) { - for (const pageConfig of config.pages) { + for (let pageIndex = 0; pageIndex < config.pages.length; pageIndex++) { + const pageConfig = config.pages[pageIndex]; + const pageBatteryStore = batteryStore[pageIndex]; + const url = `${config.baseUrl}${pageConfig.screenShotUrl}`; const outputPath = pageConfig.outputPath; @@ -150,10 +167,10 @@ async function renderAndConvertAsync(browser) { const tempPath = outputPath + ".temp"; -// console.log(`Rendering ${url} to image...`); + console.log(`Rendering ${url} to image...`); await renderUrlToImageAsync(browser, pageConfig, url, tempPath); -// console.log(`Converting rendered screenshot of ${url} to grayscale png...`); + console.log(`Converting rendered screenshot of ${url} to grayscale png...`); await convertImageToKindleCompatiblePngAsync( pageConfig, tempPath, @@ -161,33 +178,49 @@ async function renderAndConvertAsync(browser) { ); fs.unlink(tempPath); -// console.log(`Finished ${url}`); - if (batteryStore.level != 0 && config.batteryWebHook) { - updateBatteryLevelinHA(); - } + console.log(`Finished ${url}`); + + if ( + pageBatteryStore && + pageBatteryStore.batteryLevel !== null && + pageConfig.batteryWebHook + ) { + sendBatteryLevelToHomeAssistant( + pageIndex, + pageBatteryStore, + pageConfig.batteryWebHook + ); + } } } -function updateBatteryLevelinHA() { - // Let Home Assistant keep track of the battery level - const batterystatus = JSON.stringify({'level': `${batteryStore.level}`, - 'charging': `${batteryStore.charging}`}); - const options = { method: 'POST', - headers: { 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(batterystatus) }}; - const baseurl = `${config.baseUrl}/api/webhook/${config.batteryWebHook}?level=${batteryStore.level}&charging=${batteryStore.charging}`; - const url = new URL(baseurl); - const prot = url.protocol == 'https' ? https : http; - const updaterequest = prot.request(baseurl, options, (res) => { - if (res.statusCode != 200) { - console.error(`Update ${baseurl} status ${res.statusCode}: ${res.statusMessage}`); - } - }); - updaterequest.on('error', (e) => { - console.error(`Update ${baseurl} error: ${e.message}`); - }); - updaterequest.write(batterystatus); - updaterequest.end(); +function sendBatteryLevelToHomeAssistant( + pageIndex, + batteryStore, + batteryWebHook +) { + const batteryStatus = JSON.stringify(batteryStore); + const options = { + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": Buffer.byteLength(batteryStatus) + } + }; + const url = `${config.baseUrl}/api/webhook/${batteryWebHook}`; + const httpLib = url.toLowerCase().startsWith("https") ? https : http; + const req = httpLib.request(url, options, (res) => { + if (res.statusCode !== 200) { + console.error( + `Update device ${pageIndex} at ${url} status ${res.statusCode}: ${res.statusMessage}` + ); + } + }); + req.on("error", (e) => { + console.error(`Update ${pageIndex} at ${url} error: ${e.message}`); + }); + req.write(batteryStatus); + req.end(); } async function renderUrlToImageAsync(browser, pageConfig, url, path) { @@ -197,19 +230,19 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { await page.emulateMediaFeatures([ { name: "prefers-color-scheme", - value: "light", - }, + value: "light" + } ]); let size = { width: Number(pageConfig.renderingScreenSize.width), - height: Number(pageConfig.renderingScreenSize.height), + height: Number(pageConfig.renderingScreenSize.height) }; if (pageConfig.rotation % 180 > 0) { size = { width: size.height, - height: size.width, + height: size.width }; } @@ -217,12 +250,12 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { const startTime = new Date().valueOf(); await page.goto(url, { waitUntil: ["domcontentloaded", "load", "networkidle0"], - timeout: config.renderingTimeout, + timeout: config.renderingTimeout }); const navigateTimespan = new Date().valueOf() - startTime; await page.waitForSelector("home-assistant", { - timeout: Math.max(config.renderingTimeout - navigateTimespan, 1000), + timeout: Math.max(config.renderingTimeout - navigateTimespan, 1000) }); await page.addStyleTag({ @@ -233,7 +266,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { transform-origin: 0 0; transform: scale(${pageConfig.scaling}); overflow: hidden; - }`, + }` }); if (pageConfig.renderingDelay > 0) { @@ -245,8 +278,8 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { clip: { x: 0, y: 0, - ...size, - }, + ...size + } }); } catch (e) { console.error("Failed to render", e); @@ -265,7 +298,7 @@ function convertImageToKindleCompatiblePngAsync( return new Promise((resolve, reject) => { gm(inputPath) .options({ - imageMagick: config.useImageMagick === true, + imageMagick: config.useImageMagick === true }) .dither(pageConfig.dither) .rotate("white", pageConfig.rotation) From e3593e2358f2e2971483590e589984077baa1f28 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 18:17:03 +0100 Subject: [PATCH 25/74] Bump to v1.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd585a1..171437b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.3", + "version": "1.0.4", "description": "", "main": "index.js", "scripts": { From 202a2d6dfacdf39252322790967f00d225fe989c Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 18:18:01 +0100 Subject: [PATCH 26/74] Fix variable naming --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb329f3..c278493 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ if [ 1 -eq $CONNECTED ]; then - if wget -q $IMAGE_URI -O $TMPFILE; then + batteryLevel=`/usr/bin/powerd_test -s | awk -F: '/Battery Level/ {print substr($2, 0, length($2)-1) - 0}'` + isCharging=`/usr/bin/powerd_test -s | awk -F: '/Charging/ {print substr($2,2,length($2))}'` -+ if wget -q "$IMAGE_URI?batteryLevel=$batt&isCharging=$charg" -O $TMPFILE; then ++ if wget -q "$IMAGE_URI?batteryLevel=$batteryLevel&isCharging=$isCharging" -O $TMPFILE; then mv $TMPFILE $SCREENSAVERFILE logger "Screen saver image updated" ... From b2b117178843ac0d1999ece13ed1395a9f7a0e0e Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 18:38:26 +0100 Subject: [PATCH 27/74] Update documentation --- README.md | 22 ++++++++++++---------- index.js | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c278493..6b27f34 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Home Assistant related stuff: | `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | | `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/maykar/kiosk-mode) project) | | `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | -| `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | no | Webhook definied in HA which receives `level`: *percentage* as JSON and query parameters +| `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | yes | Webhook definied in HA which receives `batteryLevel` (number between 0-100) and `isCharging` (boolean) as JSON | | `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | | `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | | `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | @@ -52,13 +52,17 @@ You may also simply use the `docker-compose.yml` file inside this repository, co The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: -1. See below (inspired by [this](https://github.com/sibbl/hass-kindle-screensaver#optional-battery-level-entity)) for a patch needed to make the Kindle Online Screensaver plugin provide the battery level. -1. Create a new `input_number` entity in Home Assistant, e.g. `input_number.kindle_battery_level`, and a new `input_boolean` entity, e.g. `input_boolean.kindle_battery_charging`. You can use the "Helpers" on the HA Configuration page for this. +1. See below for a patch needed to make the Kindle Online Screensaver plugin send the battery level to this application. +1. Create two new helper entities in Home Assistant: + 1. a new `input_number` entity, e.g. `input_number.kindle_battery_level` + 1. a new `input_boolean` entity, e.g. `input_boolean.kindle_battery_charging` 1. Add an automation to handle the webhook call; see below for an example. The name of the webhook could be an unpredictable one, e.g. the output of `openssl rand -hex 16`, or a readable, predictable (and thereby hackable) one, e.g. `set_kindle_battery_level`. See [the sparse docs](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger). -1. Define the environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. +1. Define this application's environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. For multiple devices, `HA_BATTERY_WEBHOOK_2`, ... `HA_BATTERY_WEBHOOK_n` is supported as well. #### Webhook automation + Use the name of the webhook and of the `input_number` and `input_boolean` entities you defined above, + ``` automation: trigger: @@ -69,17 +73,15 @@ automation: target: entity_id: input_number.kindle_battery_level data: - value: "{{ trigger.query.level }}" + value: "{{ trigger.json.batteryLevel }}" - service_template: >- - {% if trigger.query.charging == "1" %} + {% if trigger.json.isCharging %} input_boolean.turn_on - {% elif trigger.query.charging == "0" %} - input_boolean.turn_off {% else %} - input_boolean.fronk_{{ trigger.query.charging }} + input_boolean.turn_off {% endif %} target: - entity_id: input_number.kindle_battery_charging + entity_id: input_boolean.kindle_battery_charging ``` #### Patch for Kinde Online Screensaver diff --git a/index.js b/index.js index 161d69e..b7c9e8d 100644 --- a/index.js +++ b/index.js @@ -123,7 +123,7 @@ const batteryStore = {}; isCharging: false }; } - if (!isNaN(batteryLevel) && batteryLevel >= 0) { + if (!isNaN(batteryLevel) && batteryLevel >= 0 && batteryLevel <= 100) { if (batteryLevel !== pageBatteryStore.batteryLevel) { pageBatteryStore.batteryLevel = batteryLevel; console.log( From 254454a5e0f32e4c7a046287cdaf6ca9f51d7fa2 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 19:00:41 +0100 Subject: [PATCH 28/74] Add battery sensor blueprint --- .dockerignore | 3 ++- README.md | 29 ++------------------------- battery_sensor_blueprint.yml | 38 ++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 battery_sensor_blueprint.yml diff --git a/.dockerignore b/.dockerignore index 1a3442a..84c37c9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,4 +8,5 @@ docker-compose.*.yml docker-compose.yml output/ LICENSE -*.md \ No newline at end of file +*.md +*.yml \ No newline at end of file diff --git a/README.md b/README.md index 6b27f34..7e11425 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ You can access these additional images by making GET Requests `http://localhost: You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. -### Webhook example +### How to set up the webhook The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: @@ -56,34 +56,9 @@ The webhook setting is to let HA keep track of the battery level of the Kindle, 1. Create two new helper entities in Home Assistant: 1. a new `input_number` entity, e.g. `input_number.kindle_battery_level` 1. a new `input_boolean` entity, e.g. `input_boolean.kindle_battery_charging` -1. Add an automation to handle the webhook call; see below for an example. The name of the webhook could be an unpredictable one, e.g. the output of `openssl rand -hex 16`, or a readable, predictable (and thereby hackable) one, e.g. `set_kindle_battery_level`. See [the sparse docs](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger). +1. Add an automation to set the values of these entities using a webhook: [![import blueprint](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgithub.com%2Fsibbl%2Fhass-lovelace-kindle-screensaver%2Fblob%2Fmain%2Fbattery_sensor_blueprint.yml) 1. Define this application's environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. For multiple devices, `HA_BATTERY_WEBHOOK_2`, ... `HA_BATTERY_WEBHOOK_n` is supported as well. -#### Webhook automation - -Use the name of the webhook and of the `input_number` and `input_boolean` entities you defined above, - -``` -automation: - trigger: - - platform: webhook - webhook_id: set_kindle_battery_level - action: - - service: input_number.set_value - target: - entity_id: input_number.kindle_battery_level - data: - value: "{{ trigger.json.batteryLevel }}" - - service_template: >- - {% if trigger.json.isCharging %} - input_boolean.turn_on - {% else %} - input_boolean.turn_off - {% endif %} - target: - entity_id: input_boolean.kindle_battery_charging -``` - #### Patch for Kinde Online Screensaver Modify the following lines in the Kindle Online Screensaver plugin's `bin/update.sh` (absolute path on device should be `/mnt/us/extensions/onlinescreensaver/bin/update.sh`): diff --git a/battery_sensor_blueprint.yml b/battery_sensor_blueprint.yml new file mode 100644 index 0000000..612b343 --- /dev/null +++ b/battery_sensor_blueprint.yml @@ -0,0 +1,38 @@ +blueprint: + name: Kindle Screensaver Battery Level + domain: automation + input: + webhook_id: + name: Webhook ID + description: Unique and secret ID of ID to use for webhook. It's recommended to run `openssl rand -hex 16` to generate something random. + default: set_kindle_battery_level + battery_level: + name: Entity to save battery level in + description: Please create a new helper entity first. + selector: + entity: + domain: input_number + battery_charging: + name: Entity to save battery charging state in + description: Please create a new helper entity first. + selector: + entity: + domain: input_boolean + +trigger: + - platform: webhook + webhook_id: !input webhook_id +action: + - service: input_number.set_value + target: + entity_id: !input battery_level + data: + value: "{{ trigger.json.batteryLevel }}" + - service_template: >- + {% if trigger.json.isCharging %} + input_boolean.turn_on + {% else %} + input_boolean.turn_off + {% endif %} + target: + entity_id: !input battery_charging \ No newline at end of file From d963ddf51e1c3ea23067e5834afc28e8f2436180 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 17 Dec 2021 19:02:48 +0100 Subject: [PATCH 29/74] Rename yml to yaml to avoid HA blueprint import having ".yml.yaml" filename... --- .dockerignore | 3 ++- README.md | 2 +- battery_sensor_blueprint.yml => battery_sensor_blueprint.yaml | 0 3 files changed, 3 insertions(+), 2 deletions(-) rename battery_sensor_blueprint.yml => battery_sensor_blueprint.yaml (100%) diff --git a/.dockerignore b/.dockerignore index 84c37c9..59e511a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,4 +9,5 @@ docker-compose.yml output/ LICENSE *.md -*.yml \ No newline at end of file +*.yml +*.yaml \ No newline at end of file diff --git a/README.md b/README.md index 7e11425..af51ba7 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ The webhook setting is to let HA keep track of the battery level of the Kindle, 1. Create two new helper entities in Home Assistant: 1. a new `input_number` entity, e.g. `input_number.kindle_battery_level` 1. a new `input_boolean` entity, e.g. `input_boolean.kindle_battery_charging` -1. Add an automation to set the values of these entities using a webhook: [![import blueprint](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgithub.com%2Fsibbl%2Fhass-lovelace-kindle-screensaver%2Fblob%2Fmain%2Fbattery_sensor_blueprint.yml) +1. Add an automation to set the values of these entities using a webhook: [![import blueprint](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgithub.com%2Fsibbl%2Fhass-lovelace-kindle-screensaver%2Fblob%2Fmain%2Fbattery_sensor_blueprint.yaml) 1. Define this application's environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. For multiple devices, `HA_BATTERY_WEBHOOK_2`, ... `HA_BATTERY_WEBHOOK_n` is supported as well. #### Patch for Kinde Online Screensaver diff --git a/battery_sensor_blueprint.yml b/battery_sensor_blueprint.yaml similarity index 100% rename from battery_sensor_blueprint.yml rename to battery_sensor_blueprint.yaml From 63b7a93c7e7c53afe8f3614e0fc007cc4ba8ee92 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 8 May 2022 20:05:57 +0200 Subject: [PATCH 30/74] Add "1" and "0" to expected battery isCharging values --- index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index b7c9e8d..bcbcd24 100644 --- a/index.js +++ b/index.js @@ -131,11 +131,13 @@ const batteryStore = {}; ); } - if (isCharging === "Yes" && pageBatteryStore.isCharging !== true) { + if ( + (isCharging === "Yes" || isCharging === "1") && + pageBatteryStore.isCharging !== true) { pageBatteryStore.isCharging = true; console.log(`Battery started charging for page ${pageNumber}`); } else if ( - isCharging === "No" && + (isCharging === "No" || isCharging === "0") && pageBatteryStore.isCharging !== false ) { console.log(`Battery stopped charging for page ${pageNumber}`); From 882d7c79141616310ad2e591d737b18f5642a574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Seppo=20R=C3=A4is=C3=A4nen?= Date: Sat, 14 May 2022 10:16:57 +0300 Subject: [PATCH 31/74] Add option to control image black and white levels. Some E-ink screens have low contrast, so changing levels can help with image visibility. --- config.js | 2 ++ index.js | 1 + 2 files changed, 3 insertions(+) diff --git a/config.js b/config.js index 64306e4..6a5001a 100644 --- a/config.js +++ b/config.js @@ -25,6 +25,8 @@ function getPagesConfig() { width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, }, grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, + blackLevel: getEnvironmentVariable("BLACK_LEVEL", suffix) || "0%", + whiteLevel: getEnvironmentVariable("WHITE_LEVEL", suffix) || "100%", dither: getEnvironmentVariable("DITHER", suffix) || false, colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, diff --git a/index.js b/index.js index b7c9e8d..e698dcf 100644 --- a/index.js +++ b/index.js @@ -303,6 +303,7 @@ function convertImageToKindleCompatiblePngAsync( .dither(pageConfig.dither) .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) + .level(pageConfig.blackLevel, pageConfig.whiteLevel) .bitdepth(pageConfig.grayscaleDepth) .quality(100) .write(outputPath, (err) => { From f9797d7cd6ddc43357598345781709f7a8113f9f Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sat, 18 Jun 2022 16:28:18 +0200 Subject: [PATCH 32/74] Add battery status diff for kindle 4 extension #35 --- README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af51ba7..c365507 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ The webhook setting is to let HA keep track of the battery level of the Kindle, 1. Add an automation to set the values of these entities using a webhook: [![import blueprint](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgithub.com%2Fsibbl%2Fhass-lovelace-kindle-screensaver%2Fblob%2Fmain%2Fbattery_sensor_blueprint.yaml) 1. Define this application's environment variable `HA_BATTERY_WEBHOOK` to the name of the webhook defined in the previous step. For multiple devices, `HA_BATTERY_WEBHOOK_2`, ... `HA_BATTERY_WEBHOOK_n` is supported as well. -#### Patch for Kinde Online Screensaver +#### Patch for [Kindle Online Screensaver extension](https://www.mobileread.com/forums/showthread.php?t=236104) Modify the following lines in the Kindle Online Screensaver plugin's `bin/update.sh` (absolute path on device should be `/mnt/us/extensions/onlinescreensaver/bin/update.sh`): @@ -75,6 +75,17 @@ if [ 1 -eq $CONNECTED ]; then ... ``` +#### Patch for [Hass Kindle 4 Lovelace plugin](https://github.com/sibbl/hass-lovelace-kindle-4/) + +Modify the following lines in the Kindle Online Screensaver plugin's [`script.sh`](https://github.com/sibbl/hass-lovelace-kindle-4/blob/main/extensions/homeassistant/script.sh#L133) (absolute path on device should be `/mnt/us/extensions/homeassistant/script.sh`): + +```diff +... +- DOWNLOADRESULT=$(wget -q "$IMAGE_URI" -O $TMPFILE) ++ DOWNLOADRESULT=$(wget -q "$IMAGE_URI?batteryLevel=$CHECKBATTERY&isCharging=$IS_CHARGING" -O $TMPFILE) +... +``` + ### Advanced configuration Some advanced variables for local usage which shouldn't be necessary when using Docker: From 145a702bae28c3fa69cf885a58da72224bdf65c1 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sat, 18 Jun 2022 16:30:50 +0200 Subject: [PATCH 33/74] Improve README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c365507..3cc36eb 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ The webhook setting is to let HA keep track of the battery level of the Kindle, #### Patch for [Kindle Online Screensaver extension](https://www.mobileread.com/forums/showthread.php?t=236104) -Modify the following lines in the Kindle Online Screensaver plugin's `bin/update.sh` (absolute path on device should be `/mnt/us/extensions/onlinescreensaver/bin/update.sh`): +Modify the following lines in the Kindle Online Screensaver extension's `bin/update.sh` (absolute path on device should be `/mnt/us/extensions/onlinescreensaver/bin/update.sh`): ```diff ... @@ -75,9 +75,9 @@ if [ 1 -eq $CONNECTED ]; then ... ``` -#### Patch for [Hass Kindle 4 Lovelace plugin](https://github.com/sibbl/hass-lovelace-kindle-4/) +#### Patch for [HASS Lovelace Kindle 4 extension](https://github.com/sibbl/hass-lovelace-kindle-4/) -Modify the following lines in the Kindle Online Screensaver plugin's [`script.sh`](https://github.com/sibbl/hass-lovelace-kindle-4/blob/main/extensions/homeassistant/script.sh#L133) (absolute path on device should be `/mnt/us/extensions/homeassistant/script.sh`): +Modify the following lines in the HASS Lovelace Kindle 4 extension's [`script.sh`](https://github.com/sibbl/hass-lovelace-kindle-4/blob/main/extensions/homeassistant/script.sh#L133) (absolute path on device should be `/mnt/us/extensions/homeassistant/script.sh`): ```diff ... From 0b60bd6008f4030d6b320d2db6a925361ecafa16 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 12 Jul 2022 10:01:57 +0200 Subject: [PATCH 34/74] Link to new kiosk HACS addon in readme [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc36eb..803d9e3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Home Assistant related stuff: | Env Var | Sample value | Required | Array?\* | Description | | ------------------------- | ------------------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | -| `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/maykar/kiosk-mode) project) | +| `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/NemesisRE/kiosk-mode) project) | | `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | | `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | yes | Webhook definied in HA which receives `batteryLevel` (number between 0-100) and `isCharging` (boolean) as JSON | | `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | From b6ca2bda01f8d31b017cf2e6821c3272838cdebe Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 18 Jul 2022 09:31:14 +0200 Subject: [PATCH 35/74] Make docker compose instructions more precise [skip ci] --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 803d9e3..dd6c397 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,10 @@ Using my [own Kindle 4 setup guide](https://github.com/sibbl/hass-lovelace-kindl You may simple set up the [sibbl/hass-lovelace-kindle-screensaver](https://hub.docker.com/r/sibbl/hass-lovelace-kindle-screensaver) docker container. The container exposes a single port (5000 by default). -You can access the image by doing a simple GET request to e.g. `http://localhost:5000/` to receive the most recent image. +I recommend simply using the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up -d` within the file's directory. This will pull the docker image, create the container with all environment variables from the file and run it in detached mode (using `-d`, so it continues running even when you exit your shell/bash/ssh connection). +Additionally, you can then later use `docker-compose pull && docker-compose up -d` to update the image in case you want to update it. + +You can then access the image by doing a simple GET request to e.g. `http://localhost:5000/` to receive the most recent image (might take up to 60s after the first run). Home Assistant related stuff: @@ -46,8 +49,6 @@ Home Assistant related stuff: If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. You can access these additional images by making GET Requests `http://localhost:5000/2`, `http://localhost:5000/3` etc. -You may also simply use the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up`. - ### How to set up the webhook The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: From 56f121a5aa4c54c061722a0e248041c15044da6c Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 18 Jul 2022 09:33:14 +0200 Subject: [PATCH 36/74] Fix typo [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dd6c397..01d54eb 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Home Assistant related stuff: | `RENDERING_SCREEN_WIDTH` | `600` | no | yes | Width of your kindle screen resolution | | `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | | `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | -| `GRAYSCALE_DEPTH` | `8` | no | yes | Ggrayscale bit depth your kindle supports | +| `GRAYSCALE_DEPTH` | `8` | no | yes | Grayscale bit depth your kindle supports | | `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | | `DITHER` | `false` | no | yes | Apply a dither to the images. | From b819f753bced85966e5abb5f4e0cc14cd535f42e Mon Sep 17 00:00:00 2001 From: Lorenzo Rogai Date: Sat, 30 Jul 2022 17:15:25 +0200 Subject: [PATCH 37/74] Consider ignoreCertificateErrors when sending battery status to HA --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 33eb86b..4fe7945 100644 --- a/index.js +++ b/index.js @@ -207,7 +207,8 @@ function sendBatteryLevelToHomeAssistant( headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(batteryStatus) - } + }, + rejectUnauthorized: !config.ignoreCertificateErrors }; const url = `${config.baseUrl}/api/webhook/${batteryWebHook}`; const httpLib = url.toLowerCase().startsWith("https") ? https : http; From e1d6bb0b51d5cdb8e27c8a1101eced499dafd1b6 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 16 Jan 2023 09:18:47 +0100 Subject: [PATCH 38/74] Bump alpine to 3.17 to include newer chromium #7 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 45d25b0..74502f1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine3.11 +FROM node:16-alpine3.17 WORKDIR /app From ea916cf74773c4ce59231a5c8be31c9a31680aac Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 16 Jan 2023 09:19:11 +0100 Subject: [PATCH 39/74] Include emoji font #48 --- Dockerfile | 4 +++- local.conf | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 local.conf diff --git a/Dockerfile b/Dockerfile index 74502f1..f83e5ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,8 @@ WORKDIR /app RUN apk add --no-cache \ chromium \ nss \ - freetype \ + freetype \ + font-noto-emoji \ freetype-dev \ harfbuzz \ ca-certificates \ @@ -17,6 +18,7 @@ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ USE_IMAGE_MAGICK=true COPY package*.json ./ +COPY local.conf /etc/fonts/local.conf RUN npm ci diff --git a/local.conf b/local.conf new file mode 100644 index 0000000..ed6c08b --- /dev/null +++ b/local.conf @@ -0,0 +1,31 @@ + + + + + + sans-serif + + Main sans-serif font name goes here + Noto Color Emoji + Noto Emoji + + + + + serif + + Main serif font name goes here + Noto Color Emoji + Noto Emoji + + + + + monospace + + Main monospace font name goes here + Noto Color Emoji + Noto Emoji + + + \ No newline at end of file From 7b3a36c14b0c15594d5a657ca8d07204a30d77de Mon Sep 17 00:00:00 2001 From: J3n50m4t Date: Wed, 26 Apr 2023 08:39:20 +0200 Subject: [PATCH 40/74] Adding HA Addon files --- .github/workflows/ci.yml | 60 ++++++++++++++++++++++++++++++++++------ .gitignore | 4 ++- Dockerfile.HA_ADDON | 33 ++++++++++++++++++++++ config.yaml | 53 +++++++++++++++++++++++++++++++++++ repository.yaml | 3 ++ run.sh | 22 +++++++++++++++ 6 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 Dockerfile.HA_ADDON create mode 100644 config.yaml create mode 100644 repository.yaml create mode 100755 run.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54005f3..214a559 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,13 +30,55 @@ jobs: platforms: linux/amd64,linux/arm/v7,linux/arm64 push: true tags: | - sibbl/hass-lovelace-kindle-screensaver:${{ env.PACKAGE_VERSION }}, - sibbl/hass-lovelace-kindle-screensaver:latest - - name: Tag git commit - uses: pkgdeps/git-tag-action@v2 + j3n50m4t/hass-lovelace-kindle-screensaver:${{ env.PACKAGE_VERSION }}, + j3n50m4t/hass-lovelace-kindle-screensaver:latest + - name: Build and push HA_Addon AMD64 to Docker + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.HA_ADDON + build-args: BUILD_FROM=homeassistant/amd64-base:latest + platforms: linux/amd64 + push: true + tags: | + j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-amd64:${{ env.PACKAGE_VERSION }}, + j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-amd64:latest + - name: Build and push HA_Addon aarch64 to Docker + uses: docker/build-push-action@v2 with: - github_token: ${{ secrets.GITHUB_TOKEN }} - github_repo: ${{ github.repository }} - version: ${{ env.PACKAGE_VERSION }} - git_commit_sha: ${{ github.sha }} - git_tag_prefix: "v" + context: . + file: ./Dockerfile.HA_ADDON + build-args: BUILD_FROM=homeassistant/aarch64-base:latest + platforms: linux/arm64 + push: true + tags: | + j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-aarch64:${{ env.PACKAGE_VERSION }}, + j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-aarch64:latest + + + # Currently fails with. I'dont know why, as build womm. Someone? + #8 0.148 fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/armhf/APKINDEX.tar.gz + #8 1.271 fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/armhf/APKINDEX.tar.gz + #8 2.193 ERROR: unable to select packages: + #8 2.282 chromium (no such package): + #8 2.282 required by: world[chromium] + # - name: Build and push HA_Addon ARMv7 to Docker + # uses: docker/build-push-action@v2 + # with: + # context: . + # file: ./Dockerfile.HA_ADDON + # build-args: BUILD_FROM=homeassistant/armhf-base:latest + # platforms: linux/armhf + # push: true + # tags: | + # j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, + # j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest + + # - name: Tag git commit + # uses: pkgdeps/git-tag-action@v2 + # with: + # github_token: ${{ secrets.GITHUB_TOKEN }} + # github_repo: ${{ github.repository }} + # version: ${{ env.PACKAGE_VERSION }} + # git_commit_sha: ${{ github.sha }} + # git_tag_prefix: "v" diff --git a/.gitignore b/.gitignore index 70c659c..0c2bb5c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ node_modules/ config.*.js docker-compose.*.yml cover.png -output/ \ No newline at end of file +output/ +.devcontainer/ +.DS_Store \ No newline at end of file diff --git a/Dockerfile.HA_ADDON b/Dockerfile.HA_ADDON new file mode 100644 index 0000000..0100f83 --- /dev/null +++ b/Dockerfile.HA_ADDON @@ -0,0 +1,33 @@ +ARG BUILD_FROM +FROM ${BUILD_FROM} + +WORKDIR /app +RUN apk add --no-cache \ + chromium \ + nss \ + freetype \ + font-noto-emoji \ + freetype-dev \ + harfbuzz \ + ca-certificates \ + ttf-freefont \ + imagemagick \ + nodejs \ + npm + +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \ + PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser \ + USE_IMAGE_MAGICK=true + +COPY package*.json ./ +COPY local.conf /etc/fonts/local.conf +COPY *.js ./ + +RUN npm ci + + +# Copy data for add-on +COPY run.sh / +RUN chmod a+x /run.sh + +CMD [ "/run.sh" ] \ No newline at end of file diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..a01f98c --- /dev/null +++ b/config.yaml @@ -0,0 +1,53 @@ +name: Lovelace Kindle Screensaver +version: 1.0.4 +slug: kindle-screensaver +description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. +startup: application +boot: auto +arch: + - aarch64 + - amd64 + # - - See github/ci.yml +url: 'https://github.com/J3n50m4t/hass-lovelace-kindle-screensaver' +image: 'j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-{arch}' +webui: 'http://[HOST]:[PORT:5000]' +ingress: true +ingress_port: 5000 +ports: + 5000/tcp: 5000 +ports_description: + 5000/tcp: 'Node Webserver hosting rendered image' +map: + - media:rw +watchdog: 'http://[HOST]:[PORT:5000]/' +init: false +options: + HA_BASE_URL: 'https://your-path-to-home-assistant:8123' + HA_SCREENSHOT_URL: '/lovelace/0' + HA_ACCESS_TOKEN: '' + LANGUAGE: 'en' + CRON_JOB: '* * * * *' + RENDERING_TIMEOUT: '60000' + RENDERING_DELAY: '0' + RENDERING_SCREEN_HEIGHT: '800' + RENDERING_SCREEN_WIDTH: '600' + ROTATION: '0' + SCALING: '1' + GRAYSCALE_DEPTH: '8' + COLOR_MODE: 'GrayScale' +schema: + HA_BASE_URL: "url" + HA_SCREENSHOT_URL: "str" + HA_ACCESS_TOKEN: "password" + LANGUAGE: "str" + CRON_JOB: "str" + RENDERING_TIMEOUT: "int" + RENDERING_DELAY: "int" + RENDERING_SCREEN_HEIGHT: "int" + RENDERING_SCREEN_WIDTH: "int" + ROTATION: "int" + SCALING: "int" + GRAYSCALE_DEPTH: "int" + COLOR_MODE: "list(GrayScale|TrueColor)?" +environment: + output_path: "/output/cover.png" \ No newline at end of file diff --git a/repository.yaml b/repository.yaml new file mode 100644 index 0000000..4ca365d --- /dev/null +++ b/repository.yaml @@ -0,0 +1,3 @@ +name: 'Lovelace Kindle Screensaver' +url: 'https://github.com/J3n50m4t/hass-lovelace-kindle-screensaver' +maintainer: 'sibbl' \ No newline at end of file diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..968cee8 --- /dev/null +++ b/run.sh @@ -0,0 +1,22 @@ +#!/usr/bin/with-contenv bashio + +bashio::log.info "Starting npm server..." + +export HA_BASE_URL="$(bashio::config 'HA_BASE_URL')" +export HA_SCREENSHOT_URL=$(bashio::config 'HA_SCREENSHOT_URL') +export HA_ACCESS_TOKEN="$(bashio::config 'HA_ACCESS_TOKEN')" +export LANGUAGE=$(bashio::config 'LANGUAGE') +export CRON_JOB=$(bashio::config 'CRON_JOB') +export RENDERING_TIMEOUT=$(bashio::config 'RENDERING_TIMEOUT') +export RENDERING_DELAY=$(bashio::config 'RENDERING_DELAY') +export RENDERING_SCREEN_HEIGHT=$(bashio::config 'RENDERING_SCREEN_HEIGHT') +export RENDERING_SCREEN_WIDTH=$(bashio::config 'RENDERING_SCREEN_WIDTH') +export ROTATION=$(bashio::config 'ROTATION') +export SCALING=$(bashio::config 'SCALING') +export GRAYSCALE_DEPTH=$(bashio::config 'GRAYSCALE_DEPTH') +export COLOR_MODE=$(bashio::config 'COLOR_MODE') + +bashio::log.info "Using base_url: ${HA_BASE_URL}" + +cd /app +exec /usr/bin/npm start \ No newline at end of file From bb3e3cd343a312c00126ef80e59c42e934d455f7 Mon Sep 17 00:00:00 2001 From: J3n50m4t Date: Thu, 27 Apr 2023 12:34:53 +0200 Subject: [PATCH 41/74] cleanup --- .github/workflows/ci.yml | 16 ++++++++-------- .gitignore | 1 - config.yaml | 4 ++-- repository.yaml | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 214a559..e7a7203 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,8 @@ jobs: platforms: linux/amd64,linux/arm/v7,linux/arm64 push: true tags: | - j3n50m4t/hass-lovelace-kindle-screensaver:${{ env.PACKAGE_VERSION }}, - j3n50m4t/hass-lovelace-kindle-screensaver:latest + sibbl/hass-lovelace-kindle-screensaver:${{ env.PACKAGE_VERSION }}, + sibbl/hass-lovelace-kindle-screensaver:latest - name: Build and push HA_Addon AMD64 to Docker uses: docker/build-push-action@v2 with: @@ -41,8 +41,8 @@ jobs: platforms: linux/amd64 push: true tags: | - j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-amd64:${{ env.PACKAGE_VERSION }}, - j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-amd64:latest + sibbl/hass-lovelace-kindle-screensaver-ha-addon-amd64:${{ env.PACKAGE_VERSION }}, + sibbl/hass-lovelace-kindle-screensaver-ha-addon-amd64:latest - name: Build and push HA_Addon aarch64 to Docker uses: docker/build-push-action@v2 with: @@ -52,8 +52,8 @@ jobs: platforms: linux/arm64 push: true tags: | - j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-aarch64:${{ env.PACKAGE_VERSION }}, - j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-aarch64:latest + sibbl/hass-lovelace-kindle-screensaver-ha-addon-aarch64:${{ env.PACKAGE_VERSION }}, + sibbl/hass-lovelace-kindle-screensaver-ha-addon-aarch64:latest # Currently fails with. I'dont know why, as build womm. Someone? @@ -71,8 +71,8 @@ jobs: # platforms: linux/armhf # push: true # tags: | - # j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, - # j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest + # sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, + # sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest # - name: Tag git commit # uses: pkgdeps/git-tag-action@v2 diff --git a/.gitignore b/.gitignore index 0c2bb5c..be4cc39 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,5 @@ node_modules/ config.*.js docker-compose.*.yml cover.png -output/ .devcontainer/ .DS_Store \ No newline at end of file diff --git a/config.yaml b/config.yaml index a01f98c..31a9139 100644 --- a/config.yaml +++ b/config.yaml @@ -8,8 +8,8 @@ arch: - aarch64 - amd64 # - - See github/ci.yml -url: 'https://github.com/J3n50m4t/hass-lovelace-kindle-screensaver' -image: 'j3n50m4t/hass-lovelace-kindle-screensaver-ha-addon-{arch}' +url: 'https://github.com/sibbl/hass-lovelace-kindle-screensaver' +image: 'sibbl/hass-lovelace-kindle-screensaver-ha-addon-{arch}' webui: 'http://[HOST]:[PORT:5000]' ingress: true ingress_port: 5000 diff --git a/repository.yaml b/repository.yaml index 4ca365d..1249b7a 100644 --- a/repository.yaml +++ b/repository.yaml @@ -1,3 +1,3 @@ name: 'Lovelace Kindle Screensaver' -url: 'https://github.com/J3n50m4t/hass-lovelace-kindle-screensaver' +url: 'https://github.com/sibbl/hass-lovelace-kindle-screensaver' maintainer: 'sibbl' \ No newline at end of file From 6f20b3a800f91682315e043209d185c44764f5e4 Mon Sep 17 00:00:00 2001 From: J3n50m4t Date: Thu, 27 Apr 2023 12:52:33 +0200 Subject: [PATCH 42/74] Add instructions how to install the addon --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 01d54eb..122ad69 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,8 @@ Using my [own Kindle 4 setup guide](https://github.com/sibbl/hass-lovelace-kindl You may simple set up the [sibbl/hass-lovelace-kindle-screensaver](https://hub.docker.com/r/sibbl/hass-lovelace-kindle-screensaver) docker container. The container exposes a single port (5000 by default). +Another way is to use Hassio Addons where you have to add this repository or click [here](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fsibbl%2Fhass-lovelace-kindle-screensaver). Then Reload and you should see options to the Lovelace Kindle Screensaver Addon + I recommend simply using the `docker-compose.yml` file inside this repository, configure everything in there and run `docker-compose up -d` within the file's directory. This will pull the docker image, create the container with all environment variables from the file and run it in detached mode (using `-d`, so it continues running even when you exit your shell/bash/ssh connection). Additionally, you can then later use `docker-compose pull && docker-compose up -d` to update the image in case you want to update it. From 4d9de934facd09c8c03c0a89d659a22d02af019a Mon Sep 17 00:00:00 2001 From: Davide Cavalca Date: Mon, 5 Jun 2023 08:32:45 -0700 Subject: [PATCH 43/74] Add local_only input to blueprint --- battery_sensor_blueprint.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/battery_sensor_blueprint.yaml b/battery_sensor_blueprint.yaml index 612b343..8fdce8e 100644 --- a/battery_sensor_blueprint.yaml +++ b/battery_sensor_blueprint.yaml @@ -6,6 +6,11 @@ blueprint: name: Webhook ID description: Unique and secret ID of ID to use for webhook. It's recommended to run `openssl rand -hex 16` to generate something random. default: set_kindle_battery_level + local_only: + name: Only allow connections from the local network + selector: + boolean: + default: true battery_level: name: Entity to save battery level in description: Please create a new helper entity first. @@ -22,6 +27,7 @@ blueprint: trigger: - platform: webhook webhook_id: !input webhook_id + local_only: !input local_only action: - service: input_number.set_value target: From 16b368cf8f4073b3811d1d23e60ce43134d89d09 Mon Sep 17 00:00:00 2001 From: Robert Lee Date: Sun, 25 Jun 2023 20:42:50 +0100 Subject: [PATCH 44/74] Update config.yaml Added HA_BATTERY_WEBHOOK to addon config and bumped addon version for release. --- config.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.yaml b/config.yaml index 31a9139..412eb5d 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.4 +version: 1.0.5 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application @@ -35,6 +35,7 @@ options: SCALING: '1' GRAYSCALE_DEPTH: '8' COLOR_MODE: 'GrayScale' + HA_BATTERY_WEBHOOK: '' schema: HA_BASE_URL: "url" HA_SCREENSHOT_URL: "str" @@ -49,5 +50,6 @@ schema: SCALING: "int" GRAYSCALE_DEPTH: "int" COLOR_MODE: "list(GrayScale|TrueColor)?" + HA_BATTERY_WEBHOOK: "str" environment: - output_path: "/output/cover.png" \ No newline at end of file + output_path: "/output/cover.png" From 23f14a94f20ab393d0dc00b7c685fe5b834b07f9 Mon Sep 17 00:00:00 2001 From: Robert Lee Date: Mon, 26 Jun 2023 17:16:07 +0100 Subject: [PATCH 45/74] Added HA_BATTERY_WEBHOOK env variable setting --- run.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 968cee8..e37d49d 100755 --- a/run.sh +++ b/run.sh @@ -15,8 +15,9 @@ export ROTATION=$(bashio::config 'ROTATION') export SCALING=$(bashio::config 'SCALING') export GRAYSCALE_DEPTH=$(bashio::config 'GRAYSCALE_DEPTH') export COLOR_MODE=$(bashio::config 'COLOR_MODE') +export HA_BATTERY_WEBHOOK=$(bashio::config 'HA_BATTERY_WEBHOOK') bashio::log.info "Using base_url: ${HA_BASE_URL}" cd /app -exec /usr/bin/npm start \ No newline at end of file +exec /usr/bin/npm start From a50fddc7269731f9e508493054189ba89af69989 Mon Sep 17 00:00:00 2001 From: Robert Lee Date: Mon, 26 Jun 2023 17:16:38 +0100 Subject: [PATCH 46/74] Bumping release version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 171437b..ffb19c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.4", + "version": "1.0.5", "description": "", "main": "index.js", "scripts": { From 8050ed357d341f80274956f1e9d9647d9f0e2dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Seppo=20R=C3=A4is=C3=A4nen?= Date: Fri, 13 Oct 2023 14:34:24 +0300 Subject: [PATCH 47/74] Wait until first render is done before starting up cron job. It was possible that cron job was ran while first render was still running, causing problems when two threads simultaneously wrote same output image. --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 4fe7945..346b59e 100644 --- a/index.js +++ b/index.js @@ -66,7 +66,7 @@ const batteryStore = {}; renderAndConvertAsync(browser); } else { console.log("Starting first render..."); - renderAndConvertAsync(browser); + await renderAndConvertAsync(browser); console.log("Starting rendering cronjob..."); new CronJob({ cronTime: config.cronJob, From 797cfb83e2d30d949b8f40e561fc9a20b2f2315d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Seppo=20R=C3=A4is=C3=A4nen?= Date: Fri, 13 Oct 2023 15:15:32 +0300 Subject: [PATCH 48/74] Add option to remove Gamma correction from image. Computer images are normally gamma corrected since monitors expect it. However some E-Ink displays expect linear instead gamma corrected image data. Added new option REMOVE_GAMMA that will remove gamma correction from the image when it is set to true. --- README.md | 1 + config.js | 1 + index.js | 1 + 3 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 122ad69..50b157c 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ Home Assistant related stuff: | `GRAYSCALE_DEPTH` | `8` | no | yes | Grayscale bit depth your kindle supports | | `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | | `DITHER` | `false` | no | yes | Apply a dither to the images. | +| `REMOVE_GAMMA` | `true` | no | no | Remove gamma correction from image. Computer images are normally gamma corrected since monitors expect gamma corrected data, however some E-Ink displays expect images not to have gamma correction. | **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. diff --git a/config.js b/config.js index 6a5001a..316366e 100644 --- a/config.js +++ b/config.js @@ -25,6 +25,7 @@ function getPagesConfig() { width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, }, grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, + removeGamma: getEnvironmentVariable("REMOVE_GAMMA", suffix) || false, blackLevel: getEnvironmentVariable("BLACK_LEVEL", suffix) || "0%", whiteLevel: getEnvironmentVariable("WHITE_LEVEL", suffix) || "100%", dither: getEnvironmentVariable("DITHER", suffix) || false, diff --git a/index.js b/index.js index 346b59e..163e55b 100644 --- a/index.js +++ b/index.js @@ -303,6 +303,7 @@ function convertImageToKindleCompatiblePngAsync( .options({ imageMagick: config.useImageMagick === true }) + .gamma(pageConfig.removeGamma ? 1.0/2.2 : 1.0) .dither(pageConfig.dither) .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) From 8e076105736b3f2b94ce6eb6dd35da985bb0792a Mon Sep 17 00:00:00 2001 From: Jan Suchal Date: Sat, 25 Nov 2023 18:19:54 +0100 Subject: [PATCH 49/74] Add support for browser launch timeout --- README.md | 35 ++++++++++++++++++----------------- config.js | 1 + config.yaml | 2 ++ index.js | 1 + 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 50b157c..035d9b9 100644 --- a/README.md +++ b/README.md @@ -29,23 +29,24 @@ You can then access the image by doing a simple GET request to e.g. `http://loca Home Assistant related stuff: -| Env Var | Sample value | Required | Array?\* | Description | -| ------------------------- | ------------------------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | -| `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/NemesisRE/kiosk-mode) project) | -| `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | -| `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | yes | Webhook definied in HA which receives `batteryLevel` (number between 0-100) and `isCharging` (boolean) as JSON | -| `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | -| `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | -| `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | -| `RENDERING_DELAY` | `0` | no | yes | how long to wait between navigating to the page and taking the screenshot, in milliseconds | -| `RENDERING_SCREEN_HEIGHT` | `800` | no | yes | Height of your kindle screen resolution | -| `RENDERING_SCREEN_WIDTH` | `600` | no | yes | Width of your kindle screen resolution | -| `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | -| `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | -| `GRAYSCALE_DEPTH` | `8` | no | yes | Grayscale bit depth your kindle supports | -| `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | -| `DITHER` | `false` | no | yes | Apply a dither to the images. | +| Env Var | Sample value | Required | Array?\* | Description | +|---------------------------|---------------------------------------| -------- | -------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `HA_BASE_URL` | `https://your-hass-instance.com:8123` | yes | no | Base URL of your home assistant instance | +| `HA_SCREENSHOT_URL` | `/lovelace/screensaver?kiosk` | yes | yes | Relative URL to take screenshot of (btw, the `?kiosk` parameter hides the nav bar using the [kiosk mode](https://github.com/NemesisRE/kiosk-mode) project) | +| `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | +| `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | yes | Webhook definied in HA which receives `batteryLevel` (number between 0-100) and `isCharging` (boolean) as JSON | +| `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | +| `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | +| `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | +| `RENDERING_DELAY` | `0` | no | yes | how long to wait between navigating to the page and taking the screenshot, in milliseconds | +| `RENDERING_SCREEN_HEIGHT` | `800` | no | yes | Height of your kindle screen resolution | +| `RENDERING_SCREEN_WIDTH` | `600` | no | yes | Width of your kindle screen resolution | +| `BROWSER_LAUNCH_TIMEOUT` | `30000` | no | no | Timeout for browser launch, helpful if your HASS instance is slow | +| `ROTATION` | `0` | no | yes | Rotation of image in degrees, e.g. use 90 or 270 to render in landscape | +| `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | +| `GRAYSCALE_DEPTH` | `8` | no | yes | Grayscale bit depth your kindle supports | +| `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | +| `DITHER` | `false` | no | yes | Apply a dither to the images. | | `REMOVE_GAMMA` | `true` | no | no | Remove gamma correction from image. Computer images are normally gamma corrected since monitors expect gamma corrected data, however some E-Ink displays expect images not to have gamma correction. | **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. diff --git a/config.js b/config.js index 316366e..5eefedb 100644 --- a/config.js +++ b/config.js @@ -46,6 +46,7 @@ module.exports = { pages: getPagesConfig(), port: process.env.PORT || 5000, renderingTimeout: process.env.RENDERING_TIMEOUT || 10000, + browserLaunchTimeout: process.env.BROWSER_LAUNCH_TIMEOUT || 30000, language: process.env.LANGUAGE || "en", debug: process.env.DEBUG === "true", ignoreCertificateErrors: diff --git a/config.yaml b/config.yaml index 412eb5d..0540014 100644 --- a/config.yaml +++ b/config.yaml @@ -31,6 +31,7 @@ options: RENDERING_DELAY: '0' RENDERING_SCREEN_HEIGHT: '800' RENDERING_SCREEN_WIDTH: '600' + BROWSER_LAUNCH_TIMEOUT: '30000' ROTATION: '0' SCALING: '1' GRAYSCALE_DEPTH: '8' @@ -46,6 +47,7 @@ schema: RENDERING_DELAY: "int" RENDERING_SCREEN_HEIGHT: "int" RENDERING_SCREEN_WIDTH: "int" + BROWSER_LAUNCH_TIMEOUT: "int" ROTATION: "int" SCALING: "int" GRAYSCALE_DEPTH: "int" diff --git a/index.js b/index.js index 163e55b..7b958d5 100644 --- a/index.js +++ b/index.js @@ -32,6 +32,7 @@ const batteryStore = {}; `--lang=${config.language}`, config.ignoreCertificateErrors && "--ignore-certificate-errors" ].filter((x) => x), + timeout: config.browserLaunchTimeout, headless: config.debug !== true }); From dd33180c1e6b6db8fbe5fcf273ff272ab5da320e Mon Sep 17 00:00:00 2001 From: deenter <103332332+deenter@users.noreply.github.com> Date: Sat, 2 Dec 2023 13:05:16 +0100 Subject: [PATCH 50/74] Add option to enable browser dark mode --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 035d9b9..1fdb0f0 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Home Assistant related stuff: | `HA_ACCESS_TOKEN` | `eyJ0...` | yes | no | Long-lived access token from Home Assistant, see [official docs](https://developers.home-assistant.io/docs/auth_api/#long-lived-access-token) | | `HA_BATTERY_WEBHOOK` | `set_kindle_battery_level` | no | yes | Webhook definied in HA which receives `batteryLevel` (number between 0-100) and `isCharging` (boolean) as JSON | | `LANGUAGE` | `en` | no | no | Language to set in browser and home assistant | +| `PREFERS_COLOR_SCHEME` | `light` | no | no | Enable browser dark mode, use `light` or `dark`. | | `CRON_JOB` | `* * * * *` | no | no | How often to take screenshot | | `RENDERING_TIMEOUT` | `10000` | no | no | Timeout of render process, helpful if your HASS instance might be down | | `RENDERING_DELAY` | `0` | no | yes | how long to wait between navigating to the page and taking the screenshot, in milliseconds | From 2e88cfb7571c28f80a92c7e734f6955ea82955f3 Mon Sep 17 00:00:00 2001 From: deenter <103332332+deenter@users.noreply.github.com> Date: Sat, 2 Dec 2023 13:06:32 +0100 Subject: [PATCH 51/74] Add option to enable browser dark mode --- config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/config.js b/config.js index 5eefedb..919cfb5 100644 --- a/config.js +++ b/config.js @@ -30,6 +30,7 @@ function getPagesConfig() { whiteLevel: getEnvironmentVariable("WHITE_LEVEL", suffix) || "100%", dither: getEnvironmentVariable("DITHER", suffix) || false, colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", + prefersColorScheme: getEnvironmentVariable("PREFERS_COLOR_SCHEME", suffix) || "light", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, scaling: getEnvironmentVariable("SCALING", suffix) || 1, batteryWebHook: getEnvironmentVariable("HA_BATTERY_WEBHOOK", suffix) || null, From bc03fd8c8919ea2fc7bf60cc500b87274200b77c Mon Sep 17 00:00:00 2001 From: deenter <103332332+deenter@users.noreply.github.com> Date: Sat, 2 Dec 2023 13:07:27 +0100 Subject: [PATCH 52/74] Add option to enable browser dark mode --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 7b958d5..d127e45 100644 --- a/index.js +++ b/index.js @@ -234,7 +234,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { await page.emulateMediaFeatures([ { name: "prefers-color-scheme", - value: "light" + value: `${pageConfig.prefersColorScheme}` } ]); From 6364bf17747666d91ac56377cab96d8972f55cea Mon Sep 17 00:00:00 2001 From: deenter <103332332+deenter@users.noreply.github.com> Date: Sat, 2 Dec 2023 21:02:26 +0100 Subject: [PATCH 53/74] Add option to enable browser dark mode, Hass.io dropdown entry --- config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config.yaml b/config.yaml index 0540014..f6c7d5c 100644 --- a/config.yaml +++ b/config.yaml @@ -36,6 +36,7 @@ options: SCALING: '1' GRAYSCALE_DEPTH: '8' COLOR_MODE: 'GrayScale' + PREFERS_COLOR_SCHEME: 'light' HA_BATTERY_WEBHOOK: '' schema: HA_BASE_URL: "url" @@ -52,6 +53,7 @@ schema: SCALING: "int" GRAYSCALE_DEPTH: "int" COLOR_MODE: "list(GrayScale|TrueColor)?" + PREFERS_COLOR_SCHEME: "list(light|dark)?" HA_BATTERY_WEBHOOK: "str" environment: output_path: "/output/cover.png" From 40c379fed1ceb1c6a2cecb96c74e9f7b6eaac18b Mon Sep 17 00:00:00 2001 From: Paul Chevalier Date: Fri, 5 Jan 2024 11:54:28 -0500 Subject: [PATCH 54/74] Fix bug in config.yaml for proper scaling Replaced int descriptor with float --- config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index f6c7d5c..90cab29 100644 --- a/config.yaml +++ b/config.yaml @@ -50,7 +50,7 @@ schema: RENDERING_SCREEN_WIDTH: "int" BROWSER_LAUNCH_TIMEOUT: "int" ROTATION: "int" - SCALING: "int" + SCALING: "float" GRAYSCALE_DEPTH: "int" COLOR_MODE: "list(GrayScale|TrueColor)?" PREFERS_COLOR_SCHEME: "list(light|dark)?" From f5255cc2459791a02eca76e57022cf9c4cf48759 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 21 Jan 2024 11:00:19 +0100 Subject: [PATCH 55/74] Bump to version 1.0.6 --- config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.yaml b/config.yaml index 90cab29..5e15513 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.5 +version: 1.0.6 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application From 36ec4a8acad6fa713704133f3f22bfd6cf94b620 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 21 Jan 2024 12:50:39 +0100 Subject: [PATCH 56/74] Bump package.json to 1.0.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ffb19c0..0844cfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.5", + "version": "1.0.6", "description": "", "main": "index.js", "scripts": { From a921ac8f9baec3e5ec056f0c9f83f4dcdb1b374d Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Tue, 6 Feb 2024 19:39:10 +0100 Subject: [PATCH 57/74] Add armv7 support for Hassio addon (#106) * Add armv7 hassio addon --- .github/workflows/ci.yml | 45 +++++++++++++++++----------------------- config.yaml | 2 +- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7a7203..2a16742 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,30 +55,23 @@ jobs: sibbl/hass-lovelace-kindle-screensaver-ha-addon-aarch64:${{ env.PACKAGE_VERSION }}, sibbl/hass-lovelace-kindle-screensaver-ha-addon-aarch64:latest + - name: Build and push HA_Addon ARMv7 to Docker + uses: docker/build-push-action@v2 + with: + context: . + file: ./Dockerfile.HA_ADDON + build-args: BUILD_FROM=homeassistant/armv7-base:latest + platforms: linux/armv7 + push: true + tags: | + sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, + sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest - # Currently fails with. I'dont know why, as build womm. Someone? - #8 0.148 fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/armhf/APKINDEX.tar.gz - #8 1.271 fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/armhf/APKINDEX.tar.gz - #8 2.193 ERROR: unable to select packages: - #8 2.282 chromium (no such package): - #8 2.282 required by: world[chromium] - # - name: Build and push HA_Addon ARMv7 to Docker - # uses: docker/build-push-action@v2 - # with: - # context: . - # file: ./Dockerfile.HA_ADDON - # build-args: BUILD_FROM=homeassistant/armhf-base:latest - # platforms: linux/armhf - # push: true - # tags: | - # sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, - # sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest - - # - name: Tag git commit - # uses: pkgdeps/git-tag-action@v2 - # with: - # github_token: ${{ secrets.GITHUB_TOKEN }} - # github_repo: ${{ github.repository }} - # version: ${{ env.PACKAGE_VERSION }} - # git_commit_sha: ${{ github.sha }} - # git_tag_prefix: "v" + - name: Tag git commit + uses: pkgdeps/git-tag-action@v2 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + github_repo: ${{ github.repository }} + version: ${{ env.PACKAGE_VERSION }} + git_commit_sha: ${{ github.sha }} + git_tag_prefix: "v" diff --git a/config.yaml b/config.yaml index 5e15513..ff309ea 100644 --- a/config.yaml +++ b/config.yaml @@ -7,7 +7,7 @@ boot: auto arch: - aarch64 - amd64 - # - - See github/ci.yml + - armv7 url: 'https://github.com/sibbl/hass-lovelace-kindle-screensaver' image: 'sibbl/hass-lovelace-kindle-screensaver-ha-addon-{arch}' webui: 'http://[HOST]:[PORT:5000]' From 27cdea6924564b54d67e1a62c7aa4aeb31c0b7f4 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Thu, 22 Feb 2024 16:20:47 +0100 Subject: [PATCH 58/74] Allow additional env vars for Hass Add-On + add missing config params (#111) * Add ADDITIONAL_ENV_VARS hassio option * Bump to v1.0.7 * Add missing config options to run.sh * Add changelog * Update readme * Make non-required options optional --- CHANGELOG.md | 12 ++++++++++++ README.md | 13 +++++++++++++ config.yaml | 32 ++++++++++++++++++++------------ package.json | 2 +- run.sh | 20 ++++++++++++++++++-- 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b2c2b82 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +## 1.0.7 + +### Added + +* Finally there's a changelog +* Allow custom environment variables to Home Assistant Add-On + +### Fixed + +* Add missing config variables to Home Assistant Add-On diff --git a/README.md b/README.md index 1fdb0f0..6f53342 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,19 @@ Home Assistant related stuff: If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. You can access these additional images by making GET Requests `http://localhost:5000/2`, `http://localhost:5000/3` etc. +To make us of the array feature in the Home Assistant Add-On, you may use `ADDITIONAL_ENV_VARS`. It expects a format like this to set any additional environment variable: + +```yaml +- name: "HA_SCREENSHOT_URL_2" + value: "/lovelace/second-page" +- name: "ROTATION_2" + value: "180" +- name: "HA_SCREENSHOT_URL_3" + value: "/lovelace/third-page" +``` + +To avoid problems, please ensure that the name only contains upper case letters, numbers and underscores. The value field must be a string, so it's better to always put your value (especially numbers) into a `"string"` . + ### How to set up the webhook The webhook setting is to let HA keep track of the battery level of the Kindle, so it can warn you about charging it. You need to do the following: diff --git a/config.yaml b/config.yaml index ff309ea..f21e689 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.6 +version: 1.0.7 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application @@ -36,24 +36,32 @@ options: SCALING: '1' GRAYSCALE_DEPTH: '8' COLOR_MODE: 'GrayScale' + DITHER: false + REMOVE_GAMMA: true PREFERS_COLOR_SCHEME: 'light' HA_BATTERY_WEBHOOK: '' + ADDITIONAL_ENV_VARS: [] schema: HA_BASE_URL: "url" HA_SCREENSHOT_URL: "str" HA_ACCESS_TOKEN: "password" - LANGUAGE: "str" - CRON_JOB: "str" - RENDERING_TIMEOUT: "int" - RENDERING_DELAY: "int" - RENDERING_SCREEN_HEIGHT: "int" - RENDERING_SCREEN_WIDTH: "int" - BROWSER_LAUNCH_TIMEOUT: "int" - ROTATION: "int" - SCALING: "float" - GRAYSCALE_DEPTH: "int" + LANGUAGE: "str?" + CRON_JOB: "str?" + RENDERING_TIMEOUT: "int?" + RENDERING_DELAY: "int?" + RENDERING_SCREEN_HEIGHT: "int?" + RENDERING_SCREEN_WIDTH: "int?" + BROWSER_LAUNCH_TIMEOUT: "int?" + ROTATION: "int?" + SCALING: "float?" + GRAYSCALE_DEPTH: "int?" COLOR_MODE: "list(GrayScale|TrueColor)?" + DITHER: "bool?" + REMOVE_GAMMA: "bool?" PREFERS_COLOR_SCHEME: "list(light|dark)?" - HA_BATTERY_WEBHOOK: "str" + HA_BATTERY_WEBHOOK: "str?" + ADDITIONAL_ENV_VARS: + - name: match(^[A-Z0-9_]+$) + value: str environment: output_path: "/output/cover.png" diff --git a/package.json b/package.json index 0844cfb..8d57485 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.6", + "version": "1.0.7", "description": "", "main": "index.js", "scripts": { diff --git a/run.sh b/run.sh index e37d49d..d47758b 100755 --- a/run.sh +++ b/run.sh @@ -1,6 +1,6 @@ #!/usr/bin/with-contenv bashio -bashio::log.info "Starting npm server..." +bashio::log.info "Loading config..." export HA_BASE_URL="$(bashio::config 'HA_BASE_URL')" export HA_SCREENSHOT_URL=$(bashio::config 'HA_SCREENSHOT_URL') @@ -11,13 +11,29 @@ export RENDERING_TIMEOUT=$(bashio::config 'RENDERING_TIMEOUT') export RENDERING_DELAY=$(bashio::config 'RENDERING_DELAY') export RENDERING_SCREEN_HEIGHT=$(bashio::config 'RENDERING_SCREEN_HEIGHT') export RENDERING_SCREEN_WIDTH=$(bashio::config 'RENDERING_SCREEN_WIDTH') +export BROWSER_LAUNCH_TIMEOUT=$(bashio::config 'BROWSER_LAUNCH_TIMEOUT') export ROTATION=$(bashio::config 'ROTATION') export SCALING=$(bashio::config 'SCALING') export GRAYSCALE_DEPTH=$(bashio::config 'GRAYSCALE_DEPTH') export COLOR_MODE=$(bashio::config 'COLOR_MODE') +export DITHER=$(bashio::config 'DITHER') +export REMOVE_GAMMA=$(bashio::config 'REMOVE_GAMMA') +export PREFERS_COLOR_SCHEME=$(bashio::config 'PREFERS_COLOR_SCHEME') export HA_BATTERY_WEBHOOK=$(bashio::config 'HA_BATTERY_WEBHOOK') -bashio::log.info "Using base_url: ${HA_BASE_URL}" +bashio::log.info "Loading additional environment variables..." + +# Load custom environment variables +for var in $(bashio::config 'ADDITIONAL_ENV_VARS|keys'); do + name=$(bashio::config "ADDITIONAL_ENV_VARS[${var}].name") + value=$(bashio::config "ADDITIONAL_ENV_VARS[${var}].value") + bashio::log.info "Setting ${name} to ${value}" + export "${name}=${value}" +done + +bashio::log.info "Using HA_BASE_URL: ${HA_BASE_URL}" + +bashio::log.info "Starting server..." cd /app exec /usr/bin/npm start From 0d073a260d07ea8700499eecb0df6936517289b7 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 23 Feb 2024 13:17:43 +0100 Subject: [PATCH 59/74] Remove DITHER option from HA Add-On again --- CHANGELOG.md | 6 ++++++ config.yaml | 4 +--- package.json | 2 +- run.sh | 1 - 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2c2b82..bbbdd72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.8 + +### Fixed + +* Remove DITHER option from Home Assistant Add-On again until the gm/im incompatibility will be fixed + ## 1.0.7 ### Added diff --git a/config.yaml b/config.yaml index f21e689..508e717 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.7 +version: 1.0.8 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application @@ -36,7 +36,6 @@ options: SCALING: '1' GRAYSCALE_DEPTH: '8' COLOR_MODE: 'GrayScale' - DITHER: false REMOVE_GAMMA: true PREFERS_COLOR_SCHEME: 'light' HA_BATTERY_WEBHOOK: '' @@ -56,7 +55,6 @@ schema: SCALING: "float?" GRAYSCALE_DEPTH: "int?" COLOR_MODE: "list(GrayScale|TrueColor)?" - DITHER: "bool?" REMOVE_GAMMA: "bool?" PREFERS_COLOR_SCHEME: "list(light|dark)?" HA_BATTERY_WEBHOOK: "str?" diff --git a/package.json b/package.json index 8d57485..528fd3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.7", + "version": "1.0.8", "description": "", "main": "index.js", "scripts": { diff --git a/run.sh b/run.sh index d47758b..9aab4b9 100755 --- a/run.sh +++ b/run.sh @@ -16,7 +16,6 @@ export ROTATION=$(bashio::config 'ROTATION') export SCALING=$(bashio::config 'SCALING') export GRAYSCALE_DEPTH=$(bashio::config 'GRAYSCALE_DEPTH') export COLOR_MODE=$(bashio::config 'COLOR_MODE') -export DITHER=$(bashio::config 'DITHER') export REMOVE_GAMMA=$(bashio::config 'REMOVE_GAMMA') export PREFERS_COLOR_SCHEME=$(bashio::config 'PREFERS_COLOR_SCHEME') export HA_BATTERY_WEBHOOK=$(bashio::config 'HA_BATTERY_WEBHOOK') From 5380aad3bf6edd32004a7cfec1a35024f683d794 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Mon, 4 Mar 2024 17:46:19 +0100 Subject: [PATCH 60/74] Use architecture and versions during CI build of hass addon --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a16742..ab9c1d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: context: . file: ./Dockerfile.HA_ADDON build-args: BUILD_FROM=homeassistant/aarch64-base:latest - platforms: linux/arm64 + platforms: linux/arm64/v8 push: true tags: | sibbl/hass-lovelace-kindle-screensaver-ha-addon-aarch64:${{ env.PACKAGE_VERSION }}, @@ -61,7 +61,7 @@ jobs: context: . file: ./Dockerfile.HA_ADDON build-args: BUILD_FROM=homeassistant/armv7-base:latest - platforms: linux/armv7 + platforms: linux/arm/v7 push: true tags: | sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, From 24b1a8cba76931541244a07ac6db72dc38c44505 Mon Sep 17 00:00:00 2001 From: Nacho Barrientos Date: Fri, 15 Mar 2024 14:08:13 +0100 Subject: [PATCH 61/74] Allow switching output image format --- README.md | 5 +++-- config.js | 3 ++- config.yaml | 4 +++- docker-compose.yml | 2 +- index.js | 13 +++++++------ run.sh | 1 + 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6f53342..6f85d60 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ If you're looking for a way to render your own HTML, see my other project [hass- ## Features -This tool regularly takes a screenshot of a specific page of your home assistant setup. It converts it into the PNG grayscale format which Kindles can display. +This tool regularly takes a screenshot of a specific page of your home assistant setup. It converts it into the PNG/JPEG grayscale format which Kindles can display. Using my [own Kindle 4 setup guide](https://github.com/sibbl/hass-lovelace-kindle-4) or the [online screensaver extension](https://www.mobileread.com/forums/showthread.php?t=236104) for any jailbroken Kindle, this image can be regularly polled from your device so you can use it as a weather station, a display for next public transport departures etc. @@ -47,6 +47,7 @@ Home Assistant related stuff: | `SCALING` | `1` | no | yes | Scaling factor, e.g. `1.5` to zoom in or `0.75` to zoom out | | `GRAYSCALE_DEPTH` | `8` | no | yes | Grayscale bit depth your kindle supports | | `COLOR_MODE` | `GrayScale` | no | yes | ColorMode to use, ex: `GrayScale`, or `TrueColor`. | +| `IMAGE_FORMAT` | `png` | no | no | Format for the generated images. Acceptable values are `png` or `jpeg`. | | `DITHER` | `false` | no | yes | Apply a dither to the images. | | `REMOVE_GAMMA` | `true` | no | no | Remove gamma correction from image. Computer images are normally gamma corrected since monitors expect gamma corrected data, however some E-Ink displays expect images not to have gamma correction. | @@ -109,7 +110,7 @@ Modify the following lines in the HASS Lovelace Kindle 4 extension's [`script.sh Some advanced variables for local usage which shouldn't be necessary when using Docker: -- `OUTPUT_PATH=./output.png` (destination of rendered image. `OUTPUT_2`, `OUTPUT_3`, ... is also supported) +- `OUTPUT_PATH=./output` (destination of rendered image, without extension. `OUTPUT_2`, `OUTPUT_3`, ... is also supported) - `PORT=5000` (port of server, which returns the last image) - `USE_IMAGE_MAGICK=false` (use ImageMagick instead of GraphicsMagick) - `UNSAFE_IGNORE_CERTIFICATE_ERRORS=true` (ignore certificate errors of e.g. self-signed certificates at your own risk) diff --git a/config.js b/config.js index 919cfb5..fe7c84d 100644 --- a/config.js +++ b/config.js @@ -13,10 +13,11 @@ function getPagesConfig() { if (!screenShotUrl) return pages; pages.push({ screenShotUrl, + imageFormat: getEnvironmentVariable("IMAGE_FORMAT", suffix) || "png", outputPath: getEnvironmentVariable( "OUTPUT_PATH", suffix, - `output/cover${suffix}.png` + `output/cover${suffix}` ), renderingDelay: getEnvironmentVariable("RENDERING_DELAY", suffix) || 0, renderingScreenSize: { diff --git a/config.yaml b/config.yaml index 508e717..f3c2913 100644 --- a/config.yaml +++ b/config.yaml @@ -35,6 +35,7 @@ options: ROTATION: '0' SCALING: '1' GRAYSCALE_DEPTH: '8' + IMAGE_FORMAT: 'png' COLOR_MODE: 'GrayScale' REMOVE_GAMMA: true PREFERS_COLOR_SCHEME: 'light' @@ -54,6 +55,7 @@ schema: ROTATION: "int?" SCALING: "float?" GRAYSCALE_DEPTH: "int?" + IMAGE_FORMAT: "list(png|jpeg)?" COLOR_MODE: "list(GrayScale|TrueColor)?" REMOVE_GAMMA: "bool?" PREFERS_COLOR_SCHEME: "list(light|dark)?" @@ -62,4 +64,4 @@ schema: - name: match(^[A-Z0-9_]+$) value: str environment: - output_path: "/output/cover.png" + output_path: "/output/cover" diff --git a/docker-compose.yml b/docker-compose.yml index 1da0140..cfcaf63 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,7 +13,7 @@ services: - RENDERING_SCREEN_HEIGHT=800 - RENDERING_SCREEN_WIDTH=600 - GRAYSCALE_DEPTH=8 - - OUTPUT_PATH=/output/cover.png + - OUTPUT_PATH=/output/cover - LANGUAGE=en - ROTATION=0 - SCALING=1 diff --git a/index.js b/index.js index d127e45..a80671a 100644 --- a/index.js +++ b/index.js @@ -105,13 +105,14 @@ const batteryStore = {}; const pageIndex = pageNumber - 1; const configPage = config.pages[pageIndex]; - const data = await fs.readFile(configPage.outputPath); - const stat = await fs.stat(configPage.outputPath); + const outputPathWithExtension = configPage.outputPath + "." + configPage.imageFormat + const data = await fs.readFile(outputPathWithExtension); + const stat = await fs.stat(outputPathWithExtension); const lastModifiedTime = new Date(stat.mtime).toUTCString(); response.writeHead(200, { - "Content-Type": "image/png", + "Content-Type": "image/" + configPage.imageFormat, "Content-Length": Buffer.byteLength(data), "Last-Modified": lastModifiedTime }); @@ -165,7 +166,7 @@ async function renderAndConvertAsync(browser) { const url = `${config.baseUrl}${pageConfig.screenShotUrl}`; - const outputPath = pageConfig.outputPath; + const outputPath = pageConfig.outputPath + "." + pageConfig.imageFormat; await fsExtra.ensureDir(path.dirname(outputPath)); const tempPath = outputPath + ".temp"; @@ -173,7 +174,7 @@ async function renderAndConvertAsync(browser) { console.log(`Rendering ${url} to image...`); await renderUrlToImageAsync(browser, pageConfig, url, tempPath); - console.log(`Converting rendered screenshot of ${url} to grayscale png...`); + console.log(`Converting rendered screenshot of ${url} to grayscale...`); await convertImageToKindleCompatiblePngAsync( pageConfig, tempPath, @@ -278,7 +279,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { } await page.screenshot({ path, - type: "png", + type: pageConfig.imageFormat, clip: { x: 0, y: 0, diff --git a/run.sh b/run.sh index 9aab4b9..f0bbddc 100755 --- a/run.sh +++ b/run.sh @@ -15,6 +15,7 @@ export BROWSER_LAUNCH_TIMEOUT=$(bashio::config 'BROWSER_LAUNCH_TIMEOUT') export ROTATION=$(bashio::config 'ROTATION') export SCALING=$(bashio::config 'SCALING') export GRAYSCALE_DEPTH=$(bashio::config 'GRAYSCALE_DEPTH') +export IMAGE_FORMAT=$(bashio::config 'IMAGE_FORMAT') export COLOR_MODE=$(bashio::config 'COLOR_MODE') export REMOVE_GAMMA=$(bashio::config 'REMOVE_GAMMA') export PREFERS_COLOR_SCHEME=$(bashio::config 'PREFERS_COLOR_SCHEME') From b8ab75c5bbb081ac216c272e6bf2de841e05808c Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 15 Mar 2024 16:41:19 +0100 Subject: [PATCH 62/74] Bump version, update changelog --- CHANGELOG.md | 6 ++++++ config.yaml | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbbdd72..43a1a89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.9 + +### Added + +* Add jpeg support via new `IMAGE_TYPE` config env variable (thanks to [@nbarrientos](https://github.com/nbarrientos)) + ## 1.0.8 ### Fixed diff --git a/config.yaml b/config.yaml index f3c2913..4c83a83 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.8 +version: 1.0.9 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application diff --git a/package.json b/package.json index 528fd3a..b06f942 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.8", + "version": "1.0.9", "description": "", "main": "index.js", "scripts": { From 73d2dc76f1bfd5ea115c40808f9504f58ae6fb5a Mon Sep 17 00:00:00 2001 From: cosote Date: Tue, 9 Apr 2024 11:56:57 +0200 Subject: [PATCH 63/74] REMOVE_GAMMA and DITHER options were strings and always true --- config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.js b/config.js index fe7c84d..a0f2364 100644 --- a/config.js +++ b/config.js @@ -26,10 +26,10 @@ function getPagesConfig() { width: getEnvironmentVariable("RENDERING_SCREEN_WIDTH", suffix) || 600, }, grayscaleDepth: getEnvironmentVariable("GRAYSCALE_DEPTH", suffix) || 8, - removeGamma: getEnvironmentVariable("REMOVE_GAMMA", suffix) || false, + removeGamma: getEnvironmentVariable("REMOVE_GAMMA", suffix) === "true" || false, blackLevel: getEnvironmentVariable("BLACK_LEVEL", suffix) || "0%", whiteLevel: getEnvironmentVariable("WHITE_LEVEL", suffix) || "100%", - dither: getEnvironmentVariable("DITHER", suffix) || false, + dither: getEnvironmentVariable("DITHER", suffix) === "true" || false, colorMode: getEnvironmentVariable("COLOR_MODE", suffix) || "GrayScale", prefersColorScheme: getEnvironmentVariable("PREFERS_COLOR_SCHEME", suffix) || "light", rotation: getEnvironmentVariable("ROTATION", suffix) || 0, From 117ebb7dde8eac4a004d0ddf3cb21ccc3dd86f75 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 14 Apr 2024 17:47:53 +0200 Subject: [PATCH 64/74] Change CI trigger to use versions --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab9c1d1..19b27ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,7 @@ name: ci on: push: - branches: - - main + tags: [ 'v*.*.*' ] jobs: multi: From 3cd7e086f48617e45a2407a6fecd29140d5b95b6 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 14 Apr 2024 17:50:08 +0200 Subject: [PATCH 65/74] Bump version to 1.0.10 --- CHANGELOG.md | 6 ++++++ config.yaml | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 43a1a89..b52978c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.10 + +### Fixed + +* Fix REMOVE_GAMMA and DITHER always being enabled for Home Assistant Add-On + ## 1.0.9 ### Added diff --git a/config.yaml b/config.yaml index 4c83a83..6869277 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.9 +version: 1.0.10 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application diff --git a/package.json b/package.json index b06f942..406e4aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.9", + "version": "1.0.10", "description": "", "main": "index.js", "scripts": { From 511296472970108116e1ddfc19a43759e43ec616 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Sun, 14 Apr 2024 17:51:29 +0200 Subject: [PATCH 66/74] Skip tagging commit via CI --- .github/workflows/ci.yml | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 19b27ff..59e73b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,13 +64,4 @@ jobs: push: true tags: | sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:${{ env.PACKAGE_VERSION }}, - sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest - - - name: Tag git commit - uses: pkgdeps/git-tag-action@v2 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - github_repo: ${{ github.repository }} - version: ${{ env.PACKAGE_VERSION }} - git_commit_sha: ${{ github.sha }} - git_tag_prefix: "v" + sibbl/hass-lovelace-kindle-screensaver-ha-addon-armv7:latest \ No newline at end of file From 31487f7237d0850184612aeea1e5204976ce362f Mon Sep 17 00:00:00 2001 From: Kevin Steven Caluser Date: Wed, 22 May 2024 07:44:33 +0200 Subject: [PATCH 67/74] Fix Viewport resizing upon page.screenshot --- index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.js b/index.js index a80671a..ddd88da 100644 --- a/index.js +++ b/index.js @@ -32,6 +32,7 @@ const batteryStore = {}; `--lang=${config.language}`, config.ignoreCertificateErrors && "--ignore-certificate-errors" ].filter((x) => x), + defaultViewport: null, timeout: config.browserLaunchTimeout, headless: config.debug !== true }); @@ -280,6 +281,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { await page.screenshot({ path, type: pageConfig.imageFormat, + captureBeyondViewport: false, clip: { x: 0, y: 0, From 885d0f93bef67e5d4f3d7968ab765590f1449cd6 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Wed, 22 May 2024 15:44:56 +0200 Subject: [PATCH 68/74] Extend changelog, bump version to 1.0.11 --- CHANGELOG.md | 6 ++++++ config.yaml | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b52978c..41e5635 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.11 + +### Fixed + +* Avoid viewport resize causing another rerender when taking screenshot (thanks to [@beeh5](https://github.com/beeh5)) + ## 1.0.10 ### Fixed diff --git a/config.yaml b/config.yaml index 6869277..89fbf50 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.10 +version: 1.0.11 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application diff --git a/package.json b/package.json index 406e4aa..e4bd105 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.10", + "version": "1.0.11", "description": "", "main": "index.js", "scripts": { From c9d90e8945aef6889939764622ee5873ce1d8498 Mon Sep 17 00:00:00 2001 From: Anthony Hiley-Mann Date: Tue, 6 Aug 2024 20:01:00 +0100 Subject: [PATCH 69/74] Swap CSS scale for zoom --- index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/index.js b/index.js index ddd88da..c94d9de 100644 --- a/index.js +++ b/index.js @@ -267,10 +267,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { await page.addStyleTag({ content: ` body { - width: calc(${size.width}px / ${pageConfig.scaling}); - height: calc(${size.height}px / ${pageConfig.scaling}); - transform-origin: 0 0; - transform: scale(${pageConfig.scaling}); + zoom: ${pageConfig.scaling * 100}%; overflow: hidden; }` }); From a0111ca866abb940712a5167330ee903aa138f1b Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Wed, 7 Aug 2024 09:41:29 +0200 Subject: [PATCH 70/74] Bump version to 1.0.12 --- CHANGELOG.md | 6 ++++++ config.yaml | 2 +- package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e5635..a901930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.12 + +## Fixed + +* Fix scaling bug by using zoom css property instead of transforms (thanks to [@avhm](https://github.com/avhm)) + ## 1.0.11 ### Fixed diff --git a/config.yaml b/config.yaml index 89fbf50..3f888cd 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.11 +version: 1.0.12 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application diff --git a/package.json b/package.json index e4bd105..bd69b67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.11", + "version": "1.0.12", "description": "", "main": "index.js", "scripts": { From af6e15419bf2ce6c78f66935292bc1e8f67abab7 Mon Sep 17 00:00:00 2001 From: Harry Best Date: Mon, 23 Dec 2024 13:23:50 +0000 Subject: [PATCH 71/74] Add image controls including saturation and contrast --- README.md | 4 ++++ config.js | 2 ++ index.js | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6f85d60..3423531 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,10 @@ Home Assistant related stuff: | `IMAGE_FORMAT` | `png` | no | no | Format for the generated images. Acceptable values are `png` or `jpeg`. | | `DITHER` | `false` | no | yes | Apply a dither to the images. | | `REMOVE_GAMMA` | `true` | no | no | Remove gamma correction from image. Computer images are normally gamma corrected since monitors expect gamma corrected data, however some E-Ink displays expect images not to have gamma correction. | +| SATURATION | 2 | no | no | Saturation level multiplier, e.g. 2 doubles the saturation | +| CONTRAST | 2 | no | no | Contrast level multiplier, e.g. 2 doubles the contrast | +| BLACK_LEVEL | 30% | no | no | Black point as percentage of MaxRGB, i.e. crushes blacks below specified level | +| WHITE_LEVEL | 90% | no | no | White point as percentage of MaxRGB, i.e. crushes whites above specified level | **\* Array** means that you can set `HA_SCREENSHOT_URL_2`, `HA_SCREENSHOT_URL_3`, ... `HA_SCREENSHOT_URL_n` to render multiple pages within the same instance. If you use `HA_SCREENSHOT_URL_2`, you can also set `ROTATION_2=180`. If there is no `ROTATION_n` set, then `ROTATION` will be used as a fallback. diff --git a/config.js b/config.js index a0f2364..d94b9c8 100644 --- a/config.js +++ b/config.js @@ -35,6 +35,8 @@ function getPagesConfig() { rotation: getEnvironmentVariable("ROTATION", suffix) || 0, scaling: getEnvironmentVariable("SCALING", suffix) || 1, batteryWebHook: getEnvironmentVariable("HA_BATTERY_WEBHOOK", suffix) || null, + saturation: getEnvironmentVariable("SATURATION", suffix) || 1, + contrast: getEnvironmentVariable("CONTRAST", suffix) || 1, }); } return pages; diff --git a/index.js b/index.js index c94d9de..9ac15c7 100644 --- a/index.js +++ b/index.js @@ -283,7 +283,8 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { x: 0, y: 0, ...size - } + }, + quality: 100 }); } catch (e) { console.error("Failed to render", e); @@ -304,7 +305,9 @@ function convertImageToKindleCompatiblePngAsync( .options({ imageMagick: config.useImageMagick === true }) - .gamma(pageConfig.removeGamma ? 1.0/2.2 : 1.0) + .gamma(pageConfig.removeGamma ? 1.0 / 2.2 : 1.0) + .modulate(100, 100 * pageConfig.saturation) + .contrast(pageConfig.contrast) .dither(pageConfig.dither) .rotate("white", pageConfig.rotation) .type(pageConfig.colorMode) From 836cd8757845073aca9890cd07d58aff5a6631db Mon Sep 17 00:00:00 2001 From: Harry Best Date: Mon, 23 Dec 2024 13:51:32 +0000 Subject: [PATCH 72/74] Add new variables to home assistant config --- config.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config.yaml b/config.yaml index 3f888cd..46978a0 100644 --- a/config.yaml +++ b/config.yaml @@ -40,6 +40,8 @@ options: REMOVE_GAMMA: true PREFERS_COLOR_SCHEME: 'light' HA_BATTERY_WEBHOOK: '' + SATURATION: 1 + CONTRAST: 1 ADDITIONAL_ENV_VARS: [] schema: HA_BASE_URL: "url" @@ -60,6 +62,8 @@ schema: REMOVE_GAMMA: "bool?" PREFERS_COLOR_SCHEME: "list(light|dark)?" HA_BATTERY_WEBHOOK: "str?" + SATURATION: "int?" + CONTRAST: "int?" ADDITIONAL_ENV_VARS: - name: match(^[A-Z0-9_]+$) value: str From d7ba1faa09d89dfb2bf8de55aeb6d36f60da7c45 Mon Sep 17 00:00:00 2001 From: Harry Best Date: Mon, 23 Dec 2024 13:58:32 +0000 Subject: [PATCH 73/74] Only apply quality setting to screenshot if jpeg --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 9ac15c7..525667d 100644 --- a/index.js +++ b/index.js @@ -284,7 +284,7 @@ async function renderUrlToImageAsync(browser, pageConfig, url, path) { y: 0, ...size }, - quality: 100 + ...(pageConfig.imageFormat=="jpeg") && {quality: 100} }); } catch (e) { console.error("Failed to render", e); From 1822d90f870060e25282c71b08c97da5f8acb849 Mon Sep 17 00:00:00 2001 From: Sebastian Schubotz Date: Fri, 27 Dec 2024 12:58:15 +0100 Subject: [PATCH 74/74] Bump verison to 1.0.13 --- CHANGELOG.md | 8 +++++++- config.yaml | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a901930..809ac9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ # Changelog +## 1.0.13 + +### Added + +* Allow configuring contrast, saturation, black level and white level. JPEG quality is set to 100% (thanks to [@harry48225](https://github.com/harry48225)) + ## 1.0.12 -## Fixed +### Fixed * Fix scaling bug by using zoom css property instead of transforms (thanks to [@avhm](https://github.com/avhm)) diff --git a/config.yaml b/config.yaml index 46978a0..cfce801 100644 --- a/config.yaml +++ b/config.yaml @@ -1,5 +1,5 @@ name: Lovelace Kindle Screensaver -version: 1.0.12 +version: 1.0.13 slug: kindle-screensaver description: This tool can be used to display a Lovelace view of your Home Assistant instance on a jailbroken Kindle device. It regularly takes a screenshot which can be polled and used as a screensaver image of the online screensaver plugin. startup: application diff --git a/package.json b/package.json index bd69b67..9afe7a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hass-lovelace-kindle-screensaver", - "version": "1.0.12", + "version": "1.0.13", "description": "", "main": "index.js", "scripts": {