Pekaway Connect: die neue App

Lagesensor Flow:

Dieser Flow ist komplett neu und noch nicht fertig(!), da fehlen noch einige Einstellungsmöglichkeiten und Anzeigen für das Frontend, aber im Prinzip läuft er schon, wenn ihr einen MPU6050 habt könnt ihr mit dem dazugehörigen PythonScript die Werte auslesen:

[{"id":"3739bebe6c778cd3","type":"tab","label":"position sensor","disabled":false,"info":"","env":[]},{"id":"f50f27a0bc038b47","type":"function","z":"3739bebe6c778cd3","name":"Offset hinzufügen","func":"// Erhalten der Eingangsdaten\nvar eingangsdaten = msg.payload;\n\n// Kalibrierungswert aus der globalen Variable verwenden\nvar kalibrierungswert = global.get(\"calibration_value_x\") || 0; // Standardwert ist 0, falls nicht gesetzt\n\n// Anpassen der Daten um den Kalibrierungswert\nvar datenMitKalibrierung = eingangsdaten - kalibrierungswert;\n\n// Auf eine Dezimalstelle runden\nvar gerundeteDaten = datenMitKalibrierung.toFixed(1); // 1 steht für eine Dezimalstelle\n\n// Wenn der gerundete Wert 0 ist, auf 0.0 ändern\nif (Number(gerundeteDaten) === 0) {\n    gerundeteDaten = \"0.0\";\n}\n\n// Weiterleiten der modifizierten und gerundeten Daten\nmsg.payload = parseFloat(gerundeteDaten); // Als Zahl statt String zurückgeben\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1410,"y":300,"wires":[["eb2be90032ddbb37","5d2e0c6b945bb6ca"]]},{"id":"99c6d65d1486302f","type":"smooth","z":"3739bebe6c778cd3","name":"","property":"payload","action":"mean","count":"2","round":"1","mult":"single","reduce":false,"x":1220,"y":300,"wires":[["f50f27a0bc038b47"]]},{"id":"e46980325aa122bc","type":"function","z":"3739bebe6c778cd3","name":"Offset hinzufügen","func":"// Erhalten der Eingangsdaten\nvar eingangsdaten = msg.payload;\n\n// Kalibrierungswert aus der globalen Variable verwenden\nvar kalibrierungswert = global.get(\"calibration_value_y\") || 0; // Standardwert ist 0, falls nicht gesetzt\n\n// Anpassen der Daten um den Kalibrierungswert\nvar datenMitKalibrierung = eingangsdaten - kalibrierungswert;\n\n// Auf eine Dezimalstelle runden\nvar gerundeteDaten = datenMitKalibrierung.toFixed(1); // 1 steht für eine Dezimalstelle\n\n// Wenn der gerundete Wert 0 ist, auf \"0.0\" ändern\nif (Number(gerundeteDaten) === 0) {\n    gerundeteDaten = \"0.0\";\n}\n\n// Weiterleiten der modifizierten und gerundeten Daten\nmsg.payload = parseFloat(gerundeteDaten); // Als Zahl statt String zurückgeben\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1410,"y":360,"wires":[["b848e084c8135cb7","eb0e4d09392a8a43"]]},{"id":"02a45f9f766e8ed7","type":"smooth","z":"3739bebe6c778cd3","name":"","property":"payload","action":"mean","count":"2","round":"1","mult":"single","reduce":false,"x":1220,"y":360,"wires":[["e46980325aa122bc"]]},{"id":"1f78a9c366e84c7e","type":"ui_template","z":"3739bebe6c778cd3","group":"f89e1392760d829e","name":"IMG NICK","order":1,"width":6,"height":4,"format":"\n\n<div style='width:100%; height:100%; display:flex; justify-content:center; align-items:center;'>\n    <div id='image-container' style='position: relative;'>\n        <img id='image-to-rotate' src='http://pekaway.local/images/van_side' style='transform: rotate({{msg.payload}}deg);' />\n        <div id='line'\n            style='position: absolute; width: 100%; height: 3px; background-color: grey; top: 96%; transform: translateY(-50%); z-index: -1;'>\n        </div>\n    </div>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":2130,"y":400,"wires":[[]]},{"id":"b848e084c8135cb7","type":"function","z":"3739bebe6c778cd3","name":"Rotate Image","func":"// Erhalten der Winkelinformation (z. B. über MQTT)\nvar angle = msg.payload; // Der Rotationswinkel in Grad\n\n// Wert des Payloads verdoppeln\nmsg.deg = msg.payload * 3;\n\n// CSS-Transformation zur Rotation des Bilds\nvar transformation = \"rotate(\" + msg.deg + \"deg)\";\n\n// Senden Sie die Transformation zurück\nmsg.ui_control = {\n    \"angular\": true,\n    \"rotate\": transformation\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1620,"y":360,"wires":[[]]},{"id":"dba3eb11dced800d","type":"ui_text","z":"3739bebe6c778cd3","group":"f89e1392760d829e","order":2,"width":6,"height":1,"name":"Winkel Nick","label":"","format":"← {{msg.payload}} →","layout":"row-center","className":"","x":1910,"y":360,"wires":[]},{"id":"dcb2407493d93563","type":"ui_template","z":"3739bebe6c778cd3","group":"","name":"Stylesheet Winkel","order":5,"width":0,"height":0,"format":"<style>\n[node-id=\"3409d4236d412e95\"] .value {\nfont-size: 2.9em;\nfont-weight: 100;\n}\n\n</style>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":2110,"y":360,"wires":[[]]},{"id":"7689c36c4b4dc602","type":"ui_button","z":"3739bebe6c778cd3","name":"Start Calibration","group":"f89e1392760d829e","order":5,"width":6,"height":1,"passthru":true,"label":"Calibrate position sensor","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"start_calibration","payloadType":"str","topic":"start_calibration","topicType":"str","x":240,"y":180,"wires":[["736e6e74dd4099c1","7625b64c194676df","ea251b4e38d7ad0e","295e95de4318d1b8","8d6625f941a1734f"]]},{"id":"736e6e74dd4099c1","type":"function","z":"3739bebe6c778cd3","name":"Kalibrierungsfunktion X","func":"// Variablen für die Kalibrierung\nlet calibrationDatax = context.get(\"calibrationData_x\") || [];\nlet timer = context.get(\"timer\") || null;\n\n// Startet die Kalibrierung bei einer Nachricht vom Button\nif (msg.topic === \"start_calibration\" && !timer) {\n    calibrationDatax = [];\n    context.set(\"calibrationData_x\", calibrationDatax);\n\n    timer = setTimeout(() => {\n        let sum = calibrationDatax.reduce((a, b) => a + b, 0);\n        let avg = calibrationDatax.length > 0 ? sum / calibrationDatax.length : 0;\n        global.set(\"calibration_value_x\", avg); // Speichert das Ergebnis in der globalen Variable\n        context.set(\"timer\", null);\n        node.send({ payload: avg });\n    }, 5000); // Kalibrierungszeitraum: 5 Sekunden\n\n    context.set(\"timer\", timer);\n    return;\n}\n\n// Sammelt Daten, wenn eine Nachricht vom Sensor empfangen wird\nif (msg.topic === \"x_angle\"&& timer) {\n    let value = parseFloat(msg.payload);\n    if (!isNaN(value)) {\n        calibrationDatax.push(value);\n        context.set(\"calibrationData_x\", calibrationDatax);\n    }\n}\n\nreturn null; // Sendet keine Nachricht, bis der Timer abläuft\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":140,"wires":[[]]},{"id":"7625b64c194676df","type":"function","z":"3739bebe6c778cd3","name":"Kalibrierungsfunktion Y","func":"// Variablen für die Kalibrierung\nlet calibrationData = context.get(\"calibrationData_y\") || [];\nlet timer = context.get(\"timer\") || null;\n\n// Startet die Kalibrierung bei einer Nachricht vom Button\nif (msg.topic === \"start_calibration\" && !timer) {\n    calibrationData = [];\n    context.set(\"calibrationData_y\", calibrationData);\n\n    timer = setTimeout(() => {\n        let sum = calibrationData.reduce((a, b) => a + b, 0);\n        let avg = calibrationData.length > 0 ? sum / calibrationData.length : 0;\n        global.set(\"calibration_value_y\", avg); // Speichert das Ergebnis in der globalen Variable\n        context.set(\"timer\", null);\n        node.send({ payload: avg });\n    }, 5000); // Kalibrierungszeitraum: 5 Sekunden\n\n    context.set(\"timer\", timer);\n    return;\n}\n\n// Sammelt Daten, wenn eine Nachricht vom Sensor empfangen wird\nif (msg.topic === \"y_angle\" && timer) {\n    let value = parseFloat(msg.payload);\n    if (!isNaN(value)) {\n        calibrationData.push(value);\n        context.set(\"calibrationData_y\", calibrationData);\n    }\n}\n\nreturn null; // Sendet keine Nachricht, bis der Timer abläuft\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":180,"wires":[["de3b646ac20702e7"]]},{"id":"e1981fc3d5bd5dcd","type":"ui_toast","z":"3739bebe6c778cd3","position":"top right","displayTime":"5","highlight":"","sendall":false,"outputs":0,"ok":"OK","cancel":"","raw":false,"className":"","topic":"","name":"","x":690,"y":100,"wires":[]},{"id":"ea251b4e38d7ad0e","type":"function","z":"3739bebe6c778cd3","name":"calibrating...","func":"msg.payload = \"Calibrating position sensor...\"\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":490,"y":140,"wires":[["e1981fc3d5bd5dcd"]]},{"id":"eaf79c9ddd746cfb","type":"ui_template","z":"3739bebe6c778cd3","group":"f89e1392760d829e","name":"IMG ROLL","order":3,"width":6,"height":4,"format":"\n\n<div style='width:100%; height:100%; display:flex; justify-content:center; align-items:center;'>\n    <div id='image-container' style='position: relative;'>\n        <img id='image-to-rotate' src='http://pekaway.local/images/van_back' style='transform: rotate({{msg.deg}}deg);' />\n        <div id='line'\n            style='position: absolute; width: 100%; height: 3px; background-color: grey; top: 96%; transform: translateY(-50%); z-index: -1;'>\n        </div>\n    </div>\n</div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"","x":2130,"y":260,"wires":[[]]},{"id":"5d2e0c6b945bb6ca","type":"function","z":"3739bebe6c778cd3","name":"Rotate Image","func":"// Erhalten der Winkelinformation (z. B. über MQTT)\nvar angle = msg.payload; // Der Rotationswinkel in Grad\n\n// Wert des Payloads verdoppeln\nmsg.deg = msg.payload * 3;\n\n// CSS-Transformation zur Rotation des Bilds\nvar transformation = \"rotate(\" + msg.deg + \"deg)\";\n\n// Senden Sie die Transformation zurück\nmsg.ui_control = {\n    \"angular\": true,\n    \"rotate\": transformation\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1620,"y":300,"wires":[[]]},{"id":"3fbb529e13212092","type":"ui_text","z":"3739bebe6c778cd3","group":"f89e1392760d829e","order":4,"width":6,"height":1,"name":"Winkel ROLL","label":"","format":"← {{msg.payload}} →","layout":"row-center","className":"","x":1930,"y":300,"wires":[]},{"id":"0eb6abde1cefb6f2","type":"ui_template","z":"3739bebe6c778cd3","group":"","name":"Stylesheet Winkel","order":5,"width":0,"height":0,"format":"<style>\n[node-id=\"b0736d584b4ecc68\"] .value {\nfont-size: 2.9em;\nfont-weight: 100;\n}\n\n</style>\n\n\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"global","className":"","x":2110,"y":300,"wires":[[]]},{"id":"e661be93174a3c06","type":"exec","z":"3739bebe6c778cd3","command":"python3 pekaway/mpu_py/mpuAngle.py","addpay":"payload","append":"","useSpawn":"true","timer":"","winHide":false,"oldrc":false,"name":"mpuAngle.py","x":670,"y":280,"wires":[["d793139abfd73467"],[],[]]},{"id":"d793139abfd73467","type":"json","z":"3739bebe6c778cd3","name":"","property":"payload","action":"","pretty":false,"x":850,"y":280,"wires":[["b5902b221bf2671b","215de84e496cf31f"]]},{"id":"b5902b221bf2671b","type":"function","z":"3739bebe6c778cd3","name":"filter values","func":"let msgX = {}\nlet msgY = {}\nlet msgT = {}\nmsgX.payload = Number(msg.payload.x_angle);\nmsgX.topic = \"x_angle\";\n//node.send([msg, null, null])\nmsgY.payload = Number(msg.payload.y_angle);\nmsgY.topic = \"y_angle\";\n//node.send([null, msg, null])\nmsgT.payload = msg.payload.mpu_temp.toFixed(1);\n//node.send([null, null, msg])\nreturn [msgX, msgY, msgT]","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1010,"y":280,"wires":[["736e6e74dd4099c1","99c6d65d1486302f"],["7625b64c194676df","02a45f9f766e8ed7"],[]]},{"id":"de3b646ac20702e7","type":"function","z":"3739bebe6c778cd3","name":"kill then => time 5","func":"msg.kill = \"SIGKILL\";\nnode.send(msg);\n\nsetTimeout(function () {\n    delete msg.kill;\n    msg.payload = \"--time 5\";\n    node.send(msg);\n}, 500);  // milliseconds delay","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1470,"y":180,"wires":[["e661be93174a3c06"]]},{"id":"215de84e496cf31f","type":"debug","z":"3739bebe6c778cd3","name":"debug 98","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1000,"y":320,"wires":[]},{"id":"9405f0312e7b530c","type":"function","z":"3739bebe6c778cd3","name":"time 5","func":"delete msg.kill\nmsg.payload = \"--time 5\"\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1130,"y":520,"wires":[["c72e374c3e18cf30"]]},{"id":"295e95de4318d1b8","type":"function","z":"3739bebe6c778cd3","name":"kill then => time 0.5","func":"msg.kill = \"SIGKILL\";\nnode.send(msg);\n\nsetTimeout(function () {\n    delete msg.kill;\n    msg.payload = \"--time 0.5\";\n    node.send(msg);\n}, 1000);  // milliseconds delay","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":200,"wires":[["e661be93174a3c06"]]},{"id":"8d6625f941a1734f","type":"delay","z":"3739bebe6c778cd3","name":"5.3s","pauseType":"delay","timeout":"5.3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":390,"y":100,"wires":[["ef2c0086391012ae"]]},{"id":"ef2c0086391012ae","type":"function","z":"3739bebe6c778cd3","name":"done","func":"msg.payload = \"Calibration done\"\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":100,"wires":[["e1981fc3d5bd5dcd"]]},{"id":"2f39cbd1b882b3e5","type":"inject","z":"3739bebe6c778cd3","name":"","props":[{"p":"payload"},{"p":"name","v":"Position Sensor","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"15","topic":"","payload":"","payloadType":"date","x":130,"y":540,"wires":[["2c56fd6e65d34c56"]]},{"id":"e3cd1d26208cb692","type":"exec","z":"3739bebe6c778cd3","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":510,"y":540,"wires":[["28d29a321847e02c"],[],[]]},{"id":"2c56fd6e65d34c56","type":"function","z":"3739bebe6c778cd3","name":"check processes","func":"delete msg.reset\nmsg.payload = \"ps aux | grep mpuAngle\"\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":540,"wires":[["e3cd1d26208cb692"]]},{"id":"28d29a321847e02c","type":"split","z":"3739bebe6c778cd3","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"","x":630,"y":540,"wires":[["e88f4ba0f4d1d09e"]]},{"id":"e88f4ba0f4d1d09e","type":"function","z":"3739bebe6c778cd3","name":"kill?","func":"if (msg.payload.includes(\"mpuAngle.py --time\")) {\n    const match = msg.payload.match(/\\b\\w+\\s+(\\d+)/)\n    msg.pid = match ? parseInt(match[1], 10) : null\n    if (msg.pid == null) {\n        return [msg, null]\n    }\n    else {\n        msg.kill = \"SIGKILL\";\n        // msg.payload = \"sudo pkill -f 'python3.*mpuAngle.py.*'\"\n        return [msg, msg]\n    }\n}\nelse return [msg, null ]","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":540,"wires":[["0123f1a21f90df33"],["8efd01a8cc1df5c1"]]},{"id":"0123f1a21f90df33","type":"delay","z":"3739bebe6c778cd3","name":"","pauseType":"rate","timeout":"0.1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"2","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":940,"y":520,"wires":[["9405f0312e7b530c"]]},{"id":"526759393f6f5f68","type":"ui_button","z":"3739bebe6c778cd3","name":"Start reading","group":"f89e1392760d829e","order":5,"width":6,"height":1,"passthru":true,"label":"Start reading values","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"start_fast_read","payloadType":"str","topic":"","topicType":"str","x":230,"y":280,"wires":[["339615045b1bfa7f","8d848d0e113ab89e"]]},{"id":"339615045b1bfa7f","type":"function","z":"3739bebe6c778cd3","name":"kill then => time 0.25","func":"msg.kill = \"SIGKILL\";\nnode.send(msg);\n\nsetTimeout(function () {\n    delete msg.kill;\n    msg.payload = \"--time 0.25\";\n    node.send(msg);\n}, 500);  // milliseconds delay","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":280,"wires":[["e661be93174a3c06","c24897059bbc9fcb"]]},{"id":"c645aa409e021565","type":"ui_button","z":"3739bebe6c778cd3","name":"Stop reading","group":"f89e1392760d829e","order":5,"width":6,"height":1,"passthru":true,"label":"Stop reading values","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"stop_fast_read","payloadType":"str","topic":"","topicType":"str","x":230,"y":380,"wires":[["a25b0d3ed530fb58"]]},{"id":"a25b0d3ed530fb58","type":"function","z":"3739bebe6c778cd3","name":"reset","func":"\nmsg.reset = true\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":380,"wires":[["2c56fd6e65d34c56","8d848d0e113ab89e"]]},{"id":"c72e374c3e18cf30","type":"delay","z":"3739bebe6c778cd3","name":"2s","pauseType":"delay","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1290,"y":520,"wires":[["e661be93174a3c06"]]},{"id":"6619f21f66ccc3a3","type":"link in","z":"3739bebe6c778cd3","name":"positionSensor start","links":["44b78f2a6ec1dafb"],"x":115,"y":280,"wires":[["526759393f6f5f68"]]},{"id":"be30fa7396b2172a","type":"link in","z":"3739bebe6c778cd3","name":"positionSensor stop","links":["ebdf10e1d4ee8666"],"x":115,"y":380,"wires":[["c645aa409e021565"]]},{"id":"4845fbb606ccbbb6","type":"ui_ui_control","z":"3739bebe6c778cd3","name":"","events":"all","x":220,"y":420,"wires":[["91b91b7cc974da25","1f9e364f2c365707"]]},{"id":"91b91b7cc974da25","type":"function","z":"3739bebe6c778cd3","name":"check tab","func":"if (msg.name != \"Position Sensor\" && flow.get(\"tabname\") == \"Position Sensor\") {\n    node.send(msg);\n}\nflow.set(\"tabname\", msg.name);","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":420,"wires":[["2c56fd6e65d34c56"]]},{"id":"1f9e364f2c365707","type":"function","z":"3739bebe6c778cd3","name":"check tab","func":"if (msg.payload == \"change\" && msg.name == \"Position Sensor\") {\n    msg.reset = true\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":320,"wires":[["339615045b1bfa7f"]]},{"id":"7b0d6cce040ff728","type":"comment","z":"3739bebe6c778cd3","name":"mpuAngle.py running with 5s when tab not opened","info":"","x":230,"y":500,"wires":[]},{"id":"e7b8b47f1654f01f","type":"comment","z":"3739bebe6c778cd3","name":"mpuAngle.py running with 0.5s when tab active","info":"","x":320,"y":240,"wires":[]},{"id":"eb0e4d09392a8a43","type":"range","z":"3739bebe6c778cd3","minin":"-45","maxin":"45","minout":"-10","maxout":"10","action":"scale","round":false,"property":"payload","name":"","x":1600,"y":400,"wires":[["4f3b8fba418c2d7d"]]},{"id":"4f3b8fba418c2d7d","type":"function","z":"3739bebe6c778cd3","name":"function 5","func":"msg.payload = Number(msg.payload.toFixed(1))*-1;\nglobal.set(\"y_angle\", msg.payload)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1740,"y":400,"wires":[["5fc2a31f4d9810ef","dba3eb11dced800d"]]},{"id":"5fc2a31f4d9810ef","type":"function","z":"3739bebe6c778cd3","name":"Rotate Image","func":"// Erhalten der Winkelinformation (z. B. über MQTT)\nvar angle = msg.payload; // Der Rotationswinkel in Grad\n\n// Wert des Payloads verdoppeln\nmsg.deg = msg.payload * 4;\n\n// CSS-Transformation zur Rotation des Bilds\nvar transformation = \"rotate(\" + msg.deg + \"deg)\";\n\n// Senden Sie die Transformation zurück\nmsg.ui_control = {\n    \"angular\": true,\n    \"rotate\": transformation\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1920,"y":400,"wires":[["1f78a9c366e84c7e","dba3eb11dced800d"]]},{"id":"eb2be90032ddbb37","type":"range","z":"3739bebe6c778cd3","minin":"-45","maxin":"45","minout":"-10","maxout":"10","action":"scale","round":false,"property":"payload","name":"","x":1600,"y":260,"wires":[["b834a73edcc9df3a"]]},{"id":"b834a73edcc9df3a","type":"function","z":"3739bebe6c778cd3","name":"function 6","func":"msg.payload = Number(msg.payload.toFixed(1));\nglobal.set(\"x_angle\", msg.payload)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1760,"y":260,"wires":[["4c75eab53d356616","3fbb529e13212092"]]},{"id":"4c75eab53d356616","type":"function","z":"3739bebe6c778cd3","name":"Rotate Image","func":"// Erhalten der Winkelinformation (z. B. über MQTT)\nvar angle = msg.payload; // Der Rotationswinkel in Grad\n\n// Wert des Payloads verdoppeln\nmsg.deg = msg.payload * 4;\n\n// CSS-Transformation zur Rotation des Bilds\nvar transformation = \"rotate(\" + msg.deg + \"deg)\";\n\n// Senden Sie die Transformation zurück\nmsg.ui_control = {\n    \"angular\": true,\n    \"rotate\": transformation\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1940,"y":260,"wires":[["eaf79c9ddd746cfb","3fbb529e13212092"]]},{"id":"8d848d0e113ab89e","type":"delay","z":"3739bebe6c778cd3","name":"5m","pauseType":"delay","timeout":"5","timeoutUnits":"minutes","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":390,"y":320,"wires":[["a674e27aa3a674b7"]]},{"id":"a674e27aa3a674b7","type":"delay","z":"3739bebe6c778cd3","name":"1msg/5m","pauseType":"rate","timeout":"0.1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"5","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":520,"y":320,"wires":[["2c56fd6e65d34c56"]]},{"id":"c24897059bbc9fcb","type":"debug","z":"3739bebe6c778cd3","name":"debug 113","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":220,"wires":[]},{"id":"8efd01a8cc1df5c1","type":"delay","z":"3739bebe6c778cd3","name":"1msg/0.3s","pauseType":"rate","timeout":"0.1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"0.3","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":910,"y":560,"wires":[["c237ca3c3d06f36d"]]},{"id":"c237ca3c3d06f36d","type":"function","z":"3739bebe6c778cd3","name":"set cmd","func":"delete msg.kill\ndelete msg.pid\nmsg.payload = \"/usr/bin/sudo pkill -f \\'python3.\\*mpuAngle.py\\'\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1140,"y":560,"wires":[["9c8fa4b038815cd0"]]},{"id":"9c8fa4b038815cd0","type":"exec","z":"3739bebe6c778cd3","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"2.5","winHide":false,"oldrc":false,"name":"kill mpuAngle.py","x":1320,"y":560,"wires":[[],[],[]]},{"id":"a32a3d5947c57eb9","type":"link in","z":"3739bebe6c778cd3","name":"positionSensor calibrate","links":["46505864c3d9e739"],"x":115,"y":180,"wires":[["7689c36c4b4dc602"]]},{"id":"f89e1392760d829e","type":"ui_group","name":"NICK","tab":"44c44161193a7be6","order":1,"disp":false,"width":"6","collapse":false,"className":""},{"id":"44c44161193a7be6","type":"ui_tab","name":"Position Sensor","icon":"fa-arrows","order":4,"disabled":false,"hidden":false}]

Die drei Link-In Nodes

werden mit den Link-Out Nodes im HTTP-Api Flow verbunden (von oben nach unten):

Das Python Script dazu sieht folgendermaßen aus:

import smbus
import math
import time
import json
import argparse

# MPU6050 Registers
MPU6050_ADDR = 0x69
MPU6050_PWR_MGMT_1 = 0x6B
MPU6050_TEMP_OUT_H = 0x41
MPU6050_TEMP_OUT_L = 0x42
MPU6050_ACCEL_XOUT_H = 0x3B
MPU6050_ACCEL_YOUT_H = 0x3D
MPU6050_ACCEL_ZOUT_H = 0x3F
MPU6050_GYRO_XOUT_H = 0x43
MPU6050_GYRO_YOUT_H = 0x45
MPU6050_GYRO_ZOUT_H = 0x47

# Configuration
bus = smbus.SMBus(1)  # or 0 for RPi 1
bus.write_byte_data(MPU6050_ADDR, MPU6050_PWR_MGMT_1, 0)

def read_raw_data(addr):
    high = bus.read_byte_data(MPU6050_ADDR, addr)
    low = bus.read_byte_data(MPU6050_ADDR, addr + 1)
    value = (high << 8) | low
    if value > 32768:
        value -= 65536
    return value

def get_temp():
    raw_temp = read_raw_data(MPU6050_TEMP_OUT_H)
    temp = (raw_temp / 340.0) + 36.53  # Temperature formula for MPU6050
    return temp

def get_accel_data():
    accel_xout = read_raw_data(MPU6050_ACCEL_XOUT_H)
    accel_yout = read_raw_data(MPU6050_ACCEL_YOUT_H)
    accel_zout = read_raw_data(MPU6050_ACCEL_ZOUT_H)
    return accel_xout, accel_yout, accel_zout

def get_gyro_data():
    gyro_xout = read_raw_data(MPU6050_GYRO_XOUT_H)
    gyro_yout = read_raw_data(MPU6050_GYRO_YOUT_H)
    gyro_zout = read_raw_data(MPU6050_GYRO_ZOUT_H)
    return gyro_xout, gyro_yout, gyro_zout
    
def parse_args():
    parser = argparse.ArgumentParser(description="MPU6050 Data Logger")
    parser.add_argument("--time", type=float, default=1, help="Sleep time in seconds (default: 1)")
    return parser.parse_args()

args = parse_args()

while True:
    temp = get_temp()
    accel_x, accel_y, accel_z = get_accel_data()
    gyro_x, gyro_y, gyro_z = get_gyro_data()
    
    x_angle = math.atan(accel_x / 16384.0) * (180 / math.pi)
    y_angle = math.atan(accel_y / 16384.0) * (180 / math.pi)
    
    data = {
        "x_angle": x_angle,
        "y_angle": y_angle,
        "accel_x_raw": accel_x,
        "accel_y_raw": accel_y,
        "accel_z_raw": accel_z,
        "gyro_x_raw": gyro_x,
        "gyro_y_raw": gyro_y,
        "gyro_z_raw": gyro_z,
        "mpu_temp": temp
    }
    
    print(json.dumps(data))
    
    time.sleep(args.time)

Das Script muss den folgenden Pfad haben: /home/pi/pekaway/mpu_py/mpuAngle.py

(An dieser Stelle übrigens auch ein Dankeschön an @Bock.auf.Raus :slight_smile: )

In der App könnt ihr eure eigenen Bilder für den Lagesensor einstellen (nur bei einer lokalen Verbindung), diese Bilder müssen ebenfalls in den Ordner wie das Python Script und die Namen van_back.png und van_side.png haben.

Um die Bilder laden zu können, muss Nginx noch leicht angepasst werden, der Serverblock sieht jetzt folgendermaßen aus (/etc/nginx/sites-available/pekaway1):

server {
	listen 80;
	 server_name peka.way van.pi pekaway.local;
	
	 location / {
		 proxy_pass http://127.0.0.1:1880/ui/;
	}
	location /autoexec.be {
		alias /home/pi/pekaway/autoexec.be; 
		add_header Content-Disposition 'attachment; filename="autoexec.be"';
	}
	location /nspaneltft {	
		alias /home/pi/pekaway/VanPI_NSPANEL.tft; 
		add_header Content-Disposition 'attachment; filename="VanPI_NSPANEL.tft"';
	}
	 location /images/van_side { 
		alias /home/pi/pekaway/mpu_py/van_side.png;
	}
	location /images/van_back {
	alias /home/pi/pekaway/mpu_py/van_front.png;
	}
}

server {
	listen 80;
	server_name homebridge.peka.way;

	 location / {
		proxy_pass http://127.0.0.1:8581/;
	}
}

server {
	listen 80 default_server; 
	listen [::]:80 default_server;
	server_name _;
	
	        
         location /images/van_side {
                alias /home/pi/pekaway/mpu_py/van_side.png;
        }
        location /images/van_back {
        alias /home/pi/pekaway/mpu_py/van_back.png;
        }

	
	# Redirect all requests to pekaway.local
	#return 301 $scheme://pekaway.local$request_uri;
}

Nicht vergessen Nginx neuzustarten:

sudo systemctl restart nginx

Ich hoffe ich habe nichts vergessen…
Zu guter Letzt habt ihr hier nochmal die kompletten Flows (also alle, nicht nur die genannten) als Download (Datei umbenennen und Node-RED neustarten):

Diese Flows haben aber Entwicklungsstatus, sind nicht clean und können Fehler und Bugs enthalten!