Moin Zusammen,
Ich habe mir ein kleines Oled Display in den Van gezimmert, das immer aktiv ist. Ich hatte vorher so einen China Shunt, wo ich immer mit einen Blick sehen konnte wie voll die Batterie ist und irgendwie hab ich das vermisst.
Das Oled zeigt jetzt nicht nur den SOC an, sondern Innen Temperatur , Spannung , Strom und Solar Leistung. Wenn kein Solar ertrag vorhanden ist, dann wird der Tagesertrag (Victron) angezeigt. Zusätzlich wird angezeigt wenn ein Timer gesetzt ist (Heater oder Boiler), ob einen Heizung Aktiv ist, Bolier aktiviert (Boiler Control), Wasserpumpe (Relay), Wechselrichter (Relay) und ein Relay Symbol für was auch immer. Das Ganze kann im UI angepasst werden. Verwendetes Display: 1,3 Zoll OLED Display mit I2C 128 x 64 Pixel Modul Binghe 3 Stück 1,3 Zoll OLED Display, I2C OLED Bildschirm Anzeigemodul mit weißen Zeichen 1106 Chip kompatibel mit Arduino Raspberry Pi: Amazon.de: Gewerbe, Industrie & Wissenschaft
UI:
Display im VAN:
Zur Installation:
OLED Pins sind auf der Platine gekennzeichnet. Am Core kann man gut über das Specshet die Pins vom i2c zuordnen. Oder über Multiout anklemmen. Einfach 1 zu 1 verbinden (3,3v, SDA,SCL,GND)
In Nodered am besten erst die Palette installieren: node-red-contrib-oled-i2c
https://flows.nodered.org/node/node-red-contrib-oled-i2c
Ins Verzeichnis pekaway ein ordner erstellen mit oled und dort die Symbole (PNG) einfügen.
(Bei 12x12 Pixel schöne Symbole zu erstellen hat einiges an Zeit gekostet
)
12x12clean.png ![]()
12x13clean.png ![]()
12x13heater.png ![]()
ac.png ![]()
boileron.png ![]()
relay.png ![]()
timer.png ![]()
water.png ![]()
Wenn die Symbole nicht vorhanden sind, dann bekommt ihr Probleme beim Anzeigen des Displays.
Ganz zum Schluss noch das Skript in Nodered einfügen:
[{"id":"551eaab0c2c1a9cf","type":"tab","label":"userflow_oled","disabled":false,"info":"","env":[]},{"id":"2a1cc0e0b7e76aea","type":"group","z":"551eaab0c2c1a9cf","name":"OLED 0x3c skript by Wulle on Tour","style":{"label":true},"nodes":["0fd54793a1d06082","63cf51b0acf73742","2aa2a7b35bb3f474","7bf38810c9fd4611","27e38ace3d0b160d","58e75167f702c215","384641e022261bfe","75400be909e424e3","5e0b32ae537494ae","77f3c6467c853e08","2a552d348156641c","968ecacc9fdf1941","aba78d8f4e513a90","d9148966e27f8adf","dd493d2f8092996c","04a5e76ec61b6ecb","4656914f348222ac","ca4959d0dd1ef258","3c48020c5409fcf6","30bef72104e83965","119bf80f34b3671d","23788304fc7f925f","8738bac3e75e74f7","e3fcdc711414bf44","84b304739f8377d3","180a2488c88b19fd","27077b1a78c1061a","578b0e0471f41628","b7b51369f75008e0","2bf82591c1dcb2d4","77fd30a19fe6afef","a094f8dd00c5c0c9","f93abb541b904e70","17bcb3a2849ef30a","0f807687ab30f637","8ebefe65efb42144","9c720236f8d564aa","dd02317ddcf854ea","702137a054172cfd","3b092c099decfa67","7564774aaec48d37","353f232efadf6a62","788a8cd061e253c1","fdc1acd1bde4df19","9d56e455c0c53d52","0fbeb914d7946fe4","de5aa5e567627831","ce3b6114fb191494","725b00506e8575bc","7ff2294cbe958a81","78d140fda3d9a27f","9bd23afae3653e6a","9950d9c32faef743","92dedcf7cbe60ed7","0d9f82780b606ac5","214051e4617af0c0","e209e75b36b3c481","035f3b4d9a3f496b"],"x":64,"y":59,"w":1092,"h":962},{"id":"0fd54793a1d06082","type":"String","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":850,"y":140,"wires":[]},{"id":"63cf51b0acf73742","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Innen Temp","func":"//skript by Wulle on Tour\nlet ambientTempSensor = global.get(\"heattempsensor\");\nlet ambientTemp = \"N/A\";\n\n// Sensor auslesen\nswitch (Number(ambientTempSensor)) {\n case 1: ambientTemp = global.get(\"temp1\") ?? \"\"; break;\n case 2: ambientTemp = global.get(\"temp2\") ?? \"\"; break;\n case 3: ambientTemp = global.get(\"temp3\") ?? \"\"; break;\n case 4: ambientTemp = global.get(\"temp4\") ?? \"\"; break;\n case 5: ambientTemp = global.get(\"dimmytemp1\") ?? \"\"; break;\n case 6: ambientTemp = global.get(\"dimmytemp2\") ?? \"\"; break;\n case 7: ambientTemp = global.get(\"ruuvitag_0\")?.temp ?? \"\"; break;\n case 8: ambientTemp = global.get(\"ruuvitag_1\")?.temp ?? \"\"; break;\n case 9: ambientTemp = global.get(\"ruuvitag_2\")?.temp ?? \"\"; break;\n}\n\n// Fallback, falls kein Wert verfügbar\nif (ambientTemp === \"\" || ambientTemp === undefined) {\n ambientTemp = \"N/A\";\n}\n\n// Genau 7 Zeichen formatieren\nif (ambientTemp !== \"N/A\") {\n let temp = Number(ambientTemp).toFixed(1); // 1 Nachkommastelle\n\n // Länge der Zahl + Minus prüfen\n if (temp.length === 3) {\n temp = \" \" + temp; // z.B. \"0.5\"\n } else if (temp.length === 4) {\n temp = \" \" + temp; // z.B. \"12.5\" oder \"-2.5\"\n }\n // 5-stellige Werte wie \"-12.5\" brauchen kein zusätzliches Leerzeichen\n\n ambientTemp = temp;\n}\n\n// Neuen Wert vorbereiten\nlet newText = (ambientTemp !== \"N/A\") ? ambientTemp + \"°C\" : \"N/A\";\n\n// Alten Wert aus Flow holen\nlet oldText = flow.get(\"OLED_ambientTemp\") || \"\";\n\n// Nur senden, wenn Wert sich geändert hat\nif (newText !== oldText) {\n flow.set(\"OLED_ambientTemp\", newText); // neuen Wert merken\n\n msg.payload = {\n size: 1,\n x: 87,\n y: 2,\n text: newText\n };\n return msg;\n} else {\n return null; // nichts senden\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":100,"wires":[["0fd54793a1d06082"]]},{"id":"2aa2a7b35bb3f474","type":"inject","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"30","crontab":"","once":true,"onceDelay":"60","topic":"","payload":"","payloadType":"date","x":340,"y":100,"wires":[["de5aa5e567627831"]]},{"id":"7bf38810c9fd4611","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"MainBatt","func":"// ---------- SOC ----------\nlet soc = global.get(\"MainBattSoc\") || 0;\nsoc = Math.max(0, Math.min(100, Number(soc))); // begrenzen auf 0–100\nlet socStr = soc.toString().padStart(3, \" \");\n\nlet msgSoc = {\n payload: {\n \"size\": 4,\n \"x\": 23,\n \"y\": 20,\n \"text\": socStr\n }\n};\n\n// ---------- % ----------\nlet msgPercent = {\n payload: {\n \"size\": 2,\n \"x\": 88,\n \"y\": 33,\n \"text\": \"%\"\n }\n};\n\n// ---------- VOLT ----------\nlet volt = Number(global.get(\"MainBattVolt\") || 0);\nlet voltStr = volt.toFixed(1).replace(\".\", \",\") + \"V\"; // Format 13,3V\nvoltStr = voltStr.padStart(5, \" \");\n\nlet msgVolt = {\n payload: {\n \"size\": 1,\n \"x\": 1,\n \"y\": 57,\n \"text\": voltStr\n }\n};\n\n// ---------- AMPS ----------\nlet amps = Number(global.get(\"MainBattAmps\") || 0);\nlet ampsStr;\n\nif (Math.abs(amps) >= 99.9) {\n // Keine Nachkommastelle, da sonst >6 Zeichen\n ampsStr = Math.round(amps).toString() + \"A\";\n} else {\n // Mit einer Nachkommastelle\n ampsStr = amps.toFixed(1) + \"A\";\n}\n\n// Immer auf max. 6 Zeichen mit Leerzeichen auffüllen\nampsStr = ampsStr.padStart(6, \" \");\n\nlet msgAmps = {\n payload: {\n \"size\": 1,\n \"x\": 48,\n \"y\": 57,\n \"text\": ampsStr\n }\n};\n\n// ---------- Change-Check + Senden mit Verzögerung ----------\nfunction sendIfChanged(key, msg, delay) {\n let oldText = flow.get(key) || \"\";\n let newText = msg.payload.text;\n if (newText !== oldText) {\n flow.set(key, newText);\n setTimeout(() => { node.send(msg); }, delay);\n return true; // Änderung erkannt\n }\n return false;\n}\n\n// SOC prüfen → wenn geändert, auch \"%\" mitsenden\nif (sendIfChanged(\"OLED_soc\", msgSoc, 0)) {\n setTimeout(() => { node.send(msgPercent); }, 200);\n}\n\n// Volt & Amps separat prüfen\nsendIfChanged(\"OLED_volt\", msgVolt, 400);\nsendIfChanged(\"OLED_amps\", msgAmps, 600);\n\nreturn null; // nichts direkt zurückgeben\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":570,"y":140,"wires":[["0fd54793a1d06082"]]},{"id":"27e38ace3d0b160d","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Mppt W+Wh","func":"let watts = Number(global.get(\"mppt_pv_watts\") || 0);\nlet yieldVal = Number(global.get(\"VE_dailyyield\") || 0);\n\nlet text = \"\";\n\n// Wenn mppt_pv_watts > 0 → diesen Wert nehmen\nif (watts > 0) {\n text = watts.toString() + \"W\";\n}\n// sonst daily yield prüfen\nelse if (yieldVal > 0) {\n if (yieldVal >= 10000) {\n // Umrechnen in kWh mit einer Nachkommastelle\n let kwh = (yieldVal / 1000).toFixed(1);\n text = kwh + \"kWh\";\n } else {\n text = yieldVal.toString() + \"Wh\";\n }\n}\n\n// Wenn immer noch leer → nichts zurückgeben\nif (text === \"\") {\n return null;\n}\n\n// Immer 6 Zeichen breit machen\ntext = text.padStart(6, \" \");\n\n// Nachricht zusammenbauen\nlet msgOut = {\n payload: {\n \"size\": 1,\n \"x\": 92,\n \"y\": 57,\n \"text\": text\n }\n};\n\n// ---------- Change-Check ----------\nlet oldText = flow.get(\"OLED_pv\") || \"\";\nif (text !== oldText) {\n flow.set(\"OLED_pv\", text);\n return msgOut;\n} else {\n return null; // nichts senden\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":180,"wires":[["0fd54793a1d06082"]]},{"id":"58e75167f702c215","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"linie Oben/Unten","func":"// Erste Nachricht (Linie)\nlet msg1 = {};\nmsg1.payload = {\"x0\":1,\"y0\":15,\"x1\":128,\"y1\":15,\"color\":1};\n\n// Zweite Nachricht (Text)\nlet msg2 = {};\nmsg2.payload = {\"x0\":1,\"y0\":54,\"x1\":128,\"y1\":54,\"color\":1};\n\n// Beide Nachrichten nacheinander senden\nnode.send(msg1);\nnode.send(msg2);\n\nreturn null; // wir haben schon gesendet\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":460,"wires":[["384641e022261bfe"]]},{"id":"384641e022261bfe","type":"Line","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":880,"y":460,"wires":[]},{"id":"75400be909e424e3","type":"delay","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"hour","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":370,"y":460,"wires":[["58e75167f702c215"]]},{"id":"5e0b32ae537494ae","type":"ui_switch","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","label":"OFF / ON (No Saved)","tooltip":"","group":"efeaf4a8803d0564","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":370,"y":560,"wires":[["77f3c6467c853e08"]]},{"id":"77f3c6467c853e08","type":"switch","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","property":"payload","propertyType":"msg","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":600,"y":560,"wires":[["2a552d348156641c"],["968ecacc9fdf1941"]]},{"id":"2a552d348156641c","type":"Turn-on","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":870,"y":540,"wires":[]},{"id":"968ecacc9fdf1941","type":"Turn-off","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":870,"y":580,"wires":[]},{"id":"aba78d8f4e513a90","type":"ui_switch","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","label":"Dimmed","tooltip":"","group":"efeaf4a8803d0564","order":2,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":330,"y":620,"wires":[["d9148966e27f8adf","725b00506e8575bc"]]},{"id":"d9148966e27f8adf","type":"Dimmed","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":870,"y":620,"wires":[]},{"id":"dd493d2f8092996c","type":"ui_button","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","group":"efeaf4a8803d0564","order":7,"width":0,"height":0,"passthru":false,"label":"Oled Clean / Reset","tooltip":"","color":"","bgcolor":"","className":"","icon":"","payload":"true","payloadType":"bool","topic":"topic","topicType":"msg","x":360,"y":500,"wires":[["04a5e76ec61b6ecb","58e75167f702c215","035f3b4d9a3f496b"]]},{"id":"04a5e76ec61b6ecb","type":"Clear","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"oled","display":"a0cfb356680b468b","x":880,"y":500,"wires":[]},{"id":"4656914f348222ac","type":"ui_time_scheduler","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","group":"efeaf4a8803d0564","name":"Dimmed Timer","startDay":0,"refresh":60,"devices":["OLED Dimmed"],"singleOff":false,"onlySendChange":false,"customPayload":false,"eventMode":false,"eventOptions":[],"sendTopic":true,"lat":"","lon":"","customContextStore":"","outputs":2,"order":3,"width":0,"height":0,"x":670,"y":780,"wires":[["3c48020c5409fcf6"],["ca4959d0dd1ef258"]]},{"id":"ca4959d0dd1ef258","type":"rbe","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":680,"y":720,"wires":[["aba78d8f4e513a90"]]},{"id":"3c48020c5409fcf6","type":"file","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Save Timer","filename":"pekaway/userflow/OLEDTimerDimmed","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"true","encoding":"none","x":880,"y":780,"wires":[[]]},{"id":"30bef72104e83965","type":"file in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Read Timer","filename":"pekaway/userflow/OLEDTimerDimmed","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":340,"y":780,"wires":[["4656914f348222ac"]]},{"id":"119bf80f34b3671d","type":"inject","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Boot","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"60","topic":"","payload":"","payloadType":"date","x":160,"y":780,"wires":[["30bef72104e83965","23788304fc7f925f","0f807687ab30f637","9bd23afae3653e6a"]]},{"id":"23788304fc7f925f","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"get global names","func":"const optionsArray = [];\n\n// Add Relay 1–8\noptionsArray.push([global.get(\"None\") || \"Relay 1\", \"one\"]);\noptionsArray.push([global.get(\"Ntwo\") || \"Relay 2\", \"two\"]);\noptionsArray.push([global.get(\"Nthree\") || \"Relay 3\", \"three\"]);\noptionsArray.push([global.get(\"Nfour\") || \"Relay 4\", \"four\"]);\noptionsArray.push([global.get(\"Nfive\") || \"Relay 5\", \"five\"]);\noptionsArray.push([global.get(\"Nsix\") || \"Relay 6\", \"six\"]);\noptionsArray.push([global.get(\"Nseven\") || \"Relay 7\", \"seven\"]);\noptionsArray.push([global.get(\"Neight\") || \"Relay 8\", \"eight\"]);\n\n// Add Relay 9–16 *here*, if enabled\nif (global.get(\"i2c_io-x\") === true) {\n const words = \"zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen\".split(\" \");\n for (let i = 9; i <= 16; i++) {\n const label = global.get(\"N\" + words[i]) || `Relay ${i}`;\n const value = words[i];\n optionsArray.push([label, value]);\n }\n}\n\n// Wifi relays\noptionsArray.push([global.get(\"NWone\") || \"W-Relay 1\", \"wone\"]);\noptionsArray.push([global.get(\"NWtwo\") || \"W-Relay 2\", \"wtwo\"]);\noptionsArray.push([global.get(\"NWthree\") || \"W-Relay 3\", \"wthree\"]);\noptionsArray.push([global.get(\"NWfour\") || \"W-Relay 4\", \"wfour\"]);\noptionsArray.push([global.get(\"NWfive\") || \"W-Relay 5\", \"wfive\"]);\noptionsArray.push([global.get(\"NWsix\") || \"W-Relay 6\", \"wsix\"]);\noptionsArray.push([global.get(\"NWseven\") || \"W-Relay 7\", \"wseven\"]);\noptionsArray.push([global.get(\"NWeight\") || \"W-Relay 8\", \"weight\"]);\n\n// Dimmers\n//optionsArray.push([global.get(\"Ndimmer0\") || \"Dimmer 1\", \"done\"]);\n//optionsArray.push([global.get(\"Ndimmer1\") || \"Dimmer 2\", \"dtwo\"]);\n//optionsArray.push([global.get(\"Ndimmer2\") || \"Dimmer 3\", \"dthree\"]);\n//optionsArray.push([global.get(\"Ndimmer3\") || \"Dimmer 4\", \"dfour\"]);\n//optionsArray.push([global.get(\"Ndimmer4\") || \"Dimmer 5\", \"dfive\"]);\n//optionsArray.push([global.get(\"Ndimmer5\") || \"Dimmer 6\", \"dsix\"]);\n//optionsArray.push([global.get(\"Ndimmer6\") || \"Dimmer 7\", \"dseven\"]);\n// optionsArray.push([global.get(\"Ndimmer7\") || \"Dimmer 8\", \"deight\"]); // optional\n\n// Add DimmyPro 1-8 (8-15) *here*, if enabled\n//if (global.get(\"i2c_dimmyPro\") === true) {\n// const words = \"zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen\".split(\" \");\n// for (let i = 8; i <= 15; i++) {\n// const label = global.get(\"Ndimmer\" + i) || `DimmyPro ${(i-7)}`;\n// const value = \"d\"+words[i];\n// optionsArray.push([label, value]);\n// }\n//}\n\n// Convert array back to an ordered object\nlet optionsMap = {};\nfor (const [label, value] of optionsArray) {\n optionsMap[label] = value;\n}\n\nmsg.options = [optionsMap];\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":860,"wires":[["8738bac3e75e74f7","e3fcdc711414bf44","84b304739f8377d3"]]},{"id":"8738bac3e75e74f7","type":"ui_dropdown","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","label":"AC 230V","tooltip":"select the switch for your AC 230V Relay","place":"Select Relay","group":"efeaf4a8803d0564","order":4,"width":0,"height":0,"passthru":true,"multiple":false,"options":[],"payload":"","topic":"topic","topicType":"msg","className":"","x":710,"y":900,"wires":[["180a2488c88b19fd"]]},{"id":"e3fcdc711414bf44","type":"ui_dropdown","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","label":"Waterpump","tooltip":"select the switch for your Waterpump Relay","place":"Select Relay","group":"efeaf4a8803d0564","order":6,"width":0,"height":0,"passthru":true,"multiple":false,"options":[],"payload":"","topic":"topic","topicType":"msg","className":"","x":720,"y":940,"wires":[["27077b1a78c1061a"]]},{"id":"84b304739f8377d3","type":"ui_dropdown","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","label":"Relay","tooltip":"select the switch for your Relay","place":"Select Relay","group":"efeaf4a8803d0564","order":5,"width":0,"height":0,"passthru":true,"multiple":false,"options":[],"payload":"","topic":"topic","topicType":"msg","className":"","x":700,"y":980,"wires":[["578b0e0471f41628"]]},{"id":"180a2488c88b19fd","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"set flow","func":"flow.set(\"OLED_AC230aktiv\", msg.payload);\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":900,"wires":[["b7b51369f75008e0"]]},{"id":"27077b1a78c1061a","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"set flow","func":"flow.set(\"OLED_Waterpumpaktiv\", msg.payload);\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":887.60009765625,"y":940.6000061035156,"wires":[["2bf82591c1dcb2d4"]]},{"id":"578b0e0471f41628","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"set flow","func":"flow.set(\"OLED_relayaktiv\", msg.payload);\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":980,"wires":[["77fd30a19fe6afef"]]},{"id":"b7b51369f75008e0","type":"file","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Save AC230","filename":"pekaway/userflow/OLEDac230aktiv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1040,"y":900,"wires":[[]]},{"id":"2bf82591c1dcb2d4","type":"file","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Save Water","filename":"pekaway/userflow/OLEDwateraktiv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1060,"y":940,"wires":[[]]},{"id":"77fd30a19fe6afef","type":"file","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Save Relay","filename":"pekaway/userflow/OLEDrelayaktiv","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":1020,"y":980,"wires":[[]]},{"id":"a094f8dd00c5c0c9","type":"file in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Read AC230","filename":"pekaway/userflow/OLEDac230aktiv","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":540,"y":900,"wires":[["8738bac3e75e74f7"]]},{"id":"f93abb541b904e70","type":"file in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Read Water","filename":"pekaway/userflow/OLEDwateraktiv","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":540,"y":940,"wires":[["e3fcdc711414bf44"]]},{"id":"17bcb3a2849ef30a","type":"file in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Read Relay","filename":"pekaway/userflow/OLEDrelayaktiv","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":540,"y":980,"wires":[["84b304739f8377d3"]]},{"id":"0f807687ab30f637","type":"delay","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":350,"y":980,"wires":[["a094f8dd00c5c0c9","f93abb541b904e70","17bcb3a2849ef30a"]]},{"id":"8ebefe65efb42144","type":"catch","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","scope":["a094f8dd00c5c0c9","f93abb541b904e70","17bcb3a2849ef30a","30bef72104e83965"],"uncaught":false,"x":380,"y":940,"wires":[[]]},{"id":"9c720236f8d564aa","type":"mqtt in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","topic":"pkw/cmnd/#","qos":"2","datatype":"auto-detect","broker":"0ddb07c65cbb68bc","nl":false,"rap":true,"rh":0,"inputs":0,"x":340,"y":340,"wires":[["ce3b6114fb191494"]]},{"id":"dd02317ddcf854ea","type":"Image","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","display":"a0cfb356680b468b","x":940,"y":320,"wires":[]},{"id":"702137a054172cfd","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Symbol AC","func":"// Payload normalisieren (String zu Kleinbuchstaben, Boolean direkt übernehmen)\nlet val = (typeof msg.payload === \"string\") ? msg.payload.toLowerCase() : msg.payload;\n\nlet imagePath;\nif (val === true || val === \"on\") {\n imagePath = \"pekaway/oled/ac.png\";\n} else if (val === false || val === \"off\") {\n imagePath = \"pekaway/oled/12x12clean.png\";\n} else {\n // Unbekannter Wert → Nachricht verwerfen\n return null;\n}\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_acImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_acImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 54,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":770,"y":340,"wires":[["dd02317ddcf854ea"]]},{"id":"3b092c099decfa67","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Symbol Water","func":"// Payload normalisieren (String zu Kleinbuchstaben, Boolean direkt übernehmen)\nlet val = (typeof msg.payload === \"string\") ? msg.payload.toLowerCase() : msg.payload;\n\nlet imagePath;\nif (val === true || val === \"on\") {\n imagePath = \"pekaway/oled/water.png\";\n} else if (val === false || val === \"off\") {\n imagePath = \"pekaway/oled/12x12clean.png\";\n} else {\n // Unbekannter Wert → Nachricht verwerfen\n return null;\n}\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_waterImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_waterImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 42,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":380,"wires":[["dd02317ddcf854ea"]]},{"id":"7564774aaec48d37","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Symbol Relay","func":"// Payload normalisieren (String zu Kleinbuchstaben, Boolean direkt übernehmen)\nlet val = (typeof msg.payload === \"string\") ? msg.payload.toLowerCase() : msg.payload;\n\nlet imagePath;\nif (val === true || val === \"on\") {\n imagePath = \"pekaway/oled/relay.png\";\n} else if (val === false || val === \"off\") {\n imagePath = \"pekaway/oled/12x12clean.png\";\n} else {\n // Unbekannter Wert → Nachricht verwerfen\n return null;\n}\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_relayImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_relayImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 66,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":420,"wires":[["dd02317ddcf854ea"]]},{"id":"353f232efadf6a62","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"global boilercontrol","func":"//skript by Wulle on Tour\n// Flow-Variable lesen\nlet isBoilerOn = global.get(\"boilertemp_control\");\n\n// Bildpfad wählen\nlet imagePath = isBoilerOn === true\n ? \"pekaway/oled/boileron.png\"\n : \"pekaway/oled/12x12clean.png\";\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_boilerImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_boilerImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 29,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":300,"wires":[["dd02317ddcf854ea"]]},{"id":"788a8cd061e253c1","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"global heater","func":"// Liste der zu prüfenden Flow-Variablen\nconst vars = [\n \"HeaterToggle_autoterm1\",\n \"HeaterToggle_autoterm2\",\n \"HeaterToggle\",\n \"HeaterToggle_truma\"\n];\n\n// Prüfen, ob mindestens eine auf true steht\nlet heaterOn = vars.some(v => global.get(v) === true);\n\n// Bildpfad wählen\nlet imagePath = heaterOn\n ? \"pekaway/oled/12x13heater.png\"\n : \"pekaway/oled/12x13clean.png\";\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_heaterImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_heaterImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 15,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":260,"wires":[["dd02317ddcf854ea"]]},{"id":"fdc1acd1bde4df19","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"global timer","func":"// Liste der zu prüfenden Flow-Variablen\nconst vars = [\n \"truma_watertimeronoff\",\n \"truma_heattimeronoff\",\n \"heattimeronoff_autoterm1\",\n \"heattimeronoff_autoterm2\",\n \"heattimeronoff\",\n \"boiler_timeronoff\"\n];\n\n// Prüfen, ob mindestens eine auf true steht\nlet heaterOn = vars.some(v => global.get(v) === true);\n\n// Bildpfad wählen\nlet imagePath = heaterOn \n ? \"pekaway/oled/timer.png\"\n : \"pekaway/oled/12x12clean.png\";\n\n// Change-Check mit Flow-Variable\nlet oldImage = flow.get(\"OLED_timerImg\") || \"\";\nif (imagePath !== oldImage) {\n flow.set(\"OLED_timerImg\", imagePath);\n\n msg.payload = {\n \"image\": imagePath,\n \"x\": 1,\n \"y\": 1,\n \"clear\": false,\n \"animated\": false\n };\n\n return msg;\n}\n\nreturn null; // nichts senden, wenn keine Änderung\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":580,"y":220,"wires":[["dd02317ddcf854ea"]]},{"id":"9d56e455c0c53d52","type":"ui_ui_control","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"","events":"change","x":170,"y":820,"wires":[["0fbeb914d7946fe4"]]},{"id":"0fbeb914d7946fe4","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"check tab","func":"if (msg.payload == \"change\" && msg.name == \"Devices\") {\n return msg;\n}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":330,"y":820,"wires":[["23788304fc7f925f","0f807687ab30f637"]]},{"id":"de5aa5e567627831","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"i2c check","func":"//skript by Wulle on Tour\n// globale Variable holen\nlet i2c = global.get(\"i2c_detect\");\n\n// prüfen ob vorhanden und ob 0x3c drin ist\nif (i2c && i2c.includes(\"0x3c\")) {\n return msg; // Nachricht weiterleiten\n} else {\n return null; // Nachricht blockieren\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":200,"wires":[["75400be909e424e3","63cf51b0acf73742","7bf38810c9fd4611","27e38ace3d0b160d","fdc1acd1bde4df19","788a8cd061e253c1","353f232efadf6a62","0d9f82780b606ac5","214051e4617af0c0","e209e75b36b3c481"]]},{"id":"ce3b6114fb191494","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"i2c check","func":"// globale Variable holen\nlet i2c = global.get(\"i2c_detect\");\n\n// prüfen ob vorhanden und ob 0x3c drin ist\nif (i2c && i2c.includes(\"0x3c\")) {\n return msg; // Nachricht weiterleiten\n} else {\n return null; // Nachricht blockieren\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":400,"wires":[["0d9f82780b606ac5","214051e4617af0c0","e209e75b36b3c481"]]},{"id":"725b00506e8575bc","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Switch Check filter","func":"if (msg.payload !== undefined && msg.payload !== null && msg.socketid) {\n return msg; // Nachricht weitergeben\n} else {\n return null; // Nachricht verwerfen\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":680,"y":660,"wires":[["78d140fda3d9a27f"]]},{"id":"7ff2294cbe958a81","type":"change","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"boolean","rules":[{"t":"change","p":"payload","pt":"msg","from":"true","fromt":"str","to":"true","tot":"bool"},{"t":"change","p":"payload","pt":"msg","from":"false","fromt":"str","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":720,"wires":[["aba78d8f4e513a90"]]},{"id":"78d140fda3d9a27f","type":"file","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Save Dimmed","filename":"pekaway/userflow/OLEDDimmed","filenameType":"str","appendNewline":false,"createDir":true,"overwriteFile":"true","encoding":"none","x":890,"y":660,"wires":[[]]},{"id":"9bd23afae3653e6a","type":"file in","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Read Dimmed","filename":"pekaway/userflow/OLEDDimmed","filenameType":"str","format":"utf8","chunk":false,"sendError":false,"encoding":"none","allProps":false,"x":350,"y":720,"wires":[["7ff2294cbe958a81"]]},{"id":"9950d9c32faef743","type":"comment","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"file: pekaway/oled/","info":"","x":980,"y":280,"wires":[]},{"id":"92dedcf7cbe60ed7","type":"comment","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"node-red-contrib-oled-i2c","info":"","x":990,"y":240,"wires":[]},{"id":"0d9f82780b606ac5","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"AC230 filter","func":"// Name der Flow-Variable auslesen\nlet varName = flow.get(\"OLED_AC230aktiv\");\n\nif (varName === undefined) {\n node.warn(\"AC230aktiv ist nicht gesetzt!\");\n msg.payload = false;\n} else {\n // Wert der globalen Variable auslesen\n let value = global.get(varName);\n if (value === undefined) {\n node.warn(`Globale Variable '${varName}' ist nicht gesetzt!`);\n msg.payload = false;\n } else {\n msg.payload = value; // true oder false\n }\n}\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":340,"wires":[["702137a054172cfd"]]},{"id":"214051e4617af0c0","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Water filter","func":"// Name der Flow-Variable auslesen\nlet varName = flow.get(\"OLED_Waterpumpaktiv\");\n\nif (varName === undefined) {\n node.warn(\"Waterpumpaktiv ist nicht gesetzt!\");\n msg.payload = false;\n} else {\n // Wert der globalen Variable auslesen\n let value = global.get(varName);\n if (value === undefined) {\n node.warn(`Globale Variable '${varName}' ist nicht gesetzt!`);\n msg.payload = false;\n } else {\n msg.payload = value; // true oder false\n }\n}\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":380,"wires":[["3b092c099decfa67"]]},{"id":"e209e75b36b3c481","type":"function","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Relay filter","func":"// Name der Flow-Variable auslesen\nlet varName = flow.get(\"OLED_relayaktiv\");\n\nif (varName === undefined) {\n node.warn(\"relayaktiv ist nicht gesetzt!\");\n msg.payload = false;\n} else {\n // Wert der globalen Variable auslesen\n let value = global.get(varName);\n if (value === undefined) {\n node.warn(`Globale Variable '${varName}' ist nicht gesetzt!`);\n msg.payload = false;\n } else {\n msg.payload = value; // true oder false\n }\n}\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":590,"y":420,"wires":[["7564774aaec48d37"]]},{"id":"035f3b4d9a3f496b","type":"change","z":"551eaab0c2c1a9cf","g":"2a1cc0e0b7e76aea","name":"Clean FLOW","rules":[{"t":"set","p":"OLED_ambientTemp","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_amps","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_pv","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_soc","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_volt","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_timerImg","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_heaterImg","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_boilerImg","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_acImg","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_waterImg","pt":"flow","to":"\"\"","tot":"str"},{"t":"set","p":"OLED_relayImg","pt":"flow","to":"\"\"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":520,"wires":[[]]},{"id":"a0cfb356680b468b","type":"oled-config","name":"oled","width":"128","height":"64","address":"0x3c","driver":"SH1106","i2cBus":"1"},{"id":"efeaf4a8803d0564","type":"ui_group","name":"OLED I2C 1,3 Zoll","tab":"3b6d81e4a75b05e9","order":4,"disp":true,"width":6,"collapse":true,"className":""},{"id":"0ddb07c65cbb68bc","type":"mqtt-broker","name":"","broker":"http://localhost","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"3b6d81e4a75b05e9","type":"ui_tab","name":"Devices","icon":"","order":30,"disabled":false,"hidden":true}]
Das sollte es gewesen sein.
Bei richtig Anschließen des Display, sollte es beim I2C Scan die Adresse “0x3c” anzeigen.
Driver: SH1106 (falls dieser nicht mit kommt)
Gruß Wulle










