Taking screenshots - Final?

Hello,

For some time now I'm struggling to produce working automated screenshots of my dashboard (it uibuilder dashboard but it doesn't matter here).

I've tried puppeteer and chromium headless.

First, the puppeteer from this link Headless Chrome: Webpage Capture using Puppeteer (JS and Node-Red) (youtube.com)
It produces only blank 3.3Kb PNG file. There is no documentation how to set it on Node-RED further.
So I've tried launching it from a function node, but no matter whether I try to import the module with import puppeteer from 'puppeteer'; or const puppeteer = require('puppeteer');, it always gives me this error:
"SyntaxError: Cannot use import statement outside a module (body:line 1)"
Unfortunatelly, I don't have nearly sufficient javascript experience, but I understand It can not work that way because its not plain JS.

I would like to focus on chromium headless instead.
Now, this does work (albeit with warnings):
/usr/bin/chromium --headless --disable-extensions --disable-gpu -inprivate --use-fake-ui-for-media-stream --no-sandbox --run-all-compositor-stages-before-draw --virtual-time-budget=100 --window-size=1920,900 --screenshot='/home/xxx/screenshot.png' 'http://192.168.x.xxx:1880/SUNAMA/#/'
but only when I have node-red editor opened. It does not work automated at 14:00 and 22:00.

Anyone got similar experince?

Also, here are the errors I'm getting:

[0205/071326.127680:INFO:policy_logger.cc(144)] :components/policy/core/common/config_dir_policy_loader.cc(118) Skipping mandatory platform policies because no policy file was found at: /etc/chromium/policies/managed
[0205/071326.127719:INFO:policy_logger.cc(144)] :components/policy/core/common/config_dir_policy_loader.cc(118) Skipping recommended platform policies because no policy file was found at: /etc/chromium/policies/recommended
[0205/071326.136836:WARNING:bluez_dbus_manager.cc(248)] Floss manager not present, cannot set Floss enable/disable.
1591100 bytes written to file /home/xxx/screenshot.png

Thank in advance,

BR

Not had time to watch the video. I assume you are trying to access it from a function node?

No,

First I've tried this (from the video):

