Aquarium Controller, Pardon the Topic Title, but I wanted this Project to be found.
This project has had many false starts as a baremetal project on ArduinoDue and later a UWP on RPI3B w/ Win10IoT.
I was particularly impressed by the Atlas IoT Monitoring Software from Atlas-Scientific that runs on a Raspberry PI 3B and Windows10IoT for connecting to their i2c enabled sensors, devices and circuits. Atlas-Scientific Atlas IoT Monitoring Software Link.
This next effort was to create an alternative to the Atlas IoT Software that would satisfy 4 principal objects:
1 Use the Raspberry PI 4B w/ it's extra memory and i2c ports. (throw hardware at the problem)
2 Adopt a well supported development environment under Raspbian (Win10IoT has been abandoned)
3 Include control functionality (Atlas IoT was monitoring only, which is appropriate for their products)
4 Local and Remote display/monitoring.
Node-RED on Raspbian Buster on RaspberryPI4 so far has fit the bill.
My project is in it's infancy, but I'll share what is working now:
flows.json (14.6 KB)
[{"id":"59165d4d.066034","type":"tab","label":"Sensors","disabled":false,"info":""},{"id":"e00b8f43.9ccf9","type":"i2c in","z":"59165d4d.066034","name":"RTDData","address":"102","command":"","count":"8","x":120,"y":180,"wires":[["6588eab1.c5bdb4"]]},{"id":"791936ff.768018","type":"i2c out","z":"59165d4d.066034","name":"RTDCmnd","address":"102","command":"82","payload":"payload","payloadType":"msg","count":"1","x":110,"y":100,"wires":[["33df9f56.5deff"]]},{"id":"418f9978.531ca8","type":"debug","z":"59165d4d.066034","name":"RawBuff","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":520,"y":740,"wires":[]},{"id":"a9306c4d.c7cb9","type":"inject","z":"59165d4d.066034","name":"push1","topic":"","payload":"","payloadType":"num","repeat":"10","crontab":"","once":true,"onceDelay":0.1,"x":120,"y":20,"wires":[["791936ff.768018","863f23ed.6ce2b","4c96ce0f.154ec","9214c7e3.12f458"]]},{"id":"33df9f56.5deff","type":"delay","z":"59165d4d.066034","name":"delay1","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":110,"y":140,"wires":[["e00b8f43.9ccf9"]]},{"id":"54aae87c.830b48","type":"i2c scan","z":"59165d4d.066034","name":"","x":320,"y":780,"wires":[["7dd33aaa.12b2a4"],[]]},{"id":"42f6e013.13b69","type":"inject","z":"59165d4d.066034","name":"push2","topic":"","payload":"Clear","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":740,"wires":[["b1978dba.68466"]]},{"id":"7dd33aaa.12b2a4","type":"debug","z":"59165d4d.066034","name":"i2c channel devices","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":550,"y":780,"wires":[]},{"id":"6588eab1.c5bdb4","type":"function","z":"59165d4d.066034","name":"BuffToStr1","func":"msg.payload = (String.fromCharCode(msg.payload[1])) + (String.fromCharCode(msg.payload[2]))\n + (String.fromCharCode(msg.payload[3])) + (String.fromCharCode(msg.payload[4]))\n + (String.fromCharCode(msg.payload[5])) + (String.fromCharCode(msg.payload[6]));\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":100,"wires":[["323c7e18.bdd8e2"]]},{"id":"323c7e18.bdd8e2","type":"change","z":"59165d4d.066034","name":"StrToNum1","rules":[{"t":"set","p":"payload.value","pt":"msg","to":"","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":160,"wires":[["5b912629.f72478","1ab56f48.ad8f91"]]},{"id":"5b912629.f72478","type":"ui_gauge","z":"59165d4d.066034","name":"TankTemp","group":"ffc1aa9d.ac4028","order":1,"width":5,"height":4,"gtype":"donut","title":"Tank Temp","label":"degC","format":"{{value}}","min":0,"max":"40","colors":["#ff8040","#ff8000","#ff0000"],"seg1":"10","seg2":"30","x":650,"y":120,"wires":[]},{"id":"863f23ed.6ce2b","type":"i2c out","z":"59165d4d.066034","name":"pHCmnd","address":"100","command":"082","payload":"payload","payloadType":"msg","count":"1","x":120,"y":240,"wires":[["d76c2c51.1df71"]]},{"id":"d76c2c51.1df71","type":"delay","z":"59165d4d.066034","name":"delay2","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":110,"y":280,"wires":[["4e84ff27.a688"]]},{"id":"4e84ff27.a688","type":"i2c in","z":"59165d4d.066034","name":"pHData","address":"100","command":"","count":"8","x":120,"y":320,"wires":[["5e0af3d3.7bd6bc"]]},{"id":"5e0af3d3.7bd6bc","type":"function","z":"59165d4d.066034","name":"BuffToStr2","func":"msg.payload = (String.fromCharCode(msg.payload[1])) + (String.fromCharCode(msg.payload[2]))\n + (String.fromCharCode(msg.payload[3])) + (String.fromCharCode(msg.payload[4]))\n + (String.fromCharCode(msg.payload[5])) + (String.fromCharCode(msg.payload[6]));\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":240,"wires":[["ac1f6728.22f578"]]},{"id":"ac1f6728.22f578","type":"change","z":"59165d4d.066034","name":"StrToNum2","rules":[{"t":"set","p":"payload.Value","pt":"msg","to":"","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":300,"wires":[["6436f959.83a148","adbe2f0c.98d94"]]},{"id":"6436f959.83a148","type":"ui_level","z":"59165d4d.066034","group":"ad7aabd5.7bf318","order":1,"width":5,"height":4,"name":"TankpH","label":"pH","colorHi":"#8000ff","colorWarn":"#00ff00","colorNormal":"#00ff00","colorOff":"#595959","min":"4.0","max":"10.0","segWarn":"6.0","segHigh":"8.0","unit":"","layout":"sv","channelA":"","channelB":"","decimals":"2","animations":"soft","shape":"3","colorschema":"rainbow","textoptions":"custom","colorText":"#eeeeee","fontLabel":"1.5","fontValue":"1.5","fontSmall":".75","colorFromTheme":true,"textAnimations":true,"hideValue":false,"tickmode":"segments","peakmode":false,"peaktime":3000,"x":640,"y":260,"wires":[]},{"id":"4c96ce0f.154ec","type":"i2c out","z":"59165d4d.066034","d":true,"name":"FlowCmnd","address":"104","command":"82","payload":"payload","payloadType":"msg","count":"1","x":110,"y":520,"wires":[["fb7d7fe3.15b03"]]},{"id":"fb7d7fe3.15b03","type":"delay","z":"59165d4d.066034","name":"delay4","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":110,"y":560,"wires":[["89af4958.9414b8"]]},{"id":"89af4958.9414b8","type":"i2c in","z":"59165d4d.066034","d":true,"name":"FlowData","address":"104","command":"","count":"8","x":120,"y":620,"wires":[["5e8a1754.f437d8","a4f6724b.00d57"]]},{"id":"5e8a1754.f437d8","type":"function","z":"59165d4d.066034","name":"BuffToStr4a","func":"msg.payload = (String.fromCharCode(msg.payload[1])) + (String.fromCharCode(msg.payload[2]))\n + (String.fromCharCode(msg.payload[3])) + (String.fromCharCode(msg.payload[4]))\n + (String.fromCharCode(msg.payload[5])) + (String.fromCharCode(msg.payload[6]));\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":520,"wires":[["6e7c1c2d.edae24"]]},{"id":"6e7c1c2d.edae24","type":"change","z":"59165d4d.066034","name":"StrToNum4a","rules":[{"t":"set","p":"payload.Value","pt":"msg","to":"","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":580,"wires":[["117ae2b.0951e1d","8b9f9a88.59a058"]]},{"id":"117ae2b.0951e1d","type":"ui_text","z":"59165d4d.066034","group":"b03ec9c2.970168","order":3,"width":0,"height":0,"name":"l/min","label":"l/min","format":"{{msg.payload}}","layout":"row-spread","x":630,"y":580,"wires":[]},{"id":"b1978dba.68466","type":"i2c out","z":"59165d4d.066034","name":"TotClear","address":"104","command":"","payload":"payload","payloadType":"bin","count":"8","x":320,"y":740,"wires":[["418f9978.531ca8"]]},{"id":"33f61e3b.8cb402","type":"inject","z":"59165d4d.066034","name":"push3","topic":"","payload":"","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":780,"wires":[["54aae87c.830b48"]]},{"id":"8b9f9a88.59a058","type":"ui_gauge","z":"59165d4d.066034","name":"PumpFlow","group":"b03ec9c2.970168","order":1,"width":5,"height":4,"gtype":"wave","title":"Pump Flow","label":"l/min","format":"{{value}}","min":0,"max":"30","colors":["#d7ffff","#80ffff","#00ffff"],"seg1":"10","seg2":"20","x":650,"y":520,"wires":[]},{"id":"fcfd20fc.fe16a","type":"i2c in","z":"59165d4d.066034","name":"ORPData","address":"98","command":"","count":"8","x":120,"y":460,"wires":[["8fbadc49.54a87"]]},{"id":"9214c7e3.12f458","type":"i2c out","z":"59165d4d.066034","name":"ORPCmnd","address":"98","command":"82","payload":"payload","payloadType":"msg","count":"1","x":110,"y":380,"wires":[["49ba564f.5d51a8"]]},{"id":"49ba564f.5d51a8","type":"delay","z":"59165d4d.066034","name":"delay3","pauseType":"delay","timeout":"1","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":110,"y":420,"wires":[["fcfd20fc.fe16a"]]},{"id":"e272ee73.d5b14","type":"ui_text","z":"59165d4d.066034","group":"b2db3abe.0a63d8","order":3,"width":0,"height":0,"name":"mV","label":"mV","format":"{{msg.payload}}","layout":"row-spread","x":630,"y":440,"wires":[]},{"id":"8fbadc49.54a87","type":"function","z":"59165d4d.066034","name":"BuffToStr3","func":"msg.payload = (String.fromCharCode(msg.payload[1])) + (String.fromCharCode(msg.payload[2]))\n + (String.fromCharCode(msg.payload[3])) + (String.fromCharCode(msg.payload[4]))\n + (String.fromCharCode(msg.payload[5])) + (String.fromCharCode(msg.payload[6]));\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":380,"wires":[["98d203ea.9b3c2"]]},{"id":"98d203ea.9b3c2","type":"change","z":"59165d4d.066034","name":"StrToNum3","rules":[{"t":"set","p":"payload.value","pt":"msg","to":"","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":440,"wires":[["e272ee73.d5b14","7f98aed2.615d1"]]},{"id":"7f98aed2.615d1","type":"ui_gauge","z":"59165d4d.066034","name":"TankORP","group":"b2db3abe.0a63d8","order":1,"width":5,"height":4,"gtype":"gage","title":"Tank ORP","label":"mV","format":"{{value}}","min":0,"max":"500","colors":["#00ff00","#ffff00","#ff0000"],"seg1":"275","seg2":"350","x":640,"y":380,"wires":[]},{"id":"a4f6724b.00d57","type":"function","z":"59165d4d.066034","name":"BuffToStr4b","func":"msg.payload = (String.fromCharCode(msg.payload[1])) + (String.fromCharCode(msg.payload[2]))\n + (String.fromCharCode(msg.payload[3])) + (String.fromCharCode(msg.payload[4]))\n + (String.fromCharCode(msg.payload[5])) + (String.fromCharCode(msg.payload[6]));\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":640,"wires":[["7eb33ea4.484bc"]]},{"id":"7eb33ea4.484bc","type":"change","z":"59165d4d.066034","name":"StrToNum4b","rules":[{"t":"set","p":"payload.Value","pt":"msg","to":"","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":700,"wires":[["6baa2964.726738"]]},{"id":"6baa2964.726738","type":"ui_text","z":"59165d4d.066034","group":"b03ec9c2.970168","order":4,"width":0,"height":0,"name":"litres","label":"Total litres","format":"{{msg.payload}}","layout":"row-spread","x":630,"y":700,"wires":[]},{"id":"767048b8.04b1e8","type":"ui_slider","z":"59165d4d.066034","name":"TempSetpoint","label":"sp","tooltip":"Desired Temperature","group":"ffc1aa9d.ac4028","order":2,"width":5,"height":1,"passthru":false,"outs":"end","topic":"","min":"25","max":"32","step":1,"x":660,"y":180,"wires":[[]]},{"id":"832b804.3822b8","type":"ui_slider","z":"59165d4d.066034","name":"pHSetpoint","label":"sp","tooltip":"Desired pH","group":"ad7aabd5.7bf318","order":2,"width":5,"height":1,"passthru":false,"outs":"end","topic":"","min":"5.5","max":"9.5","step":".1","x":650,"y":320,"wires":[[]]},{"id":"1ab56f48.ad8f91","type":"ramp-thermostat","z":"59165d4d.066034","name":"TempCtrl","profile":"f15ee116.77d49","hysteresisplus":".25","hysteresisminus":".25","x":500,"y":160,"wires":[["a7be1c66.ddc8f"],[],["767048b8.04b1e8"]]},{"id":"d4c352ba.e030e","type":"ui_led","z":"59165d4d.066034","group":"ffc1aa9d.ac4028","order":3,"width":5,"height":2,"label":"Heater","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"red","value":"0","valueType":"num"},{"color":"green","value":"1","valueType":"num"}],"allowColorForValueInMessage":false,"name":"Heater","x":1230,"y":100,"wires":[]},{"id":"adbe2f0c.98d94","type":"ramp-thermostat","z":"59165d4d.066034","name":"pHCtrl","profile":"965190ba.83e9b","hysteresisplus":".1","hysteresisminus":".1","x":490,"y":300,"wires":[["a0455e.c7afeaa"],[],["832b804.3822b8"]]},{"id":"8fd0d458.8ba688","type":"ui_led","z":"59165d4d.066034","group":"ad7aabd5.7bf318","order":3,"width":5,"height":2,"label":"CO2","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"red","value":"0","valueType":"num"},{"color":"green","value":"1","valueType":"num"}],"allowColorForValueInMessage":false,"name":"CO2","x":1230,"y":140,"wires":[]},{"id":"35e019aa.b80d66","type":"ncd-mcp23008","z":"59165d4d.066034","name":"NCD-GPRelayCtrlr","connection":"aa1e3ead.646b2","addr":"32","interval":"100","onchange":true,"send_init":false,"outputs":9,"output_all":true,"interrupt":0,"io_1":1,"io_2":1,"io_3":1,"io_4":1,"io_5":1,"io_6":1,"io_7":1,"io_8":1,"persist":"","startup":"","x":1050,"y":200,"wires":[["d4c352ba.e030e"],["8fd0d458.8ba688"],[],[],[],[],[],[],[]]},{"id":"a7be1c66.ddc8f","type":"change","z":"59165d4d.066034","name":"RelayCh1Set","rules":[{"t":"set","p":"topic","pt":"msg","to":"channel_1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":140,"wires":[["35e019aa.b80d66"]]},{"id":"cd643120.10061","type":"change","z":"59165d4d.066034","name":"RelayCh2Set","rules":[{"t":"set","p":"topic","pt":"msg","to":"channel_2","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":830,"y":280,"wires":[["35e019aa.b80d66"]]},{"id":"a0455e.c7afeaa","type":"function","z":"59165d4d.066034","name":"ChgDirectAct","func":"if (msg.payload === false)\n{msg.payload=true}\nelse \n{msg.payload=false}\nreturn msg;","outputs":1,"noerr":0,"x":830,"y":240,"wires":[["cd643120.10061"]]},{"id":"4a410a71.d5f3f4","type":"comment","z":"59165d4d.066034","name":"Flow Temporarily Disabled","info":"Flow is temporarily disabled as there are not provisions in the current test tank.\nFurthermore, the Atlas-Sci non-iso carrier board needs to be re-worked (bad solder)","x":830,"y":580,"wires":[]},{"id":"ffc1aa9d.ac4028","type":"ui_group","z":"","name":"EZO RTD over i2c","tab":"ba830589.55bb38","order":1,"disp":false,"width":"5","collapse":false},{"id":"ad7aabd5.7bf318","type":"ui_group","z":"","name":"EZO pH over I2C","tab":"ba830589.55bb38","order":2,"disp":false,"width":"5","collapse":false},{"id":"b03ec9c2.970168","type":"ui_group","z":"","name":"EZO Flo over I2C","tab":"ba830589.55bb38","order":4,"disp":false,"width":"5","collapse":false},{"id":"b2db3abe.0a63d8","type":"ui_group","z":"","name":"EZO ORP over I2C","tab":"ba830589.55bb38","order":3,"disp":false,"width":"5","collapse":false},{"id":"f15ee116.77d49","type":"profile","z":"","name":"SchedTemp","time1":"00:00","temp1":"27","time2":"23:59","temp2":"27","time3":"","temp3":"","time4":"","temp4":"","time5":"","temp5":"","time6":"","temp6":"","time7":"","temp7":"","time8":"","temp8":"","time9":"","temp9":"","time10":"","temp10":""},{"id":"965190ba.83e9b","type":"profile","z":"","name":"SchedpH","time1":"00:00","temp1":"7.0","time2":"23:59","temp2":"7.0","time3":"","temp3":"","time4":"","temp4":"","time5":"","temp5":"","time6":"","temp6":"","time7":"","temp7":"","time8":"","temp8":"","time9":"","temp9":"","time10":"","temp10":""},{"id":"aa1e3ead.646b2","type":"ncd-comm","z":"","name":"Pi-i2c-1-Bus","bus":"i2c-1","commType":"standard","addr":"0","useMux":false,"muxAddr":"112","muxPort":"0"},{"id":"ba830589.55bb38","type":"ui_tab","z":"","name":"Sensor Display","icon":"dashboard","disabled":false,"hidden":false}]
I have a long way to go:
1 My 'parsing' of the data I am receiving from the RTD, pH and ORP probes, and Flow Meter over i2c is a kludge.
2 I'm struggling with using the node-red-contrib-i2c nodes for complex commands. (necessary for devices that return multiple data... or for performing calibrations of sensors
3 My familiarity with json and java-script are minimal...only what I needed to hack on a website to make something look nice... so, I've got to bone up on those a bit to continue on with the project.
4 When CoVID-19 lock down is over, I'll get over to Xerocraft Hacker Space to take a laser cutter to the controller's enclosure (very old picture.. when it was an Arduino DUE project w/ UART connected devices):
My aquarium controller is geared towards planted aquariums. I'm using this controller on a 4 aquarium system that shares resources/equipment.
However, there is a hobbyist who is building an aquarium controller as well using Atlas-Sci i2c enabled circuits, raspberry pi and node-RED.. So we are comparing notes. I'll point him to this thread and maybe he will chime in on occasion. His stuff is impressive because he does 3d modelling of everything and 3d prints things.
MaddyP's Node-RED powered Reef Tank Controller
I hope you will contribute your experience to help with problems that will arise.