Zusatzdisplay OLED 1,3 Zoll über I2C

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 :sweat_smile: )

12x12clean.png 12x12clean

12x13clean.png 12x13clean

12x13heater.png 12x13heater

ac.png ac

boileron.png boileron

relay.png relay

timer.png timer

water.png water

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

12 Likes

Ich hatte auch noch so ein Display rumligen,

und hab das Programm auf mich angepasst :wink:

Die Mittlere Anzeige wechselt jetzt alle 10 sec. von SOC auf Wasser und Grauwasser.

Mann kann sicher noch eine oder 2 weitere Instanzen einsetzen, dazu muss man nur die Zeiten der Injekt node und der Delays anpassen.

Ich musste nur die Anzeige auf 99 begrenzen, um keine 3 Stellige Zahl anzuzeigen

[{"id":"7a648c2810093311","type":"function","z":"a6e506448db83d88","g":"205459a7c00e4bcf","name":"MainBatt original","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":1190,"y":100,"wires":[[]]}]

Ich brauch nur noch einen der mir ein Gehäuse druckt

Gruß Arno

1 Like

Mach ich dir gerne :wink:

Ja Super

was brauchst du dafür???

Display hab ich. Eigentlich nur deine Entscheidung, ob Ein- oder Aufbaugehäuse. :wink:

Ab Montag kann ich anfangen, da bin ich aus dem Urlaub zurück.

Schönen Rest Urlaub

Aufbaugehäuse bräuchte ich.

Kannst du wenigstens die wechselnde Anzeige brauchen??

Gruß Arno

Ja Cool umgebaut. Ich wollte mir die Füllstände noch als Balken anzeigen lassen. Heißt vor und nach der SOC anzeige. Hab ja das Awatrix Display und dort nervt es etwas, wenn man immer warten muss bis alles durch ist. Wasser hab ich so gelöst, das beim schalten der Pumpe, der Wasserstand angezeigt wird.

Gruß Wulle

Mit dem Balken Diagramm ist auch cool aber ich habe keine Wasserpumpe die übers Relayboard gesteuert wird.

Aber da kann man zur Not ja ein Dauer true setzen. :wink:

Was hast du da gedacht, Balken von unten nach oben, oder links nach rechts??

Wollte alle 4 einfach einbinden von Unten nach Oben. Zwei streifen links von der Zahl und 2 Rechts von der Zahl. So in 5 Kästen quasi, also 20 % schritte. Muss man sich mal angucken bei der auflösung

Die Balken würde ich immer anzeigen lassen.
Mit dem Anzeigen des Wassers war auf dem Awartix Display. Die Batterie und co wechseln alle 10 Sekunden, aber Wasser wird sofort angezeigt beim drücken.

1 Like

Hi Arno,
Du hast das 1,3”-OLED Display, oder?
Leider haben die verschiedenen Hersteller wohl leicht unterschiedliche Abmessungen.

Deshalb wären die Platinenabmessungen und die der Bohrungen sicher hilfreich :wink:

Hallo

Hier die Abmessungen

35,67x33,52

Lochabstand 30,5 und 28,7

Durchmesser 3,12

Display 34,54x22,95

Passt. Hier der Entwurf

Muster habe ich auch schon gedruckt.

das ist nur ein schnell gedrucktes Muster, um die Passgenauigkeit zu testen. Der ordentliche Druck kommt, wenn das Gehäuse so ok ist für dich. Wenn Du ein anderes Design willst sag es :wink:

Der Entwurf sieht ja schon mal gut aus. Ich habe allerdings auf der Rückseite angellötete pinne, die habe ich schon mal umgebogen, ist aberimmer noch. 3,7mm hoch.

Das bedeutet das die Auflage an den Löchern 3,7 mm hoch sein muss, oder ich muss die pinne auslötten.

  1. Schlitz durch’s Möbel für den Kabelstecker
  2. unteres Gehäuseteil mit Spiegeltape, Silikon oder ähnlichen anpappen
  3. OLED ins untere Teil klemmen und oberes Teil draufschieben
  4. Kabel geht nach hinten raus

die 4poligen Pins bleiben eigentlich gerade :wink:

Ich hab das untere Teil jetzt einfach 2,5mm tiefer gemacht. Das gesamte Gehäuse ist dann knapp 10mm (9,7 :wink:) hoch.