[{"id":"32cc98e2c46a956c","type":"inject","z":"fe70b7069e03e98b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":820,"y":900,"wires":[["4a930faa496f3fcd"]]},{"id":"4a930faa496f3fcd","type":"puppeteer-browser-launch","z":"fe70b7069e03e98b","timeout":30000,"slowMo":"0","headless":true,"debugport":0,"devtools":false,"name":"","x":980,"y":900,"wires":[["8b45738f8281c018"]]},{"id":"8b45738f8281c018","type":"puppeteer-page-goto","z":"fe70b7069e03e98b","name":"","url":"http://192.168.2.190:1880/SUNAMA/#/","urltype":"str","waitUntil":"networkidle2","x":1230,"y":900,"wires":[["3730c3fcd848fed4"]]},{"id":"3730c3fcd848fed4","type":"puppeteer-page-screenshot","z":"fe70b7069e03e98b","name":"","fullpage":true,"x":950,"y":960,"wires":[["ddee81f9df03e855"]]},{"id":"ddee81f9df03e855","type":"file","z":"fe70b7069e03e98b","name":"","filename":"/home/tomislav/screenshot.png","filenameType":"str","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1200,"y":960,"wires":[[]]}]

I got blank SS-s.

Then I've tried from the function node:

[{"id":"f19d8456803c9971","type":"inject","z":"fe70b7069e03e98b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1300,"y":800,"wires":[["045474efaa93026b"]]},{"id":"5ba6d2ec2c3b5339","type":"file","z":"fe70b7069e03e98b","name":"","filename":"/home/tomislav/screenshot.png","filenameType":"str","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1590,"y":860,"wires":[[]]},{"id":"045474efaa93026b","type":"function","z":"fe70b7069e03e98b","name":"function 4","func":"\nimport puppeteer from 'puppeteer';\n//const puppeteer = require('puppeteer');\n\nconst Screenshot = async () => {\n    // Launch the browser and open a new blank page\n    const browser = await puppeteer.launch();\n    const page = await browser.newPage();\n\n    // Navigate the page to a URL\n    await page.goto('http://192.168.2.190:1880/SUNAMA/#/');\n\n    // Set screen size\n    await page.setViewport({ width: 1080, height: 1024 });\n\n\n\n    await page.screenshot({                      // Screenshot the website using defined options\n\n        path: \"/home/tomislav/screenshot.png\",                   // Save the screenshot in current directory\n\n        fullPage: true                              // take a fullpage screenshot\n    });\n\n    await browser.close();\n\n\n}\n\nScreenshot();\n\n\n\n\n\n\n\n\n/*\nconst puppeteer = require('puppeteer');         // Require Puppeteer module\n\nconst url = \"http://192.168.2.190:1880/SUNAMA/#/\";           // Set website you want to screenshot\n\nconst Screenshot = async () => {                // Define Screenshot function\n\n    const browser = await puppeteer.launch();    // Launch a \"browser\"\n\n    const page = await browser.newPage();        // Open a new page\n\n    await page.goto(url);                        // Go to the website\n\n    await page.screenshot({                      // Screenshot the website using defined options\n\n        path: \"/home/tomislav/screenshot.png\",                   // Save the screenshot in current directory\n\n        fullPage: true                              // take a fullpage screenshot\n\n    });\n\n    await page.close();                           // Close the website\n\n    await browser.close();                        // Close the browser\n\n}\n\nScreenshot();                                   // Call the Screenshot function\n\n*/\n\n\n\n\n\n\n\n\n\n/*\n\nimport puppeteer from 'puppeteer';\n\n(async () => {\n    // Launch the browser and open a new blank page\n    const browser = await puppeteer.launch();\n    const page = await browser.newPage();\n\n    // Navigate the page to a URL\n    await page.goto('http://192.168.2.190:1880/SUNAMA/#/');\n\n    // Set screen size\n    await page.setViewport({ width: 1080, height: 1024 });\n\n    // Type into search box\n    await page.type('.devsite-search-field', 'automate beyond recorder');\n\n    // Wait and click on first result\n    const searchResultSelector = '.devsite-result-item-link';\n    await page.waitForSelector(searchResultSelector);\n    await page.click(searchResultSelector);\n\n    // Locate the full title with a unique string\n    const textSelector = await page.waitForSelector(\n        'text/Customize and automate'\n    );\n    const fullTitle = await textSelector?.evaluate(el => el.textContent);\n\n    // Print the full title\n    console.log('The title of this blog post is \"%s\".', fullTitle);\n\n    await browser.close();\n})();\n\n*/","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1460,"y":800,"wires":[["5ba6d2ec2c3b5339","c2c89c716d84b1f6"]]},{"id":"c2c89c716d84b1f6","type":"debug","z":"fe70b7069e03e98b","name":"debug 41","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1640,"y":800,"wires":[]}]

But I don't know how to load modules to Node-RED so It didnt work.

Final resort is the EXEC node where I launched the chromium from:

[{"id":"ed1d9a03f067fadd","type":"exec","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","command":"/usr/bin/chromium --headless --disable-extensions --disable-gpu -inprivate --use-fake-ui-for-media-stream --no-sandbox --run-all-compositor-stages-before-draw --virtual-time-budget=100 --window-size=1920,900 --screenshot='/home/tomislav/screenshot.png' 'http://192.168.2.190:1880/SUNAMA/#/'","addpay":"","append":"","useSpawn":"false","timer":"20","winHide":false,"oldrc":false,"name":"SUNAMA screenshot","x":560,"y":620,"wires":[["053b37941329fecd","fa594bb8a04d7687","9a2e152f3ae44413"],["60e2ae4ddc807e9b","20ea6bc34db55532"],["cd4728ba112bdb1c"]]}]

But this is finicky and I haven't make it run consistently. It runs only from the second try when im at the editor via inject node.

So this page has an example you should be able to use with a function node:

But you need to use the setup tab of the function and add puppeteer as a module.

Then in the code, you don't need the require statement as node-red does that for you when you add the module. Everything else should be much the same.

I would like to suggest to use the puppeteer node, which uses puppeteer in the background/headless but with custom nodes, which make it all very easy to use in node-red. Simple webdriver also works, but requires a headless server somehow.

1 Like

Tried this but got errors in the node-red:

npm WARN config production Use `--omit=dev` instead.
npm ERR! code ENOTEMPTY
npm ERR! syscall rename
npm ERR! path /home/tomislav/.node-red/node_modules/cross-fetch
npm ERR! dest /home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70
npm ERR! errno -39
npm ERR! ENOTEMPTY: directory not empty, rename '/home/tomislav/.node-red/node_modules/cross-fetch' -> '/home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70'

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/tomislav/.npm/_logs/2024-02-05T13_49_23_645Z-debug-0.log

Then I've tried to remove node-red-contrib-puppeteer-new from the pallete, but remove failed with server getting unresponsive until reboot.

Also tried manually via Putty:

tomislav@sust:~/.node-red$ npm list node-red-contrib-puppeteer-new
node-red-project@0.0.1 /home/tomislav/.node-red
└── node-red-contrib-puppeteer-new@0.3.7
tomislav@sust:~/.node-red$ sudo npm uninstall node-red-contrib-puppeteer-new
npm ERR! code ENOTEMPTY
npm ERR! syscall rename
npm ERR! path /home/tomislav/.node-red/node_modules/cross-fetch
npm ERR! dest /home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70
npm ERR! errno -39
npm ERR! ENOTEMPTY: directory not empty, rename '/home/tomislav/.node-red/node_modules/cross-fetch' -> '/home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70'

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2024-02-05T13_52_30_723Z-debug-0.log

Tried puppeteer-new but it didn't work.
Documentation for puppeteer for node-red is very scarse

What exactly "didn't work" ?

Here is an example flow that works great with puppeteer. Note: this flow uses this node.

[
    {
        "id": "e13ff486513435f4",
        "type": "puppeteer-browser-launch",
        "z": "d5ab2d7681d50185",
        "timeout": 30000,
        "slowMo": 0,
        "headless": true,
        "debugport": 0,
        "devtools": false,
        "cookies": "",
        "name": "",
        "x": 320,
        "y": 680,
        "wires": [
            [
                "fd31bec6c231b081"
            ]
        ]
    },
    {
        "id": "712f93f5f7bede3a",
        "type": "inject",
        "z": "d5ab2d7681d50185",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 680,
        "wires": [
            [
                "e13ff486513435f4"
            ]
        ]
    },
    {
        "id": "fd31bec6c231b081",
        "type": "puppeteer-page-goto",
        "z": "d5ab2d7681d50185",
        "name": "",
        "url": "https://google.com",
        "urltype": "str",
        "waitUntil": "networkidle2",
        "x": 490,
        "y": 680,
        "wires": [
            [
                "e5e0bb3915ae6ffc"
            ]
        ]
    },
    {
        "id": "e5e0bb3915ae6ffc",
        "type": "puppeteer-page-content",
        "z": "d5ab2d7681d50185",
        "name": "",
        "x": 680,
        "y": 680,
        "wires": [
            [
                "c3abb0b82310fc3a"
            ]
        ]
    },
    {
        "id": "c3abb0b82310fc3a",
        "type": "debug",
        "z": "d5ab2d7681d50185",
        "name": "debug 615",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 850,
        "y": 680,
        "wires": []
    }
]
1 Like

This issue is spelled out - there is a directory named /home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70 so npm cannot proceed.

Delete /home/tomislav/.node-red/node_modules/.cross-fetch-GIKUGa70 directory and then try installing it again.

This can happen if npm fails to finish setup either by being cancelled by the user (CTRL+C) or crashing before finishing.

1 Like

Delete any files in that folder that start with a dot and have a random string on the end. Then try installing the node again.

1 Like

Also, never use sudo when installing nodes locally.

1 Like

Thank you man.

Here is the custom resolution and file output flow I'm using:

[{"id":"e13ff486513435f4","type":"puppeteer-browser-launch","z":"fe70b7069e03e98b","timeout":30000,"slowMo":0,"headless":true,"debugport":0,"devtools":false,"cookies":"","name":"","x":1320,"y":760,"wires":[["154709dcabda3665"]]},{"id":"712f93f5f7bede3a","type":"inject","z":"fe70b7069e03e98b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1320,"y":720,"wires":[["e13ff486513435f4"]]},{"id":"fd31bec6c231b081","type":"puppeteer-page-goto","z":"fe70b7069e03e98b","name":"","url":"http://192.168.2.190:1880/SUNAMA/#/","urltype":"str","waitUntil":"networkidle2","x":1410,"y":840,"wires":[["ea3a006837fad44b"]]},{"id":"8d90b7ca7f7fa064","type":"file","z":"fe70b7069e03e98b","name":"","filename":"/home/tomislav/screenshot.png","filenameType":"str","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1390,"y":920,"wires":[[]]},{"id":"ea3a006837fad44b","type":"puppeteer-page-screenshot","z":"fe70b7069e03e98b","name":"","fullpage":false,"x":1330,"y":880,"wires":[["8d90b7ca7f7fa064"]]},{"id":"154709dcabda3665","type":"puppeteer-page-viewport","z":"fe70b7069e03e98b","name":"","width":"1920","height":"900","scale":1,"x":1320,"y":800,"wires":[["fd31bec6c231b081"]]}]
1 Like

Important update:
To prevent memory leaks / system crash / proc running at 100% it is mandatory to close the page and the browser instance afterwords like this:

[{"id":"e13ff486513435f4","type":"puppeteer-browser-launch","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","timeout":"5000","slowMo":0,"headless":true,"debugport":0,"devtools":false,"cookies":"","name":"","x":560,"y":700,"wires":[["154709dcabda3665"]]},{"id":"fd31bec6c231b081","type":"puppeteer-page-goto","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"LINK","url":"http://192.168.2.190:1880/SUNAMA/#/","urltype":"str","waitUntil":"networkidle2","x":550,"y":620,"wires":[["ea3a006837fad44b"]]},{"id":"8d90b7ca7f7fa064","type":"file","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"SAVE","filename":"/home/tomislav/screenshot.png","filenameType":"str","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":750,"y":620,"wires":[["9a2e152f3ae44413"]]},{"id":"ea3a006837fad44b","type":"puppeteer-page-screenshot","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"","fullpage":false,"x":370,"y":580,"wires":[["ca2986c094642970"]]},{"id":"154709dcabda3665","type":"puppeteer-page-viewport","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"","width":"1920","height":"900","scale":1,"x":560,"y":660,"wires":[["fd31bec6c231b081"]]},{"id":"ca2986c094642970","type":"puppeteer-page-close","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"","x":560,"y":580,"wires":[["c47dcbc7e2d26b5d"]]},{"id":"c47dcbc7e2d26b5d","type":"puppeteer-browser-close","z":"fe70b7069e03e98b","g":"236fa21271b8b8c1","name":"","x":760,"y":580,"wires":[["8d90b7ca7f7fa064"]]}]
2 Likes

Excellent, do you happen to know how to implement that image or screen saved in a PDF? or call it in a pdf structure to be displayed in a report?

The simplest way would be to use --print-to-pdf flag for chromium in the EXEC node:
chromium --headless --disable-gpu --print-to-pdf=/home/tomislav/screenshot.pdf /home/tomislav/screenshot.png

If you want to create actual PDF reports then you would need to use Node-RED template node to create html and then afterwards just convert the html to pdf with the EXEC node.
This is an example of how I've tested it in the previous project:

[{"id":"ca7cdb1e.8a1f48","type":"template","z":"610297ee.5ee3c8","name":"PDF constructor*","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<!DOCTYPE html>\n<head>\n        <meta charset=\"utf-8\">\n        <script type=\"text/javascript\" src=\"file:///home/pi/node_modules/chart.js/dist/Chart.bundle.js\"></script>\n        <script type=\"text/javascript\" src=\"http://192.168.2.191:1880/vega.js\"></script>\n        <script type=\"text/javascript\" src=\"http://192.168.2.191:1880/vega-embed.js\"></script>\n        <script>window.devicePixelRatio = 3;</script>\n</head>\n<script>\n        div {\n          width: 100%;\n          text-align: center;\n        }\n        div p {\n          text-align: center;\n          font-family: \"Arial\", sans-serif;\n          font-size: 14px;\n          color: #bdc3c7;\n        }\n        @media print {\n            .pagebreak { break-after: always; } /* page-break-after works, as well */\n        }\n</script>\n    \n    \n<body>\n    <p><span style=\"color: #008080;\">&nbsp;</span></p>\n    <table style=\"height: 27px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 75%;\"><span style=\"color: #008080;\"><strong>Report</strong></span></td>\n                <td style=\"width: 25%;\"><span style=\"color: #008080;\"><strong><img\n                                style=\"display: block; margin-left: auto; margin-right: auto;\"\n                                src=\"file:///home/pi/.node-red/static/logo.jpg\" width=\"150\" height=\"33\" /></strong></span></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; width: 100%; margin-left: auto; margin-right: auto; border:1px solid #000000;\">\n        <tbody>\n            <tr>\n                <td style=\"width: 15%;\"><span style=\"color: #008080;\"><strong>Machine:</strong></span></td>\n                <td style=\"width: 50%;\"><span style=\"color: #000000; font-size:20px\"><strong>MACHINE 4\n                            (TARGET 3)</strong></span></td>\n                <td style=\"width: 35%;\"><span style=\"color: #008080;\"><strong>Period:</strong>{{{data.Target3.labels.0}}}</span></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; width: 100%; margin-left: auto; margin-right: auto; border:1px solid #000000;\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"><span style=\"color: #008080;\"><strong>Company:</strong></span></td>\n                <td style=\"width: 90%;\"><span style=\"color: #008080;\">___________</span></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 30px; margin-left: auto; margin-right: auto;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 100%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 512.267px;\"><span style=\"color: #008080;\"><strong>Data</strong></span></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"></td>\n                <td style=\"width: 20%;\"><span style=\"color: #008080;\">Total machine work time:</span></td>\n                <td style=\"width: 10%;\"><span style=\"color: #008080;\"><strong>{{{data.Target3.work_total}}}</strong>\n                        h</span></td>\n                <td style=\"width: 60%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"></td>\n                <td style=\"width: 20%;\"><span style=\"color: #008080;\">Total machine service time:</span></td>\n                <td style=\"width: 10%;\"><span style=\"color: #008080;\"><strong>{{{data.Target3.tst_total}}}</strong>\n                        h</span></td>\n                <td style=\"width: 60%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"></td>\n                <td style=\"width: 20%;\"><span style=\"color: #008080;\">Total pieces made:</span></td>\n                <td style=\"width: 10%;\"><span\n                        style=\"color: #008080;\"><strong>{{{data.Target3.pcs_total}}}</strong></span></td>\n                <td style=\"width: 60%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"></td>\n                <td style=\"width: 20%;\"><span style=\"color: #008080;\">Total length made:</span></td>\n                <td style=\"width: 10%;\"><span style=\"color: #008080;\"><strong>{{{data.Target3.leng_total}}}</strong>\n                        m</span></td>\n                <td style=\"width: 60%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 12px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"></td>\n                <td style=\"width: 20%;\"><span style=\"color: #008080;\">Total machine utilization:</span></td>\n                <td style=\"width: 10%;\"><span style=\"color: #008080;\"><strong>{{{data.Target3.util_total}}}</strong>\n                        %</span></td>\n                <td style=\"width: 60%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 30px; margin-left: auto; margin-right: auto;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 100%;\"></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 26px; margin-left: auto; margin-right: auto;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 512.267px;\"><span style=\"color: #008080;\"><strong>Charts</strong></span></td>\n            </tr>\n        </tbody>\n    </table>\n    <table style=\"height: 343px; margin-left: auto; margin-right: auto; border:1px solid #000000;\" width=\"100%\">\n        <tbody>\n            <tr style=\"height: 249px;\">\n                <td style=\"width: 540.8px; height: 1000px; text-align: center;\"><span style=\"color: #008080;\">\n                    <div style = \"text-align:center;\">\n                        <canvas id=\"chartjs\" width=\"1050\" height=\"400\" style=\"margin-top:0px; margin-left:auto; margin-right:auto;\"></canvas>\n                        <canvas id=\"chartjs2\" width=\"1050\" height=\"100\" style=\"margin-top:0px, text-align: center\"></canvas>\n                    </div>\n                    <div id=\"vis\" style=\"height:500px; text-align:center;\"></div>\n                    </span>\n                </td>\n            </tr>\n            \n        </tbody>\n    </table>\n    \n    <table style=\"height: 15px;\" width=\"100%\">\n        <tbody>\n            <tr>\n                <td style=\"width: 10%;\"><strong><span style=\"color: #008080;\">\"Other\": </span></strong><span\n                        style=\"color: #008080;\">Wait for mechanic, Wait for warehouse worker, Preparation of raw\n                        materials, Pallet manipulation, Movex and documentation, Subsequent sheet cutting</span></td>\n            </tr>\n        </tbody>\n    </table>\n    \n    \n    \n    \n    <script>\n        var barChartData_T3_status = {\n            labels: [{{{data.Target3.labels}}}],\n            datasets: [{\n                label: 'Quilting [h]',\n                backgroundColor : \"rgba(48, 179, 30, 0.8)\",\n                borderColor: \"rgba(38, 159, 20, 1)\",\n                borderWidth: 2,               \n                data: [{{data.Target3.work}}]\n            }, {\n                label: 'Other [h]',\n                backgroundColor : \"rgba(163, 163, 163, 0.8)\",\n                borderColor: \"rgba(123, 123, 123, 1)\",\n                borderWidth: 2,\n                data: [{{data.Target3.noth}}]\n            }, {\n                label: 'Quilter service [h]',\n                backgroundColor : \"rgba(255, 127, 14, 0.8)\",\n                borderColor: \"rgba(205, 107, 4, 1)\",\n                borderWidth: 2,\n                data: [{{data.Target3.hands}}]\n            }, {\n                label: 'Overlocker service [h]',\n                backgroundColor : \"rgba(219, 6, 6, 0.8)\",\n                borderColor: \"rgba(149, 0, 0, 1)\",\n                borderWidth: 2,\n                data: [{{data.Target3.door}}]\n            }, {\n                label: 'Both service [h]',\n                backgroundColor : \"rgba(162, 1, 135, 0.8)\",\n                borderColor: \"rgba(122, 0, 115, 1)\",\n                borderWidth: 2,\n                data: [{{data.Target3.both}}]\n            }]\n        };\n\n    </script>\n    <script>\n        window.onload = function() {\n            \n            var ctx = document.getElementById(\"chartjs\").getContext(\"2d\");\n            window.myBar = new Chart(ctx, {\n                type: 'bar',\n                data: barChartData_T3_status,\n                options: {\n                    animation:{\n                        duration: 0\n                    },\n                    title:{\n                        display: true,\n                        text:\"Machine 4 (Target 3) Status\"\n                    },\n                    responsive: false,\n                    maintainAspectRatio: true,\n                    scales: {\n                        xAxes: [{\n                            stacked: true,\n                            barPercentage: 0.4\n                        }],\n                        yAxes: [{\n                            stacked: true,\n                            ticks: {\n                                beginAtZero: true,\n                                steps: 8,\n                                stepValue: 1,\n                                min: 0,\n                                max: 8 \n                            },\n                            gridLines: {\n                                color: \"rgba(75, 75, 75, 1)\",\n                            }\n                        }]\n                    }\n                }\n            });\n        };\n    </script>  \n\n\n    <script type=\"text/javascript\">\n\n    const spec = {{{payload}}}\n        \n  \tvegaEmbed(\"#vis\", spec, {\"actions\": false})\n\n    </script>\n</body>\n","output":"str","x":1910,"y":100,"wires":[["4fa65a3e.7d3c34"]]}]

But thats for another topic

1 Like

Thanks to your flow and this topic I managed to do something similar, yes with puppet but it must be used in chrome for it to work, I attach my example flow for future ideas or help and thank you in advance mate:

flow:

[
    {
        "id": "fa1432119f33bbfb",
        "type": "inject",
        "z": "67c61941.053d58",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 420,
        "y": 1500,
        "wires": [
            [
                "08d8e18d7ce7c0ee"
            ]
        ]
    },
    {
        "id": "08d8e18d7ce7c0ee",
        "type": "puppeteer-browser-launch",
        "z": "67c61941.053d58",
        "timeout": "7000",
        "slowMo": 0,
        "headless": true,
        "debugport": 0,
        "devtools": false,
        "cookies": "",
        "name": "",
        "x": 620,
        "y": 1500,
        "wires": [
            [
                "2671441d86f84188"
            ]
        ]
    },
    {
        "id": "e17eeca2886e7d9e",
        "type": "puppeteer-page-goto",
        "z": "67c61941.053d58",
        "name": "LINK",
        "url": "http://127.0.0.1:1880/ui/#!/21?socketid=H38GHI0t_eSHpxjMAAAL",
        "urltype": "str",
        "waitUntil": "networkidle2",
        "x": 610,
        "y": 1380,
        "wires": [
            [
                "89479f5b9ca016a9"
            ]
        ]
    },
    {
        "id": "89479f5b9ca016a9",
        "type": "puppeteer-page-screenshot",
        "z": "67c61941.053d58",
        "name": "",
        "fullpage": true,
        "x": 130,
        "y": 1240,
        "wires": [
            [
                "363b82550dbd1544",
                "65ba01c8108db452"
            ]
        ]
    },
    {
        "id": "2671441d86f84188",
        "type": "puppeteer-page-viewport",
        "z": "67c61941.053d58",
        "name": "",
        "width": "1920",
        "height": "1000",
        "scale": 1,
        "x": 620,
        "y": 1440,
        "wires": [
            [
                "e17eeca2886e7d9e"
            ]
        ]
    },
    {
        "id": "3749cf6b2b9cbcea",
        "type": "puppeteer-browser-close",
        "z": "67c61941.053d58",
        "name": "",
        "x": 820,
        "y": 1320,
        "wires": [
            [
                "029730d8083b07b0"
            ]
        ]
    },
    {
        "id": "363b82550dbd1544",
        "type": "function",
        "z": "67c61941.053d58",
        "name": "Select Last Value",
        "func": "msg.topic = \"SELECT * FROM plc.oee_kpi ORDER BY Fecha DESC LIMIT 1;\";\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 170,
        "y": 1400,
        "wires": [
            [
                "ba45e10e55eb771c"
            ]
        ]
    },
    {
        "id": "ba45e10e55eb771c",
        "type": "mysql",
        "z": "67c61941.053d58",
        "mydb": "fb05e811b8b0da75",
        "name": "",
        "x": 330,
        "y": 1400,
        "wires": [
            [
                "33f2686f507a65bb"
            ]
        ]
    },
    {
        "id": "33f2686f507a65bb",
        "type": "function",
        "z": "67c61941.053d58",
        "name": "FORMATO DE TABLA",
        "func": "//datatime\nvar time = new Date().toLocaleString(\"co\");\nvar imagePath = global.get('image')\n\n\t// Ahora 'data' contiene el contenido de la imagen en un Buffer\n\n//Average/Valor Promedio\nvar a = msg.payload[0][\"Tipodefalla\"];\nvar b = msg.payload[0][\"Turno\"];\nvar c = msg.payload[0][\"Tiemposdeparada\"];\nvar d = msg.payload[0][\"Tiemposdereparacion\"];\nvar e = msg.payload[0][\"Tiempodearranque\"];\n\n\n\nmsg.payload = {\n\tpageOrientation: 'LANDSCAPE',\n\tcontent: [\n\t\t{\n\t\t\timage: 'data:image/jpeg;base64,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',\n\t\twidth:50},\n\t\t{text: 'Curso: Interfaz MySQL con PLC vía Node-RED', style: 'header'},\n\t\t{text: 'Tema: Generación de Informes en pdf', style: 'header'},\n\t\t{text:'Reporte generado el: '+time+' \\n\\n' },\n\t\t\n\t\t'Ahora puede generar informes personalizados de sus datos en Node-RED. Este es solo un informe de muestra generado para explicar la función. Se puede personalizar el informe según sus preferencias.',\n\t\t{text: 'Valores del mundo real de la tabla de la base de datos MySQL llamada `plc.tanklevel`', style: 'subheader'},\n\t\t'La siguiente tabla muestra los valores provenientes del PLC',\n\t\n\t    {text: 'Valores PLC', style: 'subheader'},\n\t\t{\n\t\t\tstyle: 'tableExample',\n\t\t\ttable: {\n\t\t\t\tbody: [\n\t\t\t\t\t[{text:'OEE_ME', style: 'tableHeader'}, {text:'RECHAZO', style: 'tableHeader'}, {text:'ENERGIA_ACTUAL', style: 'tableHeader'}, {text:'AIRE_ACTUAL', style: 'tableHeader'},{text:'GAS_ACTUAL', style: 'tableHeader'}],\n\t\t\t\t\t[\"\"+a+\"\", \"\"+b+\"\", \"\"+c+\"\",\"\"+d+\"\",\"\"+e+\"\"]\n\n\t\t\t\t\n\t\t\t\t]\n\t\t\t},\n\t\t\t\n\t\t},\n\t\t{\n\t\t\timage: 'data:image/jpeg;base64,\"'+imagePath+'\"',\n\t\t\twidth: 700\n\t\t},\n\t\t\t\t\t\t\n\t\t\n\t\t\n\t\t\n\t\t{text: 'Hardware usado', style: 'subheader'},\n\t    {\n\t\t\tul: [\n\t\t\t\t{text: 'Siemens S7-1200 con OPC UA'},\n\t\t\t\t{text: 'PLC Ethernet cable'},\n\t\t\t\t{text: '24VDC Power supply'},\n\t\t\t]\n\t\t},\n\t\t\n\t\t\t{text: 'Software usado', style: 'subheader'},\n\t    {\n\t\t\tul: [\n\t\t\t\t{text: 'TIA Portal v17'},\n\t\t\t\t{text: 'IOT', color: 'purple'},\n\t\t\t\t//{text: 'Prototipo'},\n\t\t\t]\n\t\t},\n\t\t\n\t\t/*{text: 'Visítenos (Hipervinculado)', style: 'header'},\n\t\t{\n\t\t\tul: [\n\t\t\t\t//{text: 'Escuela de aprendizaje electrónico', color: 'purple' ,link: 'http://learn.codeandcompile.com' },\n\t\t\t\t{text: 'YouTube', color: 'purple', link: 'https://www.youtube.com/channel/UC4rqWPxMnjbOAhKfbse-5Wg/featured' },\n\t\t\t\t{text: 'Instagram', color: 'purple', link: '' },\n\t\t\t]\n\t\t},*/\n\t\t\t{\n\t\t\ttext: '\\n Este documento se genera únicamente con fines de capacitación. Los datos dentro de este documento no provienen de ninguna fuente comprometida. Para cualquier información contactar con Soporte',\n\t\t\tstyle: ['quote', 'small']\n\t\t}\n\n\n    ],\n    \tstyles: {\n\t\theader: {\n\t\t\tfontSize: 18,\n\t\t\tbold: true,\n\t\t\tmargin: [0, 0, 0, 10]\n\t\t\t\n\t\t},\n\t\tsubheader: {\n\t\t\tfontSize: 16,\n\t\t\tbold: true,\n\t\t\tmargin: [0, 10, 0, 5]\n\t\t},\n\t\ttableExample: {\n\t\t\tmargin: [0, 5, 0, 15],\n\t\t\talignment: 'center'\n\t\t},\n\t\ttableHeader: {\n\t\t\tbold: true,\n\t\t\tfontSize: 13,\n\t\t\tcolor: 'black'\n\t\t},\n\t\t\tquote: {\n\t\t\titalics: true\n\t\t}\n    \t}\n};\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 400,
        "y": 1240,
        "wires": [
            [
                "0666a43e7b8d954e"
            ]
        ]
    },
    {
        "id": "029730d8083b07b0",
        "type": "file",
        "z": "67c61941.053d58",
        "name": "",
        "filename": "C:\\Users\\Cristian Torres\\Desktop\\Reportes\\Informe.pdf",
        "filenameType": "str",
        "appendNewline": true,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1000,
        "y": 1240,
        "wires": [
            []
        ]
    },
    {
        "id": "0666a43e7b8d954e",
        "type": "pdfmake",
        "z": "67c61941.053d58",
        "name": "",
        "outputType": "Buffer",
        "inputProperty": "payload",
        "options": "{}",
        "outputProperty": "payload",
        "x": 660,
        "y": 1240,
        "wires": [
            [
                "029730d8083b07b0"
            ]
        ]
    },
    {
        "id": "585ccd1f08c8c921",
        "type": "function",
        "z": "67c61941.053d58",
        "name": "function 199",
        "func": "global.set('image', msg.payload)\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 450,
        "y": 1200,
        "wires": [
            []
        ]
    },
    {
        "id": "65ba01c8108db452",
        "type": "base64",
        "z": "67c61941.053d58",
        "name": "",
        "action": "",
        "property": "payload",
        "x": 260,
        "y": 1200,
        "wires": [
            [
                "585ccd1f08c8c921"
            ]
        ]
    },
    {
        "id": "fb05e811b8b0da75",
        "type": "MySQLdatabase",
        "name": "",
        "host": "127.0.0.1",
        "port": "3306",
        "db": "plc",
        "tz": "",
        "charset": "UTF8"
    }
]