RedMatic Update 7.3.5

Node-RED als CCU3/RaspberryMatic Addon, WebApp, HomeKit, ...

Moderator: Co-Administratoren

Benutzeravatar
Henke
Beiträge: 1538
Registriert: 27.06.2022, 20:51
System: CCU
Hat sich bedankt: 144 Mal
Danksagung erhalten: 312 Mal

Re: RedMatic Update 7.3.5

Beitrag von Henke » 19.01.2024, 18:19

Jetzt unter Tools "npm npm@latest"
Die node.js wird aktuell noch nicht aktualisiert, siehe ein paar Post vorher. Einfach mal alle paar Tage auf "Check/Install node.js" drücken.

hkolb
Beiträge: 14
Registriert: 08.01.2024, 11:43
System: sonstige

Re: RedMatic Update 7.3.5

Beitrag von hkolb » 19.01.2024, 20:19

Code: Alles auswählen

added 1 package in 12s
und jetzt zeit der Flow "npm Doctor":

Code: Alles auswählen

Check                               Value   Recommendation/Notes
npm ping                            ok       
npm -v                              ok      current: v10.3.0, latest: v10.3.0
node -v                             not ok  Use node v20.11.0 (current: v20.10.0)
npm config get registry             ok      using default registry (https://registry.npmjs.org/)
git executable in PATH              ok      /usr/local/addons/redmatic/bin/git
global bin folder in PATH           ok      /usr/local/bin
Perms check on cached files         ok       
Perms check on local node_modules   ok       
Perms check on global node_modules  ok       
Perms check on local bin folder     ok       
Perms check on global bin folder    ok       
Verify cache contents               ok      verified 3 tarballs
UNGLAUBLICH!!!!!!!
Damit hätte ich nach diesem Marathon nicht mehr gerechnet!!!

VIELEN DANK Henke! Auch für deine Hartnäckigkeit und Ausdauer!
Phänomenal wenn Probleme deutlich schneller und zuverlässiger gelöst werden als bei Kauf-Software!

Matten Matten
Beiträge: 286
Registriert: 09.12.2018, 17:14
System: CCU
Hat sich bedankt: 70 Mal
Danksagung erhalten: 24 Mal
Kontaktdaten:

Re: RedMatic Update 7.3.5

Beitrag von Matten Matten » 19.01.2024, 20:55

bei meinem testsystem aktualisiert er node.js auch nicht. er saggt zwar er installiert die neue jeoch nach npm doctor ist immer noch die 18er version installiert. auch nach einen reboot noch

via console

Code: Alles auswählen

root@homematic-asus:/usr/local# npm install -g  node@20.10.0
npm ERR! code 1
npm ERR! path /usr/local/lib/node_modules/node
npm ERR! command failed
npm ERR! command sh -c node installArchSpecificPackage
npm ERR! npm ERR! code E404
npm ERR! npm ERR! 404 Not Found - GET https://registry.npmjs.org/node-linux-arm - Not found
npm ERR! npm ERR! 404
npm ERR! npm ERR! 404  'node-linux-arm@20.10.0' is not in this registry.
npm ERR! npm ERR! 404
npm ERR! npm ERR! 404 Note that you can also install from a
npm ERR! npm ERR! 404 tarball, folder, http url, or git url.
npm ERR!
npm ERR! npm ERR! A complete log of this run can be found in: /tmp/npm-cache/_logs/2024-01-19T20_32_17_060Z-debug-0.log
npm ERR! node:internal/modules/cjs/loader:1080
npm ERR!   throw err;
npm ERR!   ^
npm ERR!
npm ERR! Error: Cannot find module 'node-linux-arm/package.json'
npm ERR! Require stack:
npm ERR! - /usr/local/lib/node_modules/node/installArchSpecificPackage.js
npm ERR!     at Module._resolveFilename (node:internal/modules/cjs/loader:1077:15)
npm ERR!     at Function.resolve (node:internal/modules/cjs/helpers:125:19)
npm ERR!     at ChildProcess.<anonymous> (/usr/local/lib/node_modules/node/node_modules/node-bin-setup/index.js:19:27)
npm ERR!     at ChildProcess.emit (node:events:517:28)
npm ERR!     at maybeClose (node:internal/child_process:1098:16)
npm ERR!     at ChildProcess._handle.onexit (node:internal/child_process:303:5) {
npm ERR!   code: 'MODULE_NOT_FOUND',
npm ERR!   requireStack: [ '/usr/local/lib/node_modules/node/installArchSpecificPackage.js' ]
npm ERR! }
npm ERR!
npm ERR! Node.js v18.18.2

npm ERR! A complete log of this run can be found in: /tmp/npm-cache/_logs/2024-01-19T20_32_11_641Z-debug-0.log


Benutzeravatar
Henke
Beiträge: 1538
Registriert: 27.06.2022, 20:51
System: CCU
Hat sich bedankt: 144 Mal
Danksagung erhalten: 312 Mal

Re: RedMatic Update 7.3.5

Beitrag von Henke » 20.01.2024, 04:48

Da jetzt die Installationen nur über npm laufen sollte eigentlich auch das richtige BS gefunden werden.
Daher kam der Hinweis: "Könnte auf der Standard CCU laufen.".
Matten Matten hat geschrieben:
19.01.2024, 20:55
bei meinem testsystem aktualisiert er node.js auch nicht.
Bei den beiden vorherigen Problemen wurde es aktualisiert auf 20.10.0.
Das auch verstehe ich daher nicht.

Nutze bitte mal den optimierten flow:

Code: Alles auswählen

[
    {
        "id": "0ea2818262334c44",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "RedMatic aufräumen",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "#!/bin/sh\ncd /usr/local/addons/redmatic/var\nsource /usr/local/addons/redmatic/home/.profile\nmkdir -m a+rwx -p /usr/local/lib/node_modules\nmkdir -m a+rwx -p /usr/local/bin\n# npm config set cache=/tmp/npm-cache\n\nrm /usr/local/addons/redmatic/etc/npmrc 2>/dev/null\n# rm /usr/local/addons/redmatic/bin/jq 2>/dev/null\n# rm /usr/local/addons/redmatic/bin/jo 2>/dev/null\nrm /usr/local/addons/redmatic/bin/deviceTypes 2>/dev/null\nrm /usr/local/addons/redmatic/bin/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/include/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/lib/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/libexec/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/share/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/tmp/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/var/node_modules/.nobackup 2>/dev/null\nrm /usr/local/addons/redmatic/www/.nobackup 2>/dev/null\n\nrm /usr/local/addons/redmatic/lib/pkg-repo.json 2> /dev/null\nrm /usr/local/addons/redmatic/CHANGELOG.md 2> /dev/null\nrm /usr/local/addons/redmatic/LICENSE 2> /dev/null\nrm /usr/local/addons/redmatic/README.md 2> /dev/null\n\nrm /usr/local/addons/redmatic/bin/corepack 2> /dev/null\nrm /usr/local/addons/redmatic/bin/node 2> /dev/null\nrm /usr/local/addons/redmatic/bin/npm 2> /dev/null\nrm /usr/local/addons/redmatic/bin/npx 2> /dev/null\nrm -r /usr/local/addons/redmatic/lib/node_modules/npm 2> /dev/null\nrm -r /usr/local/addons/redmatic/lib/node_modules/corepack 2> /dev/null\nrm -r /usr/local/addons/redmatic/lib/node_modules/ain2 2> /dev/null\nexit 0",
        "output": "str",
        "x": 480,
        "y": 480,
        "wires": [
            [
                "2d6177b5c2a97ca9"
            ]
        ]
    },
    {
        "id": "fa72f43dd0a8948b",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "logger.js",
        "field": "payload",
        "fieldType": "msg",
        "format": "javascript",
        "syntax": "plain",
        "template": "// Henke Version 1.2\n\nvar dgram = require('dgram');\n//var iconvLite= require('iconv-lite');\n//var exec = require('child_process').exec;\n\nmodule.exports = {\n    logging: {\n        //                console: {\n        //                    level: \"error\",\n        //                    metrics: false,\n        //                    audit: false\n        //                },\n        ain: {\n            //            level: 'debug',\n            //            metrics: false,\n            //            audit: false,\n            handler: function (conf) {\n                //console.log(\"----\");\n                //console.log(conf);\n                //console.log(\"----\");\n\n                // Return the function that will do the actual logging\n                return function (mg) {\n                    const levelNames = {\n                        10: { s: 2, t: 'crit' }, // fatal\n                        20: { s: 3, t: 'err' },\n                        30: { s: 4, t: 'warn' },\n                        40: { s: 6, t: 'info' },\n                        50: { s: 7, t: 'debug' },\n                        60: { s: 7, t: 'trace' },  // trace\n                        98: { s: 7, t: 'audit' }, // audit\n                        99: { s: 7, t: 'metric' } // metric\n                    };\n\n                    if (mg && typeof mg.msg != 'string') {\n                        mg.msg = JSON.stringify(mg.msg);\n                    }\n                    let tagStr = \"NodeRed\";\n                    // let b = Buffer.from(_msg.msg);\n                    // _msg.msg = Buffer.from(b.toString('utf8')).toString('ascii');\n                    // _msg.msg =iconvLite.decode(iconvLite.decode(_msg.msg , 'utf8'), 'latin1');\n                    if (mg.type) {\n                        let mName = (mg.name || mg.id);\n                        //                        mName = mName.replaceAll(/\\W/g, \"_\");\n                        //                        mName = mName.replaceAll(/[\\s><\\[\\]]/g, \"_\");\n\n                        let patt = new RegExp(\"[\\\\s><\\\\[\\\\]]\", \"g\");\n                        mName = mName.replace(patt, \"_\");\n                        tagStr = mg.type + '[' + mName + ']';\n                    }\n                    let patt = new RegExp(\"\\n\", \"g\");\n                    mg.msg = mg.msg.replace(patt, \"\");\n                    // _msg.msg = _msg.msg.replaceAll(/\\n/g, \"\");\n\n                    //                    const Out = 'logger -t ' + tagStr + ' -p daemon.' + levelNames[_msg.level].t + ' ' + _msg.msg;\n                    //                    exec(Out);\n                    //                    return;\n\n                    // Alternativ über Socket, dann die oberen 3 Zeilen auskommentieren\n                    // converts number to two-digit string\n                    function twoDigits(n) {\n                        return ('0' + n).slice(-2);\n                    }\n\n                    let time = new Date(mg.timestamp);\n                    const MONTHS = [\n                        'Jan',\n                        'Feb',\n                        'Mar',\n                        'Apr',\n                        'May',\n                        'Jun',\n                        'Jul',\n                        'Aug',\n                        'Sep',\n                        'Oct',\n                        'Nov',\n                        'Dec'\n                    ];\n\n                    // format time\n                    let month = MONTHS[time.getMonth()];\n                    let date = twoDigits(time.getDate());\n                    let hours = twoDigits(time.getHours());\n                    let minutes = twoDigits(time.getMinutes());\n                    let seconds = twoDigits(time.getSeconds());\n\n                    // format('%s %s %s:%s:%s'\n                    let timeStr = month + ' ' + date + ' ' + hours + \":\" + minutes + \":\" + seconds;\n                    //                                        console.log(\"---> \" + _msg.level + \" \" + levelNames[_msg.level].s + \" \" + levelNames[_msg.level].t + \" \" + _msg.msg);\n\n                    let PRI = (1 * 8) + levelNames[mg.level].s ;\n//                    console.log( \"Err Level: \" + mg.level + \" \" + levelNames[mg.level].s + \" \" + mg.msg);\n\n                    let message = \"<\" + PRI + \">\" + timeStr + \" NodeRed\" + \" \" + tagStr + \": \" + mg.msg;\n                    try {\n                        var port = 514;\n                        if (mg.level < 30)\n                            console.log(mg.msg);\n\n                        var Udp = dgram.createSocket('udp4');\n                        const out = Buffer.from(message);\n                        Udp.connect(port, '127.0.0.1', (err) => {\n                            Udp.send(out, (err) => {\n                                Udp.close();\n                            });\n                        });\n\n                        //                console.log(\"Logger connected\");\n                        //                        console.log(message);\n                        //                        console.log(JSON.stringify(msg));\n                    } catch (err) { console.log( \"catch: \" + err); }\n                }\n            }\n        }\n    }\n};\n",
        "output": "str",
        "x": 440,
        "y": 220,
        "wires": [
            [
                "21eee2220ba31f6a"
            ]
        ]
    },
    {
        "id": "21eee2220ba31f6a",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "lib/logger.js",
        "filename": "/usr/local/addons/redmatic/lib/logger.js",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 690,
        "y": 220,
        "wires": [
            [
                "b4e4431204918796"
            ]
        ]
    },
    {
        "id": "b4e4431204918796",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "service.cgi",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "# Henke Version 1.0\n#!/bin/tclsh\n\nsource ../lib/querystring.tcl\n\nputs -nonewline \"Content-Type: text/plain; charset=utf-8\\r\\n\\r\\n\"\n\nif {[info exists cmd]} {\n\n    if {$cmd == \"stop\" || $cmd == \"start\" || $cmd == \"restart\"} {\n\n        source ../lib/session.tcl\n\n        if {[info exists sid] && [check_session $sid]} {\n            catch {exec /usr/local/etc/config/rc.d/redmatic $cmd} result\n            puts $result\n            exit 0\n        } else {\n            puts {error: invalid session}\n            exit 1\n        }\n    }\n\n    # No session checks for following commands to reduce costs of periodic calls, exposed information is uncritical imho\n\n    if {$cmd == \"ps\"} {\n#        puts [exec ps -o vsz,rss,comm,args | grep \"node\\\\|redmatic\"]\n# Henke Anpassung an neuere Node\n        puts [exec ps -o vsz,rss,comm,args | grep \"node-red\\\\|node-red\" ]\n        exit 0\n    }\n    if {$cmd == \"cpu\"} {\n        puts [exec top -b -n 1 | grep \"% node-red$\" | awk \"\\{print \\$7\\}\"]\n#       puts [exec ps -o vsz,rss,comm,args | grep \"node\\\\|redmatic\" ]\n       exit 0\n    }\n    if {$cmd == \"uptime\"} {\n        puts [exec /usr/local/addons/redmatic/bin/uptime.sh]\n        exit 0\n    }\n}\n\nputs {error: invalid command}\nexit 1\n",
        "output": "str",
        "x": 970,
        "y": 220,
        "wires": [
            [
                "a0554d8f2b842c0b"
            ]
        ]
    },
    {
        "id": "a0554d8f2b842c0b",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "www/service.cgi",
        "filename": "/usr/local/addons/redmatic/www/service.cgi",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1180,
        "y": 220,
        "wires": [
            [
                "a0ee823d1b868b33"
            ]
        ]
    },
    {
        "id": "3d2fc855a49dc0ab",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "script.js",
        "field": "payload",
        "fieldType": "msg",
        "format": "javascript",
        "syntax": "plain",
        "template": "// Henke Version 1.2\n$(document).ready(() => {\n    const bcrypt = dcodeIO.bcrypt;\n\n    const $loglevel = $('#loglevel');\n    const $contextStorageDefault = $('#context-storage-default');\n    const $contextStorageFilePath = $('#context-storage-file-path');\n    const $contextStorageFileInterval = $('#context-storage-file-interval');\n\n    const $adminauthType = $('#adminauth-type');\n    const $adminauthCreds = $('#adminauth-credentials');\n    const $adminauthExpiry = $('#adminauth-expiry');\n    const $adminauthSessionExpiryTime = $('#adminauth-sessionExpiryTime');\n    const $adminauthUser = $('#adminauth-user');\n    const $adminauthPass1 = $('#adminauth-pass1');\n    const $adminauthPass2 = $('#adminauth-pass2');\n    const $adminauthSet = $('#adminauth-set');\n\n    const $nodeauthType = $('#nodeauth-type');\n    const $nodeauthCreds = $('#nodeauth-credentials');\n    const $nodeauthUser = $('#nodeauth-user');\n    const $nodeauthPass1 = $('#nodeauth-pass1');\n    const $nodeauthPass2 = $('#nodeauth-pass2');\n    const $nodeauthSet = $('#nodeauth-set');\n\n    const $staticauthType = $('#staticauth-type');\n    const $staticauthCreds = $('#staticauth-credentials');\n    const $staticauthUser = $('#staticauth-user');\n    const $staticauthPass1 = $('#staticauth-pass1');\n    const $staticauthPass2 = $('#staticauth-pass2');\n    const $staticauthSet = $('#staticauth-set');\n\n    const $projects = $('#projects');\n    const $theme = $('#theme');\n    const $backup = $('#backup');\n\n    const $alertSaved = $('#alert-saved');\n    const $alertError = $('#alert-error');\n    const $alertExec = $('#alert-exec');\n\n    const $status = $('#node-red-status');\n    const $memory = $('#node-red-memory');\n    const $cpu = $('#node-red-cpu');\n\n    $alertSaved.hide();\n    $alertError.hide();\n    $alertExec.hide();\n\n    const $restart = $('#restart');\n    const $restartSafe = $('#restartSafe');\n    const $dropdownRestart = $('#dropdownRestart');\n    const $start = $('#start');\n    const $startSafe = $('#startSafe');\n    const $dropdownStart = $('#dropdownStart');\n    const $stop = $('#stop');\n\n    const $linkRed = $('#link-red');\n    const $linkUi = $('#link-ui');\n\n    const $packageTable = $('#package-table');\n\n    let config;\n\n    let noderedState;\n\n    const qs = location.search;\n    let sid = '';\n    let tmp = qs.match(/sid=(@[0-9a-zA-Z]{10}@)/);\n    if (tmp) {\n        sid = tmp[1];\n        $('#backup').removeClass('disabled').attr('href', 'backup.cgi?sid=' + sid);\n    }\n\n    $('a[href=\"' + (location.hash || '#configuration') + '\"]').tab('show');\n    if (location.hash === '#licenses' && !$('#licenses iframe').attr('src')) {\n        $('#licenses iframe').attr('src', 'licenses.html');\n    }\n\n    $('a[data-toggle=\"tab\"]').on('shown.bs.tab', function (e) {\n        if (history.pushState) {\n            history.pushState(null, null, '#' + $(e.target).attr('href').substr(1));\n        } else {\n            location.hash = '#' + $(e.target).attr('href').substr(1);\n        }\n        if ($(e.target).attr('href') === '#licenses' && !$('#licenses iframe').attr('src')) {\n            $('#licenses iframe').attr('src', 'licenses.html');\n        }\n    });\n\n    let psTimeout;\n    let psInterval = 5000;\n\n    function checkUpdate() {\n        $.getJSON(`update_check.cgi?cmd=versions&sid=${sid}`, (current, success) => {\n            $('#redmatic-version').html('RedMatic Version ' + current.redmatic);\n            $.get(`update_check.cgi?sid=${sid}`, (available, success) => {\n                available = $.trim(available);\n                if (available !== 'n/a' && current.redmatic !== available) {\n                    $('#update-link').html(`<a href=\"https://github.com/rdmtc/RedMatic/releases/latest\" target=\"_blank\">Download Version ${available}</a>`);\n                    $('#update-notify').show();\n                }\n            });\n        });\n    }\n\n    //    checkUpdate();\n\n    function pkg() {\n        let packages;\n        $.get(`pkg.cgi?sid=${sid}&cmd=repo`, data => {\n            packages = data;\n            $.get(`pkg.cgi?sid=${sid}&cmd=ls`, data => {\n                $('#pkg-spinner').hide();\n                data.split('\\n').forEach(line => {\n                    const [name, currentVersion] = line.split(' ');\n                    if (name && packages[name]) {\n                        packages[name].installed = true;\n                        packages[name].currentVersion = currentVersion;\n                    }\n                });\n                $packageTable.html('');\n                Object.keys(packages).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).forEach(name => {\n                    const installed = packages[name].installed ?\n                        (packages[name].version === packages[name].currentVersion ? '✅' : `⚠${packages[name].currentVersion}`) :\n                        '&nbsp;';\n\n                    let url = packages[name].homepage || (packages[name].repository && packages[name].repository.url) || packages[name].repository;\n                    if (url) {\n                        url = url.replace(/^git\\+/, '').replace(/\\.git$/, '');\n                    }\n\n                    $packageTable.append(`<tr><td><a href=\"${url}\" target=\"_blank\">${name}</a><br><span class=\"pkg-desc\">${packages[name].description || ''}</span></td><td>${packages[name].version}</td><td style=\"text-align: center;\">${installed}</td><td><button data-pkg=\"${name}\" type=\"button\" class=\"btn btn-primary btn-sm pkg-install\" ${packages[name].installed ? 'disabled' : ''}><span class=\"spinner-install spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\" hidden></span>\n  install</button> <button data-pkg=\"${name}\" type=\"button\" class=\"btn btn-danger btn-sm pkg-remove\" ${packages[name].installed ? '' : 'disabled'}><span class=\"spinner-remove spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\" hidden></span>\n  remove</button></td></tr>`)\n                });\n                $('.pkg-install').click(function () {\n                    $(this).attr('disabled', true);\n                    $(this).find('.spinner-install').removeAttr('hidden');\n                    $.get(`pkg.cgi?sid=${sid}&cmd=install&package=${$(this).data('pkg')}`, (data, success) => {\n                        $(this).find('.spinner-install').attr('hidden', true);\n                        if (data.includes('Done.')) {\n                            alert($alertExec);\n                        } else {\n                            alert($alertError);\n                        }\n                        pkg();\n                    });\n                });\n                $('.pkg-remove').click(function () {\n                    $(this).attr('disabled', true);\n                    $(this).find('.spinner-remove').removeAttr('hidden');\n                    $.get(`pkg.cgi?sid=${sid}&cmd=remove&package=${$(this).data('pkg')}`, (data, success) => {\n                        $(this).find('.spinner-remove').attr('hidden', true);\n                        if (data.includes('Done.')) {\n                            alert($alertExec);\n                        } else {\n                            alert($alertError);\n                        }\n                        pkg();\n                    });\n                })\n            });\n        });\n    }\n\n    pkg();\n\n    function refresh() {\n        //        checkUpdate();\n        //        pkg();\n    }\n\n    function cpu() {\n        $.get(`service.cgi?sid=${sid}&cmd=cpu`, (data, success) => {\n            data = $.trim(data);\n            $cpu.html((data ? 'cpu ' + data + ', ' : ''));\n        });\n    }\n\n    function ps() {\n        clearTimeout(psTimeout);\n        $.get(`service.cgi?sid=${sid}&cmd=ps`, (data, success) => {\n            cpu();\n            const lines = data.split('\\n');\n            let found = false;\n            lines.forEach(line => {\n                if (found) {\n                    return;\n                }\n                let match;\n                match = line.match(/([0-9]+[a-z]?)\\s+([0-9]+[a-z]?)\\s+node\\s+node-red/);\n                // Henke - Anpassung an neuere Node Versionen\n                if (!match)\n                    match = line.match(/([0-9]+[a-z]?)\\s+([0-9]+[a-z]?)\\s+node-red\\s+node-red/);\n                if (match) {\n                    let [vsz, rss] = line.split(\" \");\n                    vsz = vsz.replace('m', 'MB').replace('g', 'GB');\n                    rss = rss.replace('m', 'MB').replace('g', 'GB');\n                    if (!vsz.endsWith('B')) {\n                        vsz += 'kB';\n                    }\n                    if (!rss.endsWith('B')) {\n                        rss += 'kB';\n                    }\n                    $('#status-spinner').hide();\n                    if (noderedState !== 'running') {\n                        $status.html('<span class=\"status-running\">running</span>');\n                        noderedState = 'running';\n                        refresh();\n                        $.get(`service.cgi?sid=${sid}&cmd=uptime`, (uptime, success) => {\n                            $status.html('<span class=\"status-running\">running</span> <span id=\"uptime\">(' + $.trim(uptime) + ')');\n                        });\n                    }\n                    $memory.html(`rss ${rss}, vsz ${vsz},`);\n                    //                    $memory.html(line.split(\" \"));\n\n                    found = true;\n                    $dropdownRestart.removeClass('disabled');\n                    $stop.removeClass('disabled');\n                    $linkRed.removeClass('disabled');\n                    $linkUi.removeClass('disabled');\n                    $dropdownStart.addClass('disabled');\n                    psInterval = 5000;\n                    return;\n                }\n                match = line.match(/([0-9]+[a-z]?)\\s+([0-9]+[a-z]?)\\s+.*red.js/);\n                if (match) {\n                    noderedState = 'starting';\n                    $('#status-spinner').show();\n                    let [, vsz, rss] = match;\n                    vsz = vsz.replace('m', 'MB').replace('g', 'GB');\n                    rss = rss.replace('m', 'MB').replace('g', 'GB');\n                    if (!vsz.endsWith('B')) {\n                        vsz += 'kB';\n                    }\n                    if (!rss.endsWith('B')) {\n                        rss += 'kB';\n                    }\n                    $status.html('<span class=\"status-starting\">starting</span>');\n                    $memory.html(`rss ${rss}, vsz ${vsz}`);\n                    found = true;\n                    $dropdownRestart.addClass('disabled');\n                    $stop.addClass('disabled');\n                    $dropdownStart.addClass('disabled');\n                    $linkRed.addClass('disabled');\n                    $linkUi.addClass('disabled');\n                    psInterval = 2500;\n                    return;\n                }\n\n                /*                match = line.match(/redmatic-pkg install ([^\\s]+)/);\n                                if (match) {\n                                    noderedState = 'upgrading';\n                                    $('#status-spinner').show();\n                                    $status.html('<span class=\"status-upgrade\">Upgrading ' + match[1] + '</span>');\n                                    $memory.html('');\n                                    found = true;\n                                    $dropdownRestart.addClass('disabled');\n                                    $stop.addClass('disabled');\n                                    $dropdownStart.addClass('disabled');\n                                    $linkRed.addClass('disabled');\n                                    $linkUi.addClass('disabled');\n                                    psInterval = 5000;\n                                    return;\n                                }*/\n            });\n            if (!found) {\n                noderedState = 'stopped';\n                $('#status-spinner').hide();\n                $status.html('<span class=\"status-stopped\">stopped</span>');\n                $memory.html('');\n                $dropdownRestart.addClass('disabled');\n                $stop.addClass('disabled');\n                $dropdownStart.removeClass('disabled');\n                $linkRed.addClass('disabled');\n                $linkUi.addClass('disabled');\n                psInterval = 5000;\n            }\n            psTimeout = setTimeout(ps, psInterval);\n        });\n    }\n\n    ps();\n\n    function alert($elem, timeout = 1600) {\n        $elem.show();\n        $elem.addClass('show');\n        setTimeout(() => {\n            $elem.removeClass('show');\n            setTimeout(() => {\n                $elem.hide();\n            }, 200);\n        }, timeout);\n    }\n\n    function invalidSession() {\n        $('#invalidSession').show();\n        clearTimeout(psTimeout);\n    }\n\n    function save() {\n        console.log('save', config)\n        $.post({\n            url: 'setconfig.cgi' + location.search,\n            data: JSON.stringify(config, null, '  '),\n            success: function (data) {\n                if ($.trim(data) === 'ok') {\n                    alert($alertSaved);\n                } else {\n                    if ($.trim(data) === 'error: invalid session') {\n                        invalidSession();\n                        return;\n                    }\n                    alert($alertError);\n                }\n            }\n        }).fail(() => {\n            alert($alertError);\n        });\n    }\n\n    $.get('getnick.cgi' + location.search, (data, success) => {\n        if ($.trim(data) === 'error: invalid session') {\n            invalidSession();\n            return;\n        }\n        const nick = $.trim(data);\n        if (nick) {\n            $('#nickname').val(nick);\n            $('#log-upload').removeClass('disabled');\n        }\n    });\n\n    $('#nickname').change(() => {\n        const nick = $.trim($('#nickname').val());\n        if (nick) {\n            $('#log-upload').removeClass('disabled');\n        } else {\n            $('#log-upload').addClass('disabled');\n        }\n    });\n\n    $.get('getconfig.cgi' + location.search, (data, success) => {\n        if ($.trim(data) === 'error: invalid session') {\n            invalidSession();\n            return;\n        }\n        config = JSON.parse(data);\n        $loglevel.val(config.logging.ain.level);\n\n        if (config.adminAuth) {\n            $adminauthSessionExpiryTime.val(config.adminAuth.sessionExpiryTime || '604800');\n            $adminauthType.val(config.adminAuth.type);\n            if (config.adminAuth.type === 'credentials') {\n                $adminauthCreds.show();\n                $adminauthExpiry.show();\n                $adminauthUser.val(config.adminAuth.users[0].username);\n\n            }\n            /* else if (config.adminAuth.type === 'rega') {\n                            $adminauthExpiry.show();\n                        }*/\n        }\n\n        if (config.httpNodeAuth) {\n            $nodeauthType.val('basic');\n            $nodeauthCreds.show();\n            $nodeauthUser.val(config.httpNodeAuth.user);\n        }\n\n        if (config.httpStaticAuth) {\n            $staticauthType.val('basic');\n            $staticauthCreds.show();\n            $staticauthUser.val(config.httpStaticAuth.user);\n        }\n\n        if (!config.contextStorage) {\n            config.contextStorage = {};\n        }\n        if (!config.contextStorage.default || !config.contextStorage.default.module) {\n            config.contextStorage.default = { module: 'memory' };\n        }\n        if (!config.contextStorage.memory) {\n            config.contextStorage.memory = {\n                'module': 'memory'\n            };\n        }\n        if (!config.contextStorage.file) {\n            config.contextStorage.file = {\n                'module': 'localfilesystem'\n            };\n        }\n\n        if (!config.contextStorage.file.config) {\n            config.contextStorage.file.config = {\n                dir: '/usr/local/addons/redmatic/var',\n                flushInterval: 30\n            }\n        }\n\n        if (!config.editorTheme) {\n            config.editorTheme = {};\n        }\n        if (!config.editorTheme.projects) {\n            config.editorTheme.projects = {};\n        }\n        config.editorTheme.projects.enabled = config.editorTheme.projects.enabled || false;\n\n        $projects.val(String(config.editorTheme.projects.enabled));\n\n        if (config.editorTheme.projects.enabled) {\n            $projects.prop('disabled', true);\n        }\n\n        if (config.editorTheme.theme) {\n            $theme.val(config.editorTheme.theme);\n        }\n\n        // Migration from 1.x to 2.x\n        if (config.contextStorage.default && config.contextStorage.default.module === 'localfilesystem') {\n            config.contextStorage.default.module = 'file';\n        }\n\n        config.contextStorage.default.module = config.contextStorage.default.module || 'memory';\n\n        updateContextTitle();\n\n        $contextStorageDefault.val(config.contextStorage.default.module);\n\n        $contextStorageFilePath.val(config.contextStorage.file.config.dir);\n        $contextStorageFileInterval.val(config.contextStorage.file.config.flushInterval);\n\n        $('#autorestart').val(config.restartOnCrash);\n        $('#backup').val(config.ccuBackup || 'full');\n    });\n\n    $loglevel.change(() => {\n        config.logging.ain.level = $loglevel.val();\n        save();\n    });\n\n    function updateContextTitle() {\n        switch (config.contextStorage.default.module) {\n            case 'memory':\n                $('#context-file-title').html('file');\n                $('#context-memory-title').html('default');\n                break;\n            case 'file':\n                $('#context-file-title').html('default');\n                $('#context-memory-title').html('memory');\n                break;\n            default:\n        }\n    }\n\n    $projects.change(() => {\n        config.editorTheme.projects.enabled = $projects.val() === 'true';\n        save();\n        if (config.editorTheme.projects.enabled) {\n            $projects.prop('disabled', true)\n        }\n    });\n\n    $theme.change(() => {\n        switch ($theme.val()) {\n            case '':\n            case 'default':\n                delete config.editorTheme.theme;\n                break;\n\n            default:\n                config.editorTheme.theme = $theme.val();\n                break;\n        }\n        delete config.editorTheme.page;\n        save();\n    });\n\n    $contextStorageDefault.change(() => {\n        if (!config.contextStorage) {\n            config.contextStorage = {};\n        }\n        if (!config.contextStorage.default) {\n            config.contextStorage.default = {};\n        }\n\n        config.contextStorage.default.module = $contextStorageDefault.val();\n        updateContextTitle();\n\n        save();\n    });\n\n    $contextStorageFilePath.change(() => {\n        config.contextStorage.file.config.dir = $contextStorageFilePath.val();\n        save();\n    });\n\n    $contextStorageFileInterval.change(() => {\n        config.contextStorage.file.config.flushInterval = parseInt($contextStorageFileInterval.val(), 10);\n        save();\n    });\n\n    $adminauthSessionExpiryTime.change(() => {\n        if (!config.adminAuth) {\n            config.adminAuth = {};\n        }\n        const time = parseInt($adminauthSessionExpiryTime.val(), 10) || 604800;\n        if (config.adminAuth.sessionExpiryTime !== time) {\n            config.adminAuth.sessionExpiryTime = time;\n            save();\n        }\n    });\n\n    $adminauthType.change(() => {\n        switch ($adminauthType.val()) {\n            case 'credentials':\n                $adminauthCreds.show();\n                break;\n            /*            case 'rega':\n                            $adminauthExpiry.show();\n                            $adminauthCreds.hide();\n                            $adminauthUser.val('');\n                            if (!config.adminAuth) {\n                                config.adminAuth = {};\n                            }\n                            delete config.adminAuth.users;\n                            config.adminAuth.type = 'rega';\n                            config.adminAuth.sessionExpiryTime = parseInt($adminauthSessionExpiryTime.val(), 10) || 604800;\n                            save();\n                            break;*/\n            default:\n                $adminauthExpiry.hide();\n                $adminauthCreds.hide();\n                $adminauthUser.val('');\n                delete config.adminAuth;\n                save();\n        }\n    });\n\n    $nodeauthType.change(() => {\n        switch ($nodeauthType.val()) {\n            case 'basic':\n                $nodeauthCreds.show();\n                break;\n            default:\n                $nodeauthCreds.hide();\n                $nodeauthUser.val('');\n                delete config.httpNodeAuth;\n                save();\n        }\n    });\n\n    $staticauthType.change(() => {\n        switch ($staticauthType.val()) {\n            case 'basic':\n                $staticauthCreds.show();\n                break;\n            default:\n                $staticauthCreds.hide();\n                $staticauthUser.val('');\n                delete config.httpStaticAuth;\n                save();\n        }\n    });\n\n    $adminauthSet.click(() => {\n        const user = $.trim($adminauthUser.val());\n        const pw1 = $adminauthPass1.val();\n        const pw2 = $adminauthPass2.val();\n\n        let valid = true;\n\n        if (!user) {\n            $adminauthUser.addClass('is-invalid');\n            valid = false;\n        } else {\n            $adminauthUser.removeClass('is-invalid');\n        }\n\n        if (!pw1 || pw1 !== pw2) {\n            $adminauthPass1.addClass('is-invalid');\n            $adminauthPass2.addClass('is-invalid');\n            valid = false;\n        } else {\n            $adminauthPass1.removeClass('is-invalid');\n            $adminauthPass2.removeClass('is-invalid');\n        }\n\n        if (valid) {\n            config = Object.assign(config, {\n                adminAuth: {\n                    type: 'credentials',\n                    sessionExpiryTime: parseInt($adminauthSessionExpiryTime.val(), 10) || 604800,\n                    users: [{\n                        username: user,\n                        password: bcrypt.hashSync(pw1, 8),\n                        permissions: '*'\n                    }]\n                }\n            });\n            save();\n        }\n    });\n\n    $staticauthSet.click(() => {\n        const user = $.trim($staticauthUser.val());\n        const pw1 = $staticauthPass1.val();\n        const pw2 = $staticauthPass2.val();\n\n        let valid = true;\n\n        if (!user) {\n            $staticauthUser.addClass('is-invalid');\n            valid = false;\n        } else {\n            $staticauthUser.removeClass('is-invalid');\n        }\n\n        if (!pw1 || pw1 !== pw2) {\n            $staticauthPass1.addClass('is-invalid');\n            $staticauthPass2.addClass('is-invalid');\n            valid = false;\n        } else {\n            $staticauthPass1.removeClass('is-invalid');\n            $staticauthPass2.removeClass('is-invalid');\n        }\n\n        if (valid) {\n            config = Object.assign(config, {\n                httpStaticAuth: {\n                    user,\n                    pass: bcrypt.hashSync(pw1, 8),\n                }\n            });\n            save();\n        }\n    });\n\n    $nodeauthSet.click(() => {\n        const user = $.trim($nodeauthUser.val());\n        const pw1 = $nodeauthPass1.val();\n        const pw2 = $nodeauthPass2.val();\n\n        let valid = true;\n\n        if (!user) {\n            $nodeauthUser.addClass('is-invalid');\n            valid = false;\n        } else {\n            $nodeauthUser.removeClass('is-invalid');\n        }\n\n        if (!pw1 || pw1 !== pw2) {\n            $nodeauthPass1.addClass('is-invalid');\n            $nodeauthPass2.addClass('is-invalid');\n            valid = false;\n        } else {\n            $nodeauthPass1.removeClass('is-invalid');\n            $nodeauthPass2.removeClass('is-invalid');\n        }\n\n        if (valid) {\n            config = Object.assign(config, {\n                httpNodeAuth: {\n                    user,\n                    pass: bcrypt.hashSync(pw1, 8),\n                }\n            });\n            save();\n        }\n    });\n\n    function restart() {\n        clearTimeout(psTimeout);\n        $dropdownRestart.addClass('disabled');\n        $stop.addClass('disabled');\n        $dropdownStart.addClass('disabled');\n        $('#status-spinner').show();\n        $status.html('<span class=\"status-starting\">stopping</span>');\n        $memory.html('');\n        $cpu.html('');\n        $.get({\n            url: `service.cgi?sid=${sid}&cmd=restart`,\n            success: data => {\n                if (data.match(/Starting Node-RED: OK/)) {\n                    alert($alertExec);\n                } else if ($.trim(data) === 'error: invalid session') {\n                    invalidSession();\n                    return;\n                } else {\n                    alert($alertError);\n                }\n                psInterval = 1000;\n                setTimeout(() => {\n                    ps();\n                }, 1000);\n            }\n        });\n        setTimeout(() => {\n            ps();\n        }, 10000);\n\n    }\n\n    $restart.click(() => {\n        restart();\n    });\n\n    function safeMode(cb) {\n        $.get({\n            url: `safemode.cgi?sid=${sid}`,\n            success: cb\n        });\n    }\n\n    $restartSafe.click(() => {\n        safeMode(restart);\n    });\n\n    function start() {\n        $dropdownRestart.addClass('disabled');\n        $stop.addClass('disabled');\n        $dropdownStart.addClass('disabled');\n        $status.html('<span class=\"status-starting\">starting</span>');\n        $memory.html('');\n        $.get({\n            url: `service.cgi?sid=${sid}&cmd=start`,\n            success: data => {\n                if ($.trim(data) === 'error: invalid session') {\n                    invalidSession();\n                    return;\n                }\n\n                if (data.match(/Starting Node-RED: OK/)) {\n                    psInterval = 2000;\n                    setTimeout(() => {\n                        ps();\n                    }, 6000);\n                    alert($alertExec);\n                } else {\n                    alert($alertError);\n                }\n            }\n        });\n    }\n\n    $start.click(() => {\n        start();\n    });\n\n    $startSafe.click(() => {\n        safeMode(start);\n    });\n\n    $stop.click(() => {\n        clearTimeout(psTimeout);\n        $dropdownRestart.addClass('disabled');\n        $stop.addClass('disabled');\n        $dropdownStart.addClass('disabled');\n        $status.html('<span class=\"status-starting\">stopping</span>');\n        $memory.html('');\n        $.get({\n            url: `service.cgi?sid=${sid}&cmd=stop`,\n            success: data => {\n                if ($.trim(data) === 'error: invalid session') {\n                    invalidSession();\n                    return;\n                }\n                if (data.match(/Stopping Node-RED: OK/)) {\n                    alert($alertExec);\n                    psInterval = 2000;\n                    setTimeout(() => {\n                        ps();\n                    }, 6000);\n                } else {\n                    alert($alertError);\n                }\n            }\n        });\n    });\n\n    function setHeader(xhr) {\n        xhr.setRequestHeader('accept', 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*');\n    }\n\n    $.get('restart_count', data => {\n        $('#restarts').html(data || 'keine');\n    });\n\n    function download(filename, dataUrl) {\n        let link = document.createElement(\"a\");\n        link.download = filename;\n        link.target = \"_blank\";\n\n        link.href = dataUrl;\n        document.body.appendChild(link);\n        link.click();\n\n        document.body.removeChild(link);\n    }\n\n    $('#log').on('click', () => {\n        download('redmatic.' + (new Date()).toISOString() + '.log', 'log.cgi' + location.search);\n    });\n\n    function logUpload() {\n        $('#log-upload-spinner').show();\n        $('#log-upload').addClass('disabled');\n        $.post({\n            url: 'setnick.cgi' + location.search,\n            data: $.trim($('#nickname').val().toLowerCase()),\n            success: function (data) {\n                if ($.trim(data) === 'ok') {\n                    $.get({\n                        url: 'logupload.cgi?sid=' + sid,\n                        success: data => {\n                            $('#log-upload-spinner').hide();\n                            $('#log-upload').removeClass('disabled');\n                            $('#log-name').html(data);\n                            $('#modal-upload').modal('show')\n                        }\n                    }).fail(() => {\n                        $('#log-upload').removeClass('disabled');\n                        $('#log-upload-spinner').hide();\n                        alert($alertError);\n                    });\n                } else {\n                    $('#log-upload').removeClass('disabled');\n                    $('#log-upload-spinner').hide();\n                    if ($.trim(data) === 'error: invalid session') {\n                        invalidSession();\n                        return;\n                    }\n                    alert($alertError);\n                }\n            }\n        }).fail(() => {\n            alert($alertError);\n            $('#log-upload').removeClass('disabled');\n            $('#log-upload-spinner').hide();\n        });\n    }\n\n    $('#log-upload').on('click', () => {\n        $('#modal-nickname').modal('show');\n    });\n\n    $('#upgrade-log').on('click', () => {\n        download('redmatic-pkg-upgrade.' + (new Date()).toISOString() + '.log', 'log.cgi' + location.search + '&cmd=upgrade');\n    });\n\n    $('#autorestart').on('change', event => {\n        config.restartOnCrash = parseInt(event.target.value, 10);\n        save();\n    });\n\n    $backup.on('change', () => {\n        config.ccuBackup = $backup.val();\n        save();\n    });\n\n    $('#discard-package-hint').on('click', () => {\n        localStorage.setItem('package-hint', 'discarded');\n        $('#package-hint').hide();\n    });\n    if (localStorage.getItem('package-hint') !== 'discarded') {\n        $('#package-hint').show();\n    }\n\n    $('#package-filter').on('keyup', () => {\n        const filter = $('#package-filter').val();\n        $packageTable.find('tr').each(function () {\n            const name = $(this).find('td').html().toLowerCase();\n            if (name.includes(filter.toLowerCase())) {\n                $(this).show();\n            } else {\n                $(this).hide();\n            }\n        });\n    });\n\n});\n\n",
        "output": "str",
        "x": 440,
        "y": 300,
        "wires": [
            [
                "07089cae74365102"
            ]
        ]
    },
    {
        "id": "07089cae74365102",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "www/js/script.js",
        "filename": "/usr/local/addons/redmatic/www/js/script.js",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 700,
        "y": 300,
        "wires": [
            [
                "aecdcf17e967759b"
            ]
        ]
    },
    {
        "id": "3b213cd16eeb1a66",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "redmaticLoader",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "# Henke Version 1.2\n#!/bin/sh\n\nlogger -t redmatic -p daemon.warn \"Henke Script redmaticLoader\"\n\nCONF_DIR=/usr/local/etc/config\nADDON_DIR=/usr/local/addons/redmatic\nWWW_DIR=/usr/local/etc/config/addons/www/redmatic\n\ncd $ADDON_DIR/bin\n# Henke\nif [ -f /usr/bin/node ]; then\n\tNODE=/usr/bin/node\nfi\nif [ -f /usr/local/bin/node ]; then\n\tNODE=/usr/local/bin/node\nfi\n\n# NODE=$ADDON_DIR/bin/node\n\nexport PATH=$ADDON_DIR/bin:$PATH\nexport LD_LIBRARY_PATH=$ADDON_DIR/lib:$LD_LIBRARY_PATH\nexport HOME=$ADDON_DIR/home\n\nexport NO_UPDATE_NOTIFIER=true\n\nRED_DIR=$ADDON_DIR/lib/node_modules/node-red\nRED=$RED_DIR/red.js\n\nSETTINGS=$ADDON_DIR/lib/settings.js\n\nstatus=1\nrestarts=0\n\nlogger -t redmatic -p daemon.warn \"Henke checkNR start - $NODE\"\nnode checkNR.js\nsource /tmp/red-settings\nlogger -t redmatic -p daemon.warn \"Henke checkNR done $RedSettings_NodeRedUpdate\"\n#logger -t redmatic -p daemon.warn \"NodeRedUpdate$RedSettings_NodeRedUpdate\"\nif [[ $RedSettings_NodeRedUpdate != \"false\" ]]; then\n  logger -t redmatic -p daemon.warn \"Update NodeRed\"\n$ADDON_DIR/bin/updateNodeRed.sh\nfi\n\n#echo \"RR $RedSettings_RestartOnCrash\"\n#echo \"BB $RedSettings_Test\"\n#limit=`jq '.restartOnCrash' $ADDON_DIR/etc/settings.json`\n\nif [[ -z $RedSettings_RestartOnCrash ]]; then\n  RedSettings_RestartOnCrash = 0\nfi\n\nwhile [[ $status != 0 ]]; do\n  echo $restarts > $ADDON_DIR/var/restart_count\n  if [[ $restarts -gt 0 ]]; then\n    echo \"Restarting Node-RED ($restarts/$RedSettings_RestartOnCrash)\" | logger -p daemon.warn -t redmatic\n  else\n    echo \"Starting Node-RED\" | logger -p daemon.info -t redmatic\n  fi\n  if [[ -f $ADDON_DIR/var/safe_mode ]]; then\n    SAFE=\"--safe\"\n    rm $ADDON_DIR/var/safe_mode\n  fi\n  set -o pipefail\n# Henke add --max-old-space-size=256 --max-semi-space-size=8 --trace-deprecation --trace-warnings \n  $NODE $RED $SAFE -s $SETTINGS 2>&1 | logger -p daemon.err -t node-red\n  status=$?\n  if [[ $status != 0 ]]; then\n    echo \"Node-RED exited with non-zero exit status $status\" | logger -p daemon.err -t node-red\n    let \"restarts=restarts+1\"\n    if [[ $restarts -gt $RedSettings_RestartOnCrash ]]; then\n        if [[ $RedSettings_RestartOnCrash -gt 0 ]]; then\n            echo \"Maximum Node-RED restarts exceeded\" | logger -p daemon.err -t redmatic\n        fi\n        status=0\n    fi\n  fi\ndone\n",
        "output": "str",
        "x": 980,
        "y": 180,
        "wires": [
            [
                "19200cbb67cc50b9"
            ]
        ]
    },
    {
        "id": "19200cbb67cc50b9",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "bin/redmaticLoader",
        "filename": "/usr/local/addons/redmatic/bin/redmaticLoader",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1190,
        "y": 180,
        "wires": [
            [
                "fa72f43dd0a8948b"
            ]
        ]
    },
    {
        "id": "e435bc41d8c9739d",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "redmatic",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "#!/bin/sh\n\n# Henke\nlogger -t redmatic -p daemon.info \"Henke Script redmatic $1\"\n\nCONF_DIR=/usr/local/etc/config\nADDON_DIR=/usr/local/addons/redmatic\nWWW_DIR=/usr/local/etc/config/addons/www/redmatic\n\n# Henke NODE=$ADDON_DIR/bin/node\n\nSETTINGS=$ADDON_DIR/lib/settings.js\nRED_DIR=$ADDON_DIR/lib/node_modules/node-red\nRED=$RED_DIR/red.js\n\nLIGHTTPD_CONF=/etc/lighttpd/lighttpd.conf\nLIGHTTPD_SSL_CONF=/etc/lighttpd/lighttpd_ssl.conf\n#BACKUP_CGI=/www/config/cp_security.cgi\n\nexport PATH=$ADDON_DIR/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/addons/redmatic/lib:/usr/lib:/usr/local/lib\nexport GIT_EXEC_PATH=/usr/local/addons/redmatic/libexec/git-core\nexport NO_UPDATE_NOTIFIER=true\n\nStop () {\n    if [ -f /usr/bin/monit ]; then\n        /usr/bin/monit -g redmatic unmonitor\n    fi\n\n    PSPID=`ps -o pid,comm,args | awk '{if($3 == \"node-red\" || $4 ~ /node-red/){print $1}}'`\n    if [ \"$PSPID\" != \"\" ]; then\n        echo -n \"Stopping Node-RED: \"\n        logger -t redmatic -p daemon.info \"Stopping Node-RED\"\n\n        killall redmaticLoader 2>/dev/null\n        kill -SIGINT $PSPID 2>/dev/null\n        sleep 2\n        if kill -0 $PSPID 2> /dev/null\n        then\n            sleep 4\n            if kill -0 $PSPID 2> /dev/null\n            then\n                logger -t redmatic -p daemon.warn \"Killing Node-RED\"\n                kill -SIGKILL $PSPID 2>/dev/null\n            fi\n        fi\n        echo \"OK\"\n        logger -t redmatic -p daemon.info \"Node-RED stopped\"\n        return 0\n    else\n        echo \"Node-RED not running\"\n        return 1\n    fi\n}\n\nStart () {\n#    if [ `$ADDON_DIR/bin/jq -r '.ccuBackup' $ADDON_DIR/etc/settings.json` = \"full\" ]; then\nrm $ADDON_DIR/etc/.nobackup 2>/dev/null\nrm $ADDON_DIR/bin/.nobackup 2>/dev/null\nrm $ADDON_DIR/include/.nobackup 2>/dev/null\nrm $ADDON_DIR/lib/.nobackup 2>/dev/null\nrm $ADDON_DIR/libexec/.nobackup 2>/dev/null\nrm $ADDON_DIR/share/.nobackup 2>/dev/null\nrm $ADDON_DIR/tmp/.nobackup 2>/dev/null\nrm $ADDON_DIR/var/node_modules/.nobackup 2>/dev/null\nrm $ADDON_DIR/www/.nobackup 2>/dev/null\n#    else\n#        touch $ADDON_DIR/bin/.nobackup\n#        touch $ADDON_DIR/include/.nobackup\n#        touch $ADDON_DIR/lib/.nobackup\n#        touch $ADDON_DIR/libexec/.nobackup\n#        touch $ADDON_DIR/share/.nobackup\n#        touch $ADDON_DIR/tmp/.nobackup\n#        touch $ADDON_DIR/var/node_modules/.nobackup\n#        touch $ADDON_DIR/www/.nobackup\n#    fi\n\n#    if [ -f $ADDON_DIR/var/do_pkg_upgrade ]; then\n#        echo \"Updating Packages\"\n#        date +\"%b %d %H:%M:%S\" >> $ADDON_DIR/var/pkg-upgrade.log\n#        set -o pipefail\n#        $ADDON_DIR/bin/redmatic-pkg upgrade 2>&1 | tee -a $ADDON_DIR/var/pkg-upgrade.log | logger -t redmatic-pkg -p daemon.info && rm $ADDON_DIR/var/do_pkg_upgrade\n#        echo \"\" >> $ADDON_DIR/var/pkg-upgrade.log\n#        sleep 1\n#    fi\n\n    if ! grep -Fq \"/etc/config/lighttpd/\" $LIGHTTPD_CONF\n    then\n      echo \"patching $LIGHTTPD_CONF\"\n      mount -o remount,rw /\n      cp $LIGHTTPD_CONF $LIGHTTPD_CONF.orig\n      echo \"include_shell \\\"test -d /etc/config/lighttpd && cat /etc/config/lighttpd/*.conf\\\"\" >> $LIGHTTPD_CONF\n      mount -o remount,ro /\n      /etc/init.d/S50lighttpd restart\n    fi\n\n    if [ -f $LIGHTTPD_SSL_CONF ]\n    then\n        if ! grep -Fq \"/etc/config/lighttpd/\" $LIGHTTPD_SSL_CONF\n        then\n          echo \"patching $LIGHTTPD_SSL_CONF\"\n          mount -o remount,rw /\n          cp $LIGHTTPD_SSL_CONF $LIGHTTPD_SSL_CONF.orig\n          echo \"include_shell \\\"test -d /etc/config/lighttpd && cat /etc/config/lighttpd/*.conf\\\"\" >> $LIGHTTPD_SSL_CONF\n          mount -o remount,ro /\n          /etc/init.d/S50lighttpd restart\n        fi\n    fi\n\n#    if ! grep -Fq \"exclude-tag=.nobackup\" $BACKUP_CGI\n#    then\n#        echo \"patching $BACKUP_CGI\"\n#        mount -o remount,rw /\n#        cp $BACKUP_CGI $BACKUP_CGI.orig\n#        sed \"s/exec tar czf \\/tmp\\/usr_local.tar.gz usr\\/local/exec tar --exclude-tag=.nobackup -czf \\/tmp\\/usr_local.tar.gz usr\\/local/\" $BACKUP_CGI > $BACKUP_CGI.tmp && mv $BACKUP_CGI.tmp $BACKUP_CGI\n#        chmod 755 $BACKUP_CGI\n#        mount -o remount,ro /\n#    fi\n\n    if [ ! -f /etc/config/rdmtc.uuid ]; then\n        /usr/bin/uuidgen > /etc/config/rdmtc.uuid\n    fi\n    LD_LIBRARY_PATH=/usr/lib:/usr/local/lib:/usr/local/addons/redmatic/lib ; /usr/local/addons/redmatic/bin/redmaticVersions | /usr/bin/curl -H \"Content-Type: application/json\" -H \"X-RedMatic-uuid: `cat /etc/config/rdmtc.uuid`\" --data @- -s --max-time 3 https://telemetry.redmatic.de\n\n    PSPID=`ps -o pid,comm,args | awk '{if($3 == \"node-red\" || $4 ~ /node-red/){print $1}}'`\n    if [ \"$PSPID\" != \"\" ]; then\n        echo \"Node-RED already running\"\n        logger -t redmatic -p daemon.error \"cant start - already running\"\n        exit 1\n    else\n        upSeconds=\"$(cat /proc/uptime | grep -o '^[0-9]\\+')\"\n        if [ \"${upSeconds}\" -lt \"120\" ]; then\n              logger -t redmatic -p daemon.info \"Starting Node-RED after reboot ... waiting 30 seconds...\"\n              echo \"Starting Node-RED ... waiting 30 seconds...\"\n              sleep 30\n        fi\n        echo -n \"Starting Node-RED: \"\n        source $ADDON_DIR/versions\n        logger -t redmatic -p daemon.info \"RedMatic v$VERSION_ADDON (c) Sebastian Raff https://github.com/rdmtc/RedMatic - Patch Henke\"\n        start-stop-daemon -S -q -b --exec $ADDON_DIR/bin/redmaticLoader\n        echo \"OK\"\n    fi\n\n    if [ -f /usr/bin/monit ]; then\n        nohup $ADDON_DIR/bin/monit-start > /dev/null 2>&1 &\n    fi\n}\n\ncase \"$1\" in\n\n    stop)\n        Stop || exit 1\n    ;;\n\n    start)\n        Start\n    ;;\n\n    restart)\n        Stop\n        sleep 10\n        Start\n    ;;\n\n    info)\n        source $ADDON_DIR/versions\n        echo \"Info: <div><a target=\\\"_blank\\\" href=\\\"https://github.com/rdmtc/RedMatic\\\"><img src=\\\"/addons/redmatic/redmatic5-wide.png\\\" height=\\\"48\\\"/></a></div>\"\n        echo \"Name: RedMatic\"\n        echo \"Version: $VERSION_ADDON\"\n#        echo \"Update: /addons/redmatic/update_check.cgi\"\n        echo \"Config-Url: /addons/redmatic/settings.cgi\"\n        echo \"Operations: restart uninstall\"\n    ;;\n\n    uninstall)\n        Stop\n\n        $ADDON_DIR/bin/update_addon redmatic\n        rm -r $ADDON_DIR\n        rm -r $WWW_DIR\n        rm $CONF_DIR/lighttpd/redmatic.conf\n        rm $CONF_DIR/rc.d/redmatic\n\n        if [ -f /usr/local/etc/monit-redmatic.cfg ]; then\n            rm /usr/local/etc/monit-redmatic.cfg\n            /usr/bin/monit reload\n        fi\n\n        mount -o remount,rw /\n        if [ -f $LIGHTTPD_CONF.orig ]; then\n            mv $LIGHTTPD_CONF.orig $LIGHTTPD_CONF\n        fi\n        if [ -f $LIGHTTPD_SSL_CONF.orig ]; then\n            mv $LIGHTTPD_SSL_CONF.orig $LIGHTTPD_SSL_CONF\n        fi\n#        if [ -f $BACKUP_CGI.orig ]; then\n#            mv $BACKUP_CGI.orig $BACKUP_CGI\n#        fi\n        mount -o remount,ro /\n\n        logger -t redmatic -p daemon.info \"Uninstalled RedMatic\"\n    ;;\n\n    *)\n        echo \"Usage: node-red {start|stop|restart|info|uninstall}\" >&2\n        exit 1\n    ;;\n\nesac\n\nexit 0\n",
        "output": "str",
        "x": 440,
        "y": 180,
        "wires": [
            [
                "7def8072ba56d9d1"
            ]
        ]
    },
    {
        "id": "7def8072ba56d9d1",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "bin/redmatic",
        "filename": "/usr/local/addons/redmatic/bin/redmatic",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 690,
        "y": 180,
        "wires": [
            [
                "3b213cd16eeb1a66"
            ]
        ]
    },
    {
        "id": "a0ee823d1b868b33",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "settings.js",
        "field": "payload",
        "fieldType": "msg",
        "format": "javascript",
        "syntax": "plain",
        "template": "const fs = require('fs');\n\nconst addOn = '/usr/local/addons/redmatic/';\nconst etcSettings = addOn + 'etc/settings.json';\n\nconst defaults = require(addOn + 'lib/node_modules/node-red/settings.js');\nconst settings = require(etcSettings);\nconst logging = require(addOn + 'lib/logger.js');\n\n// Migration\nif (settings.logging.console) {\n    settings.logging.ain = settings.logging.console;\n    delete settings.logging.console;\n    fs.writeFileSync(etcSettings, JSON.stringify(settings, null, '  '));\n}\n\n// Credentials encryption key\nif (fs.existsSync(addOn + 'etc/credentials.key')) {\n    settings.credentialSecret = fs.readFileSync(addOn + 'etc/credentials.key').toString();\n}\n\n// Logging\ndelete defaults.logging.console;\nObject.assign(logging.logging.ain, settings.logging.ain);\n\n// Enable Projects Feature\nif (!defaults.editorTheme) {\n    defaults.editorTheme = {};\n}\nif (!defaults.editorTheme.projects) {\n    defaults.editorTheme.projects = {};\n}\ndefaults.editorTheme.projects.enabled = defaults.editorTheme.projects.enabled || false;\n\n// Auskommentiert, M. Henke\n// Inject sessionExpiryTime to Rega Authentication\nif (settings.adminAuth && settings.adminAuth.type === 'rega') {\n    //    const regaAuth = require(addOn + 'lib/rega-auth.js');\n    delete settings.adminAuth;\n    console.log(\"ReGa Passworte nicht mehr unterstützt\");\n    /*    if (settings.adminAuth.sessionExpiryTime) {\n            regaAuth.sessionExpiryTime = settings.adminAuth.sessionExpiryTime;\n        }\n        settings.adminAuth = regaAuth;*/\n}\n\n// M. Henke\nif (settings.httpRoot) {\n    settings.httpAdminRoot = settings.httpRoot;\n    settings.httpNodeRoot = settings.httpRoot;\n    delete settings.httpRoot;\n}\nif (!settings.runtimeState)\n    settings.runtimeState = {};\nif (settings.runtimeState) {\n//    settings.runtimeState.enabled = true;\n    settings.runtimeState.ui = true;\n}\n\n// Context Storage\nif (!settings.contextStorage) {\n    settings.contextStorage = {};\n}\nif (!settings.contextStorage.default) {\n    settings.contextStorage.default = {};\n}\nif (!settings.contextStorage.default.module) {\n    settings.contextStorage.default.module = 'memory';\n}\nif (settings.contextStorage.default.module === 'localfilesystem') {\n    settings.contextStorage.default.module = 'file';\n}\n\nif (settings.contextStorage.default.module !== 'file' && settings.contextStorage.default.module !== 'memory') {\n    settings.contextStorage.default.module = 'memory';\n}\n\nif (!settings.contextStorage.memory) {\n    settings.contextStorage.memory = {\n        'module': 'memory'\n    }\n}\nif (!settings.contextStorage.file) {\n    settings.contextStorage.file = {\n        'module': 'localfilesystem',\n        config: {\n            dir: addOn + 'var',\n            flushInterval: 300\n        }\n    }\n}\n\nconst defaultContextStorage = Object.assign({}, settings.contextStorage[settings.contextStorage.default.module]);\ndelete settings.contextStorage[settings.contextStorage.default.module];\nsettings.contextStorage.default = defaultContextStorage;\n\nconst result = Object.assign(\n    defaults,\n    settings,\n    logging\n);\n\nfs.writeFileSync('/tmp/red-settings.json', JSON.stringify(result));\n\nmodule.exports = result;\n",
        "output": "str",
        "x": 440,
        "y": 260,
        "wires": [
            [
                "773c8ac10017ce00"
            ]
        ]
    },
    {
        "id": "773c8ac10017ce00",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "lib/settings.js",
        "filename": "/usr/local/addons/redmatic/lib/settings.js",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 690,
        "y": 260,
        "wires": [
            [
                "775f2a96c0c5bcc3"
            ]
        ]
    },
    {
        "id": "775f2a96c0c5bcc3",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "versions",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "mustache",
        "template": "# Henke\nexport VERSION_ADDON={{VersionAddOn}}\n",
        "output": "str",
        "x": 960,
        "y": 260,
        "wires": [
            [
                "ef6f947e639c52b9"
            ]
        ]
    },
    {
        "id": "ef6f947e639c52b9",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "versions",
        "filename": "/usr/local/addons/redmatic/versions",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1160,
        "y": 260,
        "wires": [
            [
                "3d2fc855a49dc0ab"
            ]
        ]
    },
    {
        "id": "aecdcf17e967759b",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "settings.html",
        "field": "payload",
        "fieldType": "msg",
        "format": "html",
        "syntax": "plain",
        "template": "<!DOCTYPE html>\n<meta charset=\"UTF-8\">\n\n<title>RedMatic</title>\n\n<script src=\"node_modules/jquery/dist/jquery.min.js\"></script>\n<script src=\"node_modules/bcryptjs/dist/bcrypt.min.js\"></script>\n<script src=\"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js\"></script>\n\n<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"apple-icon-180x180.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"96x96\" href=\"favicon-96x96.png\">\n\n<link rel=\"stylesheet\" href=\"node_modules/bootstrap/dist/css/bootstrap.min.css\">\n<link rel=\"stylesheet\" href=\"node_modules/@fortawesome/fontawesome-free/css/all.css\">\n<link rel=\"stylesheet\" href=\"css/style.css\">\n\n<div id=\"invalidSession\">\n    Sitzung ung&uuml;ltig. Bitte diese Seite schlie&szlig;en.\n</div>\n\n<nav class=\"navbar sticky-top navbar-light bg-light mb-4\">\n    <a href=\"https://github.com/rdmtc/RedMatic\" target=\"_blank\"><img src=\"redmatic5-compact.png\"\n            style=\"height: 42px; \"></a>\n\n    <ul class=\"nav navbar-nav mr-auto d-flex flex-row mt-2\" role=\"tablist\" id=\"myTab\">\n        <li class=\"nav-item ml-3\">\n            <a class=\"nav-link pb-0\" id=\"configuration-tab\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"configuration\"\n                aria-selected href=\"#configuration\">Konfiguration</a>\n        </li>\n<!-- Henke\n                                    <li class=\"nav-item ml-3\">\n                                        <a class=\"nav-link pb-0\" id=\"packages-tab\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"packages\" aria-selected href=\"#packages\">Pakete</a>\n                                    </li>\n//-->\n        <li class=\"nav-item ml-3\">\n            <a class=\"nav-link pb-0\" id=\"versions-tab\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"versions\"\n                aria-selected href=\"#versions\">Debug</a>\n        </li>\n        <li class=\"nav-item ml-3\">\n            <a class=\"nav-link pb-0\" id=\"licenses-tab\" data-toggle=\"tab\" role=\"tab\" aria-controls=\"licenses\"\n                href=\"#licenses\">Lizenzen</a>\n        </li>\n    </ul>\n    <div class=\"ml-3 mr-2 pl-2\">\n        <a id=\"link-red\" role=\"button\" class=\"btn btn-sm btn-outline-info\" target=\"_blank\" href=\"/addons/red/\"><i\n                class=\"fa fa-external-link-alt\"></i> Node-RED</a>\n        <a id=\"link-ui\" role=\"button\" class=\"btn btn-sm btn-outline-info mr-3\" target=\"_blank\" href=\"/addons/red/ui/\"><i\n                class=\"fa fa-external-link-alt\"></i> Dashboard</a>\n    </div>\n    <div style=\"min-width: 130px\" id=\"redmatic-version\"></div>\n</nav>\n\n<div id=\"container\" class=\"container\">\n\n    <div id=\"alert-saved\" style=\"display: none;\" class=\"fixed-top mx-auto alert alert-success alert-dismissible fade\"\n        role=\"alert\">\n        <strong>Settings gespeichert, Node-RED Neustart notwendig.</strong>\n    </div>\n\n    <div id=\"alert-error\" style=\"display: none;\" class=\"fixed-top mx-auto alert alert-error alert-dismissible fade\"\n        role=\"alert\">\n        <strong>Ein Fehler ist aufgetreten</strong>\n    </div>\n\n    <div id=\"alert-exec\" style=\"display: none;\" class=\"fixed-top mx-auto alert alert-success alert-dismissible fade\"\n        role=\"alert\">\n        <strong>Kommando ausgef&uuml;hrt</strong>\n    </div>\n\n    <div id=\"modal-upload\" class=\"modal\" tabindex=\"-1\" role=\"dialog\">\n        <div class=\"modal-dialog\" role=\"document\">\n            <div class=\"modal-content\">\n                <div class=\"modal-header\">\n                    <h5 class=\"modal-title\">Log Datei erfolgreich hochgeladen</h5>\n                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n                        <span aria-hidden=\"true\">&times;</span>\n                    </button>\n                </div>\n                <div class=\"modal-body\">\n                    <p>Log Datei <strong><span id=\"log-name\"></span></strong> hochgeladen</p>\n                </div>\n                <div class=\"modal-footer\">\n                    <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Schliessen</button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <div id=\"modal-nickname\" class=\"modal\" tabindex=\"-1\" role=\"dialog\">\n        <div class=\"modal-dialog\" role=\"document\">\n            <div class=\"modal-content\">\n                <div class=\"modal-header\">\n                    <h5 class=\"modal-title\">Log Versand</h5>\n                    <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">\n                        <span aria-hidden=\"true\">&times;</span>\n                    </button>\n                </div>\n                <div class=\"modal-body\">\n                    <input id=\"nickname\" placeholder=\"Nickname\" type=\"text\" class=\"form-control\" style=\"width: 240px;\">\n                </div>\n                <div class=\"modal-footer\">\n                    <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">Abbrechen</button>\n                    <button type=\"button\" class=\"btn btn-primary\" id=\"log-upload-do\">Log versenden</button>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"tab-content\" id=\"myTabContent\">\n        <div class=\"tab-pane fade show\" id=\"configuration\" role=\"tabpanel\" aria-labelledby=\"configuration-tab\">\n\n<!-- Henke\n            <div id=\"update-notify\" class=\"card mb-4\" style=\"border-color: orange; display: none;\">\n                <div class=\"card-body\">\n                    RedMatic Update steht zur Verf&uuml;gung: <span id=\"update-link\"></span> (siehe <a\n                        href=\"https://github.com/rdmtc/RedMatic/wiki/Update\" target=\"_blank\">Installationsanleitung\n                        im RedMatic Wiki</a>)\n                </div>\n            </div>\n//-->\n\n            <div class=\"card mb-4\">\n\n                <div class=\"card-body\">\n                    <label style=\"display: block\">Node-RED Prozess</label>\n                    <!--<a id=\"backup\" role=\"button\" class=\"btn btn-sm btn-primary mr-3 disabled\">Backup</a>-->\n                    <div class=\"dropdown\" style=\"display: inline-block\">\n                        <button type=\"button\" class=\"btn btn-sm btn-warning dropdown-toggle\" id=\"dropdownRestart\"\n                            data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n                            <i class=\"fa fa-sync-alt\"></i> Neustart\n                        </button>\n\n                        <div class=\"dropdown-menu\" aria-labelledby=\"dropdownMenuButton\">\n                            <a id=\"restart\" class=\"dropdown-item\" href=\"#\">Normal</a>\n                            <a id=\"restartSafe\" class=\"dropdown-item\" href=\"#\">Safe Mode</a>\n                        </div>\n                    </div>\n\n                    <button id=\"stop\" type=\"button\" class=\"btn btn-sm btn-warning\"><i class=\"fa fa-stop\"></i>\n                        Stop</button>\n\n                    <div class=\"dropdown\" style=\"display: inline-block\">\n                        <button type=\"button\" class=\"btn btn-sm btn-warning dropdown-toggle\" id=\"dropdownStart\"\n                            data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n                            <i class=\"fa fa-play\"></i> Start\n                        </button>\n\n                        <div class=\"dropdown-menu\" aria-labelledby=\"dropdownMenuButton\">\n                            <a id=\"start\" class=\"dropdown-item\" href=\"#\">Normal</a>\n                            <a id=\"startSafe\" class=\"dropdown-item\" href=\"#\">Safe Mode</a>\n                        </div>\n                    </div>\n\n                    <div style=\"width: 30px; display: inline-block\">\n                        <div id=\"status-spinner\" class=\"spinner-border spinner-border-sm ml-2 mr-2\" role=\"status\"\n                            style=\"color: #6a737d; display: inline-block;\">\n                            <span class=\"sr-only\">Please wait...</span>\n                        </div>\n                    </div>\n\n                    <div style=\"vertical-align: middle; display: inline-block; width: 210px; font-size: 11px; color: grey;\"\n                        class=\"\">\n                        <div><span id=\"node-red-status\" style=\"font-weight: bold;\"></span></div>\n                        <div>\n                            <span id=\"node-red-cpu\" style=\"font-weight: bold;\"></span><span id=\"node-red-memory\"\n                                style=\"font-weight: bold;\"></span>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n<!-- Henke\n            <div class=\"card mb-4 pr-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label for=\"projects\">Backup <a href=\"https://github.com/rdmtc/RedMatic/wiki/Backup\"\n                                class=\"help-link\" target=\"_blank\"><i class=\"far fa-question-circle\"></i></a></label>\n                        <select class=\"form-control\" id=\"backup\">\n                            <option value=\"reduce\">Reduziere Backupgrö&szlig;e - nur relevante Daten inkludieren\n                            </option>\n                            <option value=\"full\">Alles im Backup inkludieren - Warnung: das kann u.U. zu Problemen\n                                mit dem Backup/Restore f&uuml;hren!</option>\n                        </select>\n                    </div>\n                </div>\n            </div>\n//-->\n\n            <div class=\"card mb-4 pr-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label>Context Storage <a href=\"https://github.com/rdmtc/RedMatic/wiki/Context-Storage\"\n                                class=\"help-link\" target=\"_blank\"><i class=\"far fa-question-circle\"></i></a></label>\n                        <div class=\"row mb-2\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                default\n                            </div>\n                            <div class=\"col-sm-9\">\n                                <select class=\"form-control\" id=\"context-storage-default\">\n                                    <option>memory</option>\n                                    <option>file</option>\n                                </select>\n                            </div>\n                        </div>\n                        <div class=\"row mb-2\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                <code id=\"context-memory-title\">memory</code>\n                            </div>\n                            <div class=\"col-sm-9\"\n                                style=\"min-height: 26px; padding: 6px 22px; vertical-align: middle; color: grey; font-style: italic;\">\n                                memory\n                            </div>\n                        </div>\n\n                        <div class=\"row mb-2\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                <code id=\"context-file-title\">file</code>\n                            </div>\n                            <div class=\"col-sm-6\">\n                                <input class=\"form-control\" id=\"context-storage-file-path\" placeholder=\"Path\" required>\n                            </div>\n                            <div class=\"col-sm-3\">\n                                <input class=\"form-control\" type=\"number\" id=\"context-storage-file-interval\"\n                                    placeholder=\"Schreibintervall\">\n                            </div>\n                        </div>\n\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"card mb-4 pr-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label for=\"projects\">Projekte <a href=\"https://github.com/rdmtc/RedMatic/wiki/Projekte\"\n                                class=\"help-link\" target=\"_blank\"><i class=\"far fa-question-circle\"></i></a></label>\n                        <select class=\"form-control\" id=\"projects\">\n                            <option value=\"false\">Nicht verwenden</option>\n                            <option value=\"true\">Aktiv</option>\n                        </select>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"card mb-4 pr-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label for=\"theme\">Theme</label>\n                        <select class=\"form-control\" id=\"theme\">\n                            <option value=\"default\">standard</option>\n                            <option value=\"midnight-red\">midnight-red</option>\n                            <option value=\"totallyinformation\">totallyinformation</option>\n                        </select>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"card mb-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label>Authentifizierung <a href=\"https://github.com/rdmtc/RedMatic/wiki/Passwort\"\n                                class=\"help-link\" target=\"_blank\"><i class=\"far fa-question-circle\"></i></a></label>\n                        <div class=\"row mb-3\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                Admin\n                            </div>\n                            <div class=\"col-sm-9\">\n                                <div class=\"row mb-2 col-sm-12\">\n                                    <select class=\"form-control\" id=\"adminauth-type\">\n                                        <option value=\"none\">Keine Authentifizierung</option>\n                                        <option value=\"credentials\">Username/Passwort individuell</option>\n                                        <!--                                        <option value=\"rega\">ReGaHSS (CCU WebUI User nutzen)</option> -->\n                                    </select>\n                                </div>\n                                <div id=\"adminauth-expiry\" class=\"col-sm-12 row mb-1\" style=\"display: none\">\n                                    <label class=\"col-sm-6 mt-2\" for=\"adminauth-sessionExpiryTime\">Session Timeout\n                                        (Sekunden)</label>\n                                    <input class=\"col-sm-6 form-control\" id=\"adminauth-sessionExpiryTime\" placeholder=\"\"\n                                        type=\"number\">\n                                </div>\n                                <div id=\"adminauth-credentials\" class=\"col-sm-12 row pl-0 pr-0\" style=\"display: none\">\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" id=\"adminauth-user\" placeholder=\"User\" required>\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"adminauth-pass1\"\n                                            placeholder=\"Passwort\">\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"adminauth-pass2\"\n                                            placeholder=\"Passwort wiederholen\">\n                                    </div>\n                                    <div class=\"col-md-auto\">\n                                        <button id=\"adminauth-set\" type=\"button\"\n                                            class=\"btn btn-primary\">&Uuml;bernehmen</button>\n                                    </div>\n                                </div>\n                            </div>\n                        </div>\n                        <div class=\"row mb-3\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                Node\n                            </div>\n                            <div class=\"col-sm-9\">\n                                <div class=\"row mb-1 col-sm-12\">\n                                    <select class=\"form-control\" id=\"nodeauth-type\">\n                                        <option value=\"none\">Keine Authentifizierung</option>\n                                        <option value=\"basic\">Username/Passwort individuell</option>\n                                    </select>\n                                </div>\n                                <div id=\"nodeauth-credentials\" class=\"col-sm-12 row pl-0 pr-0\" style=\"display: none\">\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" id=\"nodeauth-user\" placeholder=\"User\">\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"nodeauth-pass1\"\n                                            placeholder=\"Passwort\">\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"nodeauth-pass2\"\n                                            placeholder=\"Passwort wiederholen\">\n                                    </div>\n                                    <div class=\"col-md-auto\">\n                                        <button id=\"nodeauth-set\" type=\"button\"\n                                            class=\"btn btn-primary\">&Uuml;bernehmen</button>\n                                    </div>\n                                </div>\n                            </div>\n                        </div>\n                        <div class=\"row mb-3\">\n                            <div class=\"col-sm-3\" style=\"line-height: 38px;\">\n                                Static\n                            </div>\n                            <div class=\"col-sm-9\">\n                                <div class=\"row mb-1 col-sm-12\">\n                                    <select class=\"form-control\" id=\"staticauth-type\">\n                                        <option value=\"none\">Keine Authentifizierung</option>\n                                        <option value=\"basic\">Username/Passwort individuell</option>\n                                    </select>\n                                </div>\n                                <div id=\"staticauth-credentials\" class=\"col-sm-12 row pl-0 pr-0\" style=\"display: none\">\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" id=\"staticauth-user\" placeholder=\"User\">\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"staticauth-pass1\"\n                                            placeholder=\"Passwort\">\n                                    </div>\n                                    <div class=\"col-sm\">\n                                        <input class=\"form-control\" type=\"password\" id=\"staticauth-pass2\"\n                                            placeholder=\"Passwort wiederholen\">\n                                    </div>\n                                    <div class=\"col-md-auto\">\n                                        <button id=\"staticauth-set\" type=\"button\"\n                                            class=\"btn btn-primary\">&Uuml;bernehmen</button>\n                                    </div>\n                                </div>\n                            </div>\n                        </div>\n\n                    </div>\n\n                </div>\n            </div>\n\n        </div>\n\n<!-- Henke\n                                    <div class=\"tab-pane fade show\" id=\"packages\" role=\"tabpanel\" aria-labelledby=\"packages-tab\">\n\n                                        <div id=\"package-hint\" class=\"card mb-4\" style=\"border-color: blue; display: none;\">\n                                            <div class=\"card-body\">\n                                                <button type=\"button\" class=\"btn btn-mini btn-info\" id=\"discard-package-hint\" style=\"padding: 0px 8px 2px; margin-top: -4px;\">x</button>\n                                                <b>Tipp:</b> Nicht-verwendete Pakete deinstallieren, das spart Speicher und reduziert den RAM-Bedarf und die Startzeit von Node-RED.\n                                            </div>\n                                        </div>\n\n                                        <table id=\"table-packages\" class=\"table\">\n                                            <thead>\n                                                <tr>\n                                                    <th scope=\"col\" style=\"min-width: 300px;\">Paket</th>\n                                                    <th scope=\"col\" style=\"min-width: 120px;\">Version</th>\n                                                    <th scope=\"col\" style=\"min-width: 80px; width: 80px;\">Installiert</th>\n                                                    <th scope=\"col\" style=\"min-width: 300px;\"></th>\n                                                </tr>\n                                                <tr>\n                                                    <th scope=\"col\"><input class=\"form-control form-control-sm\" id=\"package-filter\"></th>\n                                                    <th scope=\"col\"></th>\n                                                    <th scope=\"col\"></th>\n                                                    <th scope=\"col\"></th>\n                                                </tr>\n                                            </thead>\n                                            <tbody id=\"package-table\">\n\n                                            </tbody>\n                                        </table>\n                                        <div id=\"pkg-spinner\" class=\"text-center\">\n                                            <div class=\"spinner-border text-center\" role=\"status\">\n                                                <span class=\"sr-only\">Lade...</span>\n                                            </div>\n                                        </div>\n                                    </div>\n//-->\n\n        <div class=\"tab-pane fade show\" id=\"versions\" role=\"tabpanel\" aria-labelledby=\"versions-tab\">\n\n            <div class=\"card mb-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label for=\"loglevel\">Log Level</label>\n                        <select class=\"form-control\" id=\"loglevel\">\n                            <option>fatal</option>\n                            <option>error</option>\n                            <option>warn</option>\n                            <option>info</option>\n                            <option>debug</option>\n                            <option>trace</option>\n                        </select>\n                    </div>\n\n                </div>\n            </div>\n\n            <div class=\"card mb-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <button id=\"log\" type=\"button\" class=\"btn btn-sm btn-info\"><i class=\"fa fa-download\"></i>\n                            Log herunterladen</button>\n\n\n                        <button id=\"log-upload\" type=\"button\" class=\"btn btn-sm btn-info\" style=\"display:none;\"><i\n                                class=\"fa fa-upload\"></i> Log versenden</button>\n                        <div id=\"log-upload-spinner\" class=\"spinner-border spinner-border-sm ml-2 mr-2\" role=\"status\"\n                            style=\"color: #6a737d; display: none;\">\n                            <span class=\"sr-only\">Please wait...</span>\n                        </div>\n\n\n                    </div>\n                </div>\n            </div>\n\n\n            <div class=\"card mb-4\">\n                <div class=\"card-body\">\n                    <div class=\"form-group\">\n                        <label for=\"autorestart\">Node-RED im Falle eines Absturzes neu starten</label>\n                        <select class=\"form-control\" id=\"autorestart\">\n                            <option value=\"0\">Deaktiviert</option>\n                            <option value=\"1\">Einmal</option>\n                            <option value=\"2\">Zweimal</option>\n                            <option value=\"3\">Dreimal</option>\n                            <option value=\"4\">Viermal</option>\n                            <option value=\"5\">F&uuml;nfmal</option>\n                            <option value=\"2147483647\">Unbegrenzt</option>\n                        </select>\n                    </div>\n                    <p>Node-RED Abst&uuml;rze seit letztem RedMatic-Start: <span id=\"restarts\">keine</span></p>\n                </div>\n            </div>\n\n        </div>\n\n        <div class=\"tab-pane fade show\" id=\"licenses\" role=\"tabpanel\" aria-labelledby=\"licenses-tab\">\n            <iframe></iframe>\n        </div>\n\n\n    </div>\n</div>\n\n<script src=\"js/script.js\"></script>",
        "output": "str",
        "x": 970,
        "y": 300,
        "wires": [
            [
                "eb41e227ba32cd94"
            ]
        ]
    },
    {
        "id": "eb41e227ba32cd94",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "www/settings.html",
        "filename": "/usr/local/addons/redmatic/www/settings.html",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1190,
        "y": 300,
        "wires": [
            [
                "001c9a1b2a7e8e2e"
            ]
        ]
    },
    {
        "id": "001c9a1b2a7e8e2e",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "default-settings.json",
        "field": "payload",
        "fieldType": "msg",
        "format": "json",
        "syntax": "plain",
        "template": "{\n  \"uiPort\": 1880,\n  \"uiHost\": \"127.0.0.1\",\n  \"flowFile\": \"flows.json\",\n  \"userDir\": \"/usr/local/addons/redmatic/var\",\n  \"httpRoot\": \"/addons/red\",\n  \"logging\": {\n    \"ain\": {\n      \"level\": \"info\",\n      \"metrics\": false,\n      \"audit\": false\n    }\n  },\n  \"contextStorage\": {\n    \"default\": {\n      \"module\": \"memory\"\n    },\n    \"memory\": {\n      \"module\": \"memory\"\n    },\n    \"file\": {\n      \"module\": \"localfilesystem\",\n      \"config\": {\n        \"dir\": \"/usr/local/addons/redmatic/var\",\n        \"flushInterval\": 300\n      }\n    }\n  },\n  \"editorTheme\": {\n    \"projects\": {\n      \"enabled\": false\n    }\n  },\n  \"adminAuth\": {\n    \"sessionExpiryTime\": 86400\n  },\n  \"restartOnCrash\": 0\n}",
        "output": "str",
        "x": 480,
        "y": 340,
        "wires": [
            [
                "5b8172939d7a1e26"
            ]
        ]
    },
    {
        "id": "5b8172939d7a1e26",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "etc/default-settings.json",
        "filename": "/usr/local/addons/redmatic/etc/default-settings.json",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 730,
        "y": 340,
        "wires": [
            [
                "70bdbbad9e26b78d"
            ]
        ]
    },
    {
        "id": "4c6951d8ab085736",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "mount",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "mustache",
        "template": "#!/bin/sh\nmount -o rw,remount /\nsleep 10\nchmod -R a+rwx /usr/local/addons/redmatic",
        "output": "str",
        "x": 950,
        "y": 140,
        "wires": [
            [
                "f1c29c21b7b7338a"
            ]
        ]
    },
    {
        "id": "1900d9b72af1a2d8",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "mount",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "mustache",
        "template": "#!/bin/sh\nchmod -R a+rwx /usr/local/addons/redmatic\nmount -o ro,remount /",
        "output": "str",
        "x": 1090,
        "y": 480,
        "wires": [
            [
                "eda7f0ecc302657e"
            ]
        ]
    },
    {
        "id": "8abba785cac84dc4",
        "type": "file in",
        "z": "2ab1de6847dd7ea2",
        "name": "versions",
        "filename": "/usr/local/addons/redmatic/versions",
        "filenameType": "str",
        "format": "utf8",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 140,
        "y": 280,
        "wires": [
            [
                "82abbf82a75e4ea3"
            ]
        ]
    },
    {
        "id": "82abbf82a75e4ea3",
        "type": "function",
        "z": "2ab1de6847dd7ea2",
        "name": "check",
        "func": "const key = \"VERSION_ADDON=\";\nlet ist = msg.payload.substring(msg.payload.indexOf(key) + key.length);\nist = ist.substring(0, ist.indexOf(\"\\n\"));\n// msg.ist = ist;\nlet ref = msg.VersionAddOn;\nlet cmp = cmpVersion(ist, ref);\nmsg.AddOn_ok = (cmp >= 0);\nif (!msg.AddOn_ok)\n    return msg;\nreturn [null,msg];\n\nfunction cmpVersion(aa, bb) {\n    const aArr = aa.split(\".\");\n    const bArr = bb.split(\".\");\n    const min = Math.min(aArr.length, bArr.length);\n    for (let index = 0; index < min; index++) {\n        if (aArr[index] != bArr[index])\n            return (aArr[index] - bArr[index]);\n    }\n    return 0;\n}",
        "outputs": 2,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 270,
        "y": 280,
        "wires": [
            [
                "85fa60362bb04a1a"
            ],
            [
                "33e539048f9a09f1"
            ]
        ]
    },
    {
        "id": "3b8d7efc8f41e5f5",
        "type": "inject",
        "z": "2ab1de6847dd7ea2",
        "name": "erzwungen Patch 7.3.5",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "VersionAddOn",
                "v": "7.3.5",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "Patch,einmal bei neuem Flow",
        "x": 180,
        "y": 380,
        "wires": [
            [
                "85fa60362bb04a1a"
            ]
        ],
        "icon": "font-awesome/fa-play-circle"
    },
    {
        "id": "33e539048f9a09f1",
        "type": "debug",
        "z": "2ab1de6847dd7ea2",
        "name": "Patch aktuell",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "\"Patch aktuell\"",
        "targetType": "jsonata",
        "statusVal": "msg.Process.NodeVersion",
        "statusType": "auto",
        "x": 150,
        "y": 320,
        "wires": []
    },
    {
        "id": "7d35a6579c0a2026",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": ".profile",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "export PATH=/usr/local/addons/redmatic/bin:/usr/local/bin:/usr/bin:$PATH\nexport LD_LIBRARY_PATH=/usr/local/addons/redmatic/lib:/usr/local/lib:/usr/lib\nexport HOME=/usr/local/addons/redmatic/home\nexport GIT_EXEC_PATH=/usr/local/addons/redmatic/libexec/git-core\nexport GIT_TEMPLATE_DIR=/usr/local/addons/redmatic/share/git-core/templates\nexport NO_UPDATE_NOTIFIER=true",
        "output": "str",
        "x": 430,
        "y": 380,
        "wires": [
            [
                "dee60a8eb7a86f2b"
            ]
        ]
    },
    {
        "id": "6de4e13207fb3de5",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": ".profileRoot",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "export PATH=/usr/local/bin\nexport LD_LIBRARY_PATH=/usr/local/lib:/usr/lib\nexport HOME=/usr/local/addons/redmatic/home\nexport GIT_EXEC_PATH=/usr/local/addons/redmatic/libexec/git-core\nexport GIT_TEMPLATE_DIR=/usr/local/addons/redmatic/share/git-core/templates\nexport NO_UPDATE_NOTIFIER=true",
        "output": "str",
        "x": 970,
        "y": 380,
        "wires": [
            [
                "f96c2071a00c11a3"
            ]
        ]
    },
    {
        "id": "70bdbbad9e26b78d",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "Update node-red",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "#!/bin/sh\ncd /usr/local/addons/redmatic/lib\nsource /usr/local/addons/redmatic/home/.profile\n\nlogger -t redmatic -p daemon.info \"Henke Script updateNodeRed.sh\"\n\nVersionWeb=cat npm view node-red version\nnpm install node-red@$VersionWeb\nlogger -t redmatic -p daemon.info \"Henke Script updateNodeRed.sh node-red done\"\nnpm install @node-red-contrib-themes/theme-collection\nlogger -t redmatic -p daemon.info \"Henke Script updateNodeRed.sh theme-collection done\"\n",
        "output": "str",
        "x": 990,
        "y": 340,
        "wires": [
            [
                "9f4a6594386fabb9"
            ]
        ]
    },
    {
        "id": "9f4a6594386fabb9",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "bin/updateNodeRed.sh",
        "filename": "/usr/local/addons/redmatic/bin/updateNodeRed.sh",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1200,
        "y": 340,
        "wires": [
            [
                "7d35a6579c0a2026"
            ]
        ]
    },
    {
        "id": "85fa60362bb04a1a",
        "type": "file in",
        "z": "2ab1de6847dd7ea2",
        "name": "",
        "filename": "/boot/VERSION",
        "filenameType": "str",
        "format": "utf8",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 460,
        "y": 140,
        "wires": [
            [
                "aec8a9833a7f477a"
            ]
        ]
    },
    {
        "id": "aec8a9833a7f477a",
        "type": "function",
        "z": "2ab1de6847dd7ea2",
        "name": "RasberryMatic?",
        "func": "if ( msg.payload.indexOf(\"PRODUCT=raspmatic\") < 0 )\n{\n    node.warn(\"Kein RasberryMatic\");\n    return;\n}\n\nconst key = \"VERSION=\";\nlet ist = msg.payload.substring(msg.payload.indexOf(key) + key.length);\nist = ist.substring ( 0, ist.indexOf(\"\\n\"));\n// msg.ist = ist;\nlet ref = \"3.71.12.20231013\";\nlet cmp = cmpVersion(ist, ref);\nmsg.node_js_ok = (cmp >=0);\nreturn msg;\n\nfunction cmpVersion(aa, bb) {\n    const aArr = aa.split(\".\");\n    const bArr = bb.split(\".\");\n    const min = Math.min(aArr.length, bArr.length);\n    for (let index = 0; index < min; index++) {\n        if (aArr[index] != bArr[index])\n            return (aArr[index] - bArr[index]);\n    }\n    return 0;\n}",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 700,
        "y": 140,
        "wires": [
            [
                "4c6951d8ab085736"
            ]
        ]
    },
    {
        "id": "f1c29c21b7b7338a",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "Schreibe Script",
        "filename": "/usr/local/update/_run.sh",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1180,
        "y": 140,
        "wires": [
            [
                "0f65a59c71d5cefe"
            ]
        ]
    },
    {
        "id": "0f65a59c71d5cefe",
        "type": "exec",
        "z": "2ab1de6847dd7ea2",
        "command": "sh /usr/local/update/_run.sh",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "Ausführen",
        "x": 1410,
        "y": 140,
        "wires": [
            [],
            [
                "ffa53e6eff89319c"
            ],
            [
                "e435bc41d8c9739d"
            ]
        ]
    },
    {
        "id": "ffa53e6eff89319c",
        "type": "debug",
        "z": "2ab1de6847dd7ea2",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 1525,
        "y": 140,
        "wires": [],
        "l": false
    },
    {
        "id": "2d6177b5c2a97ca9",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "Schreibe Script",
        "filename": "/usr/local/update/_run.sh",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 700,
        "y": 480,
        "wires": [
            [
                "9e84ed95b487240c"
            ]
        ]
    },
    {
        "id": "9e84ed95b487240c",
        "type": "exec",
        "z": "2ab1de6847dd7ea2",
        "command": "sh /usr/local/update/_run.sh",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "Ausführen",
        "x": 870,
        "y": 480,
        "wires": [
            [],
            [
                "7d14f0f429c0f826"
            ],
            [
                "1900d9b72af1a2d8"
            ]
        ]
    },
    {
        "id": "7d14f0f429c0f826",
        "type": "debug",
        "z": "2ab1de6847dd7ea2",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 975,
        "y": 480,
        "wires": [],
        "l": false
    },
    {
        "id": "eda7f0ecc302657e",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "Schreibe Script",
        "filename": "/usr/local/update/_run.sh",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1240,
        "y": 480,
        "wires": [
            [
                "591f97800f8e5ab6"
            ]
        ]
    },
    {
        "id": "591f97800f8e5ab6",
        "type": "exec",
        "z": "2ab1de6847dd7ea2",
        "command": "sh /usr/local/update/_run.sh",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "Ausführen",
        "x": 1410,
        "y": 480,
        "wires": [
            [],
            [
                "abb099706360873f"
            ],
            [
                "42584b3b89350e87"
            ]
        ]
    },
    {
        "id": "abb099706360873f",
        "type": "debug",
        "z": "2ab1de6847dd7ea2",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 1535,
        "y": 480,
        "wires": [],
        "l": false
    },
    {
        "id": "dee60a8eb7a86f2b",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "home/.profile",
        "filename": "/usr/local/addons/redmatic/home/.profile",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 690,
        "y": 380,
        "wires": [
            [
                "6de4e13207fb3de5"
            ]
        ]
    },
    {
        "id": "f96c2071a00c11a3",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "home/.profileRoot",
        "filename": "/usr/local/addons/redmatic/home/.profileRoot",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1190,
        "y": 380,
        "wires": [
            [
                "0aa2148e71e010d7"
            ]
        ]
    },
    {
        "id": "9d7cfabd2bbf2be3",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "checkNR.js",
        "field": "payload",
        "fieldType": "msg",
        "format": "javascript",
        "syntax": "plain",
        "template": "const fs = require('fs');\n\nconst addOn = '/usr/local/addons/redmatic/';\nconst settings = addOn + '/etc/settings.json';\nconst restartOnCrash = require(settings).restartOnCrash;\n// console.log(\"RedMatic settings.js NodeRed: \" + restartOnCrash );\nlet out = \"\";\n\nlet runUpdateNodeRed = false;\n{\n    let msg = {};\n\n    try {\n        const nodeRed = addOn + 'lib/node_modules/node-red/package.json';\n        const nodeRedVersion = require(nodeRed).version;\n//        console.info(\"RedMatic checkNR.js NodeRed: \" + nodeRedVersion);\n        msg.payload = nodeRedVersion;\n        msg.AddOn_ok = (cmpVersion(nodeRedVersion, \"3.0.0\") >= 0);\n        if (!msg.AddOn_ok)\n            runUpdateNodeRed = true;\n    }\n    catch\n    {\n//        console.error(\"RedMatic checkNR.js Error NodeRed fehlt?\");\n        runUpdateNodeRed = true;\n    }\n\n    function cmpVersion(aa, bb) {\n        const aArr = aa.split(\".\");\n        const bArr = bb.split(\".\");\n        const min = Math.min(aArr.length, bArr.length);\n        for (let index = 0; index < min; index++) {\n            if (aArr[index] != bArr[index])\n                return (aArr[index] - bArr[index]);\n        }\n        return 0;\n    }\n\n    const prefix = \"RedSettings_\";\n    out += prefix + \"RestartOnCrash\" + \"=\" + restartOnCrash + \"\\n\";\n    out += prefix + \"NodeRedUpdate\" + \"=\" + runUpdateNodeRed + \"\\n\";\n\n    fs.writeFileSync('/tmp/red-settings', out);\n}\n\n//process.stdout.write(out);",
        "output": "str",
        "x": 450,
        "y": 420,
        "wires": [
            [
                "227744a2ca3ffd24"
            ]
        ]
    },
    {
        "id": "227744a2ca3ffd24",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "bin/checkNR.js",
        "filename": "/usr/local/addons/redmatic/bin/checkNR.js",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 700,
        "y": 420,
        "wires": [
            [
                "372b8ef8e105c0ba"
            ]
        ]
    },
    {
        "id": "61fccb767b94a8ac",
        "type": "inject",
        "z": "2ab1de6847dd7ea2",
        "name": "Patch 7.3.5",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "VersionAddOn",
                "v": "7.3.5",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "Patch,einmal bei neuem Flow",
        "x": 270,
        "y": 220,
        "wires": [
            [
                "8abba785cac84dc4"
            ]
        ],
        "icon": "font-awesome/fa-play-circle"
    },
    {
        "id": "1e9fdeab1ba13c95",
        "type": "comment",
        "z": "2ab1de6847dd7ea2",
        "name": "Hit me...",
        "info": "",
        "x": 100,
        "y": 220,
        "wires": []
    },
    {
        "id": "5ada11e830a3b224",
        "type": "comment",
        "z": "2ab1de6847dd7ea2",
        "name": "Warnung: NodeRed wird neu gestartet!",
        "info": "",
        "x": 190,
        "y": 180,
        "wires": []
    },
    {
        "id": "372b8ef8e105c0ba",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": "redmaticVersions",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "#!/bin/sh\n\n# Henke Version 1.1\nlogger -t redmatic -p daemon.info \"Henke Script redmaticVersions $1\"\n\nADDON_DIR=/usr/local/addons/redmatic\nGLOBAL_MODULES=$ADDON_DIR/lib/node_modules\nLOCAL_MODULES=$ADDON_DIR/var/node_modules\n\n#NODE=$ADDON_DIR/bin/node\n\nexport PATH=$ADDON_DIR/bin:$PATH\nexport LD_LIBRARY_PATH=$ADDON_DIR/lib:$LD_LIBRARY_PATH\nexport NO_UPDATE_NOTIFIER=true\n\nsource $ADDON_DIR/versions\n\nJO_ARGS=\"\"\n\n#scan_dir()\n#{\n#    for dir in $1/*\n#    do\n#        dir=${dir%*/}\n#        PKG=${dir##*/}\n#        PKGJSON=$1/$PKG/package.json\n#        if [[ -f \"$PKGJSON\" ]]; then\n#            JO_ARGS=\"$JO_ARGS `jq -r '.name' $1/$PKG/package.json`=`jq -r '.version' $1/$PKG/package.json`\"\n#        fi\n#        case $PKG in @*)\n#            scan_dir \"$1/$PKG\"\n#        esac\n#    done\n#}\n\n#scan_dir $GLOBAL_MODULES\n#scan_dir $LOCAL_MODULES\n\nsource /VERSION\n\nif [ -d /etc/piVCCU3 ]; then\n    PRODUCT=\"pivccu3\"\nfi\n\nPLATFORM=\"$PLATFORM-`uname -m`\"\nnodejs=`node --version | cut -c 2-`\necho '{\"ccu\": {\"VERSION\": \"'$VERSION'\", \"PRODUCT\": \"'$PRODUCT'\",\"PLATFORM\": \"'$PLATFORM'\"},\"redmatic\": \"'$VERSION_ADDON'\",\"nodejs\": \"'$nodejs'\"}'\n\n#jo -p ccu=`(echo \"VERSION=$VERSION\"; echo \"PRODUCT=$PRODUCT\"; echo \"PLATFORM=$PLATFORM\" && echo -n \"deviceTypes=\" && $ADDON_DIR/bin/deviceTypes) | jo` \\\n#jo -p ccu=`(echo \"VERSION=$VERSION\"; echo \"PRODUCT=$PRODUCT\"; echo \"PLATFORM=$PLATFORM\" ) | jo` \\\n#    redmatic=$VERSION_ADDON \\\n#    nodejs=`node --version | cut -c 2-` \\\n#    $JO_ARGS\n\n",
        "output": "str",
        "x": 990,
        "y": 420,
        "wires": [
            [
                "40d4e066a89307f4"
            ]
        ]
    },
    {
        "id": "40d4e066a89307f4",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "bin/redmaticVersions",
        "filename": "/usr/local/addons/redmatic/bin/redmaticVersions",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1200,
        "y": 420,
        "wires": [
            [
                "0ea2818262334c44"
            ]
        ]
    },
    {
        "id": "0aa2148e71e010d7",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "name": ".npmrc",
        "field": "payload",
        "fieldType": "msg",
        "format": "markdown",
        "syntax": "plain",
        "template": "prefix=/usr/local\ncache=/tmp/npm-cache\n",
        "output": "str",
        "x": 1390,
        "y": 380,
        "wires": [
            [
                "c1fc15dc666dfe56"
            ]
        ]
    },
    {
        "id": "c1fc15dc666dfe56",
        "type": "file",
        "z": "2ab1de6847dd7ea2",
        "name": "home/.profileRoot",
        "filename": "/usr/local/addons/redmatic/home/.npmrc",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 1550,
        "y": 380,
        "wires": [
            [
                "0ea2818262334c44"
            ]
        ]
    },
    {
        "id": "665899be2814dfb7",
        "type": "group",
        "z": "2ab1de6847dd7ea2",
        "style": {
            "stroke": "#2e333a",
            "stroke-opacity": "1",
            "fill": "#2e333a",
            "fill-opacity": "0.75",
            "label": true,
            "label-position": "nw",
            "color": "#a4a4a4"
        },
        "nodes": [
            "e28522bbbf4ccec3",
            "62227816a2ee54e2",
            "42584b3b89350e87",
            "0270d062629f4e2c"
        ],
        "x": 1494,
        "y": 619,
        "w": 452,
        "h": 122
    },
    {
        "id": "e28522bbbf4ccec3",
        "type": "inject",
        "z": "2ab1de6847dd7ea2",
        "g": "665899be2814dfb7",
        "name": "Warnung: NodeRed wird neu gestartet!",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "true",
        "payloadType": "bool",
        "x": 1690,
        "y": 660,
        "wires": [
            [
                "42584b3b89350e87"
            ]
        ]
    },
    {
        "id": "62227816a2ee54e2",
        "type": "http request",
        "z": "2ab1de6847dd7ea2",
        "g": "665899be2814dfb7",
        "name": "Local",
        "method": "POST",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://127.0.0.0:8181/a.exe",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 1790,
        "y": 700,
        "wires": [
            [
                "0270d062629f4e2c"
            ]
        ]
    },
    {
        "id": "42584b3b89350e87",
        "type": "template",
        "z": "2ab1de6847dd7ea2",
        "g": "665899be2814dfb7",
        "name": "Restart NodeRed",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "system.Exec(\"/usr/local/addons/redmatic/bin/redmatic restart &\");",
        "output": "str",
        "x": 1630,
        "y": 700,
        "wires": [
            [
                "62227816a2ee54e2"
            ]
        ]
    },
    {
        "id": "0270d062629f4e2c",
        "type": "debug",
        "z": "2ab1de6847dd7ea2",
        "g": "665899be2814dfb7",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": true,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "counter",
        "x": 1885,
        "y": 700,
        "wires": [],
        "l": false
    }
]
und dann über den flow das Update node.js starten.
Zuletzt geändert von Henke am 16.02.2024, 14:39, insgesamt 1-mal geändert.

Matten Matten
Beiträge: 286
Registriert: 09.12.2018, 17:14
System: CCU
Hat sich bedankt: 70 Mal
Danksagung erhalten: 24 Mal
Kontaktdaten:

Re: RedMatic Update 7.3.5

Beitrag von Matten Matten » 20.01.2024, 10:17

Henke hat geschrieben:
20.01.2024, 04:48
Bei den beiden vorherigen Problemen wurde es aktualisiert auf 20.10.0.
Das auch verstehe ich daher nicht.
Guten morgen henke sorry war ein langer tag gestern. das "auch" ist fehl am platz.

hab folgendes erledigt:
  • Backup gemacht
  • den Flow importiert
  • den Flow "erzwungenen Patch" drüber gebügelt (gestartet)
  • danach den Flow Update node.js/npm gestartet
  • danach einmal "node --version" abgefragt jedoch spuckt er immer noch v18.18.2 aus.
CCU reboot gemacht keine Änderung.

Benutzeravatar
Henke
Beiträge: 1538
Registriert: 27.06.2022, 20:51
System: CCU
Hat sich bedankt: 144 Mal
Danksagung erhalten: 312 Mal

Re: RedMatic Update 7.3.5

Beitrag von Henke » 20.01.2024, 17:02

Und mit "npm doctor" unter Tools kommt auch die 18.18.2?

Matten Matten
Beiträge: 286
Registriert: 09.12.2018, 17:14
System: CCU
Hat sich bedankt: 70 Mal
Danksagung erhalten: 24 Mal
Kontaktdaten:

Re: RedMatic Update 7.3.5

Beitrag von Matten Matten » 20.01.2024, 21:38

Henke hat geschrieben:
20.01.2024, 17:02
Und mit "npm doctor" unter Tools kommt auch die 18.18.2?
ja.

Code: Alles auswählen

Check                               Value   Recommendation/Notes
npm ping                            ok       
npm -v                              ok      current: v10.3.0, latest: v10.3.0
node -v                             not ok  Use node v20.11.0 (current: v18.18.2)
npm config get registry             ok      using default registry (https://registry.npmjs.org/)
git executable in PATH              ok      /usr/local/addons/redmatic/bin/git
global bin folder in PATH           ok      /usr/local/bin
Perms check on cached files         ok       
Perms check on local node_modules   ok       
Perms check on global node_modules  ok       
Perms check on local bin folder     ok       
Perms check on global bin folder    ok       
Verify cache contents               ok      verified 2 tarballs
hab heut nur keine Zeit mehr um weiter zu forschen. zumal es aktuell mich nirgendwo behindert.

Gruß
Matten Matten

fischmir
Beiträge: 972
Registriert: 03.02.2014, 18:04
Wohnort: Münsterland
Hat sich bedankt: 27 Mal
Danksagung erhalten: 8 Mal

Re: RedMatic Update 7.3.5

Beitrag von fischmir » 22.01.2024, 08:03

Hallo zusammen,

ich habe den Flow runtergeladen, importiert und gestartet.

Wo sehe ich denn die Versionsnummer um prüfen zu können, ob das Update funktioniert hat?

Danke und Grüße
fischmir

Matten Matten
Beiträge: 286
Registriert: 09.12.2018, 17:14
System: CCU
Hat sich bedankt: 70 Mal
Danksagung erhalten: 24 Mal
Kontaktdaten:

Re: RedMatic Update 7.3.5

Beitrag von Matten Matten » 22.01.2024, 20:02

fischmir hat geschrieben:
22.01.2024, 08:03
Wo sehe ich denn die Versionsnummer um prüfen zu können, ob das Update funktioniert hat?
unter Systemsteuerung->Zusatzsoftware

Antworten

Zurück zu „RedMatic“