• Please visit and share your knowledge at our sister communities:
  • If you have not, please join our official Homebrewing Facebook Group!

    Homebrewing Facebook Group

Crane's Never ending Brewery Upgrades

Homebrew Talk

Help Support Homebrew Talk:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
You guys kill me! With your automatic stuff. I love it, but I have a hard time understanding gravity!!! :ghostly:

Isn't that whats to great about this hobby? We can all participate at the level we are comfortable with and still make great beer. There are so many different areas to go hog wild and geek out on; from automation, to hi-tech home yeast wrangling labs. However, none of that is necessary to make a good batch.
 


You may notice in this video that there is a moment where the 2 yellow/green LEDs turn gray. I didn't realize this at the time, but the Arduino Mega in my second panel was being reset because of the butterfly valve.

I soldered some resistors and capacitors I had on hand to create some RC snubbers for the valve's power lines, but that didn't completely take care of the problem. The Mega would still occasionally reset while the valve was moving. So something else is also going on here. I am using the feed back signals from the valve to know when its fully open/closed. I use these in my script to prevent the script from advancing too soon without having to put in arbitrary sleep statements.

Turns out the motors on these valves put out a significant amount of EMI/EMC. This EMC was being coupled to the open/close feedback signals going to the digital inputs on the Mega. I had some of these ferrite beads sitting around that I ripped out of old VGA computer monitor cables. I put one around the feedback signals and that took care of the Mega resetting while the motor was moving.

zmf-700a4.jpg
 
Which DC pumps were you running that you found you were not satisfied with their performance?

Some of the 24V tan guys. I also bought some March 24VDC pumps off Ebay a while back. They came without heads, so I bought some chugger heads for them.

IMG_20200418_125631.jpg


DC pumps definitely need closed loop feedback and a comfort knowing you can't start them at slow speeds.

Correct. These things can be accounted for and were with my deadband flow control scripts. However, given that I needed to add a way to restrict the flow during sparging (proportional valve), it made sense to switch to AC pumps. AC pumps also have a higher max flow rate which will help to reduce heat stratification in the HLT, and better whirlpool cone formation in the BK.
 
I cut off one of the handles on the MT and cut the corners off the base plate of my crappy barley crusher/drill combo, so I can mill directly into the MT. Definitely cut down on the amount of grain dust in the air.

IMG_20200418_163238.jpg


I'm pretty sure I have a new best friend and its name is CIP.

IMG_20200419_122830.jpg


I brewed today... So my garage is cleaner than ever.
 
I cut off one of the handles on the MT and cut the corners off the base plate of my crappy barley crusher/drill combo, so I can mill directly into the MT. Definitely cut down on the amount of grain dust in the air.

View attachment 676486

I'm pretty sure I have a new best friend and its name is CIP.

View attachment 676488

I brewed today... So my garage is cleaner than ever.

You're letting me down with that drill attached to your mill, at least mount a maker motor to it o_O. Yeah CIP is the first thing I got up and running once I finished my brew day script, it makes life much better.
 
You're letting me down with that drill attached to your mill, at least mount a maker motor to it o_O. Yeah CIP is the first thing I got up and running once I finished my brew day script, it makes life much better.
A new mill and motor are on my list of the never ending upgrades...
 
I plan on using it to acidify strike and sparge water as well as dosing for the acid rinse at the end of the CIP routine. It uses an SNx4HC595 8-Bit Shift Register to select which pump to activate (0-3) and 4 ULN2003A darlington transistor arrrays to drive the pumps. You could write a script in BruControl to bit bang digital IOs, but I opted to use my nodeMCU data exchange solution here instead. I have 3 globals set in BruControl, DosingPumpSend, DosingPump, and DosingTime. DosingPumpSend is a boolean to tell it to start pumping. Once its finished pumping it will write false back to this global so BruControl can know when its done in case I dose multiple things back to back. It reads DosingPump to get the index of what pump to activate and DosingTime to know how long to keep the pump on for. To calibrate this, I will do the same as the original control board where I will time how long it takes to fill a known volume. I will have a script in BruControl that will convert a global for dosing volume to the DosingTime global.

Code:
/**********************************************************************************
* Dosing Pump BruControl nodeMCU http bridge
* Version: 1
*
* BruControl nodeMCU http bridge framework Version: 0.2
*
* This framework provides a bridge between a nodeMCU and BruControl using BruControl's
* http GET/PUT data exchange protocol.
*   Basic flow
*     1. Every checkInterval each BruControl global variable in the globalsToRead array is read
*        and its value is placed in the corresonding index in the globalReadValues array.
*     2. Every calcInterval user defined code is ran to:
*           process inputs
*           interface with devices
*           calculate return values
*     3. Every sendInterval each BruControl global variable in the globalsToWrite array's
*        corresponding value in the globalValuesToWrite array is sent back to BruControl.
*
* General use of this framework.
*     Place your user code within the @@@@@@@@@@@ sections
*     There should be no need to modify the code outside of these sections.
*
************************************************************************************/


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Interfaces to Jebao DP-4 auto dosing pump.
*
* Polling BruControl for DosingPumpSend updates
*   DosingPumpSend is a boolean.  Transitioning from false to true triggers triggers
*   the following:
*     1. Reads DosingPump value (integer 0-3 for what pump to turn on)
*     2. Reads DosingTime value (integer representing how many milliseconds to turn
*        the pump on for.
*     3. Doses the pump for the time called for.
*     4. Writes to DosingPumpSend to indicate that the dosing is complete in case
*        multiple doses will be performed back to back.
*
* Jebao DP-4 Uses SNx4HC595 8-Bit Shift Register to select which pump to activate (0-3)
* and 4 ULN2003A darlington transistor arrrays to drive the pumps.
*
* This uses the shiftout function to write the bits into the shift register.
* Only one pump can be on at a time.
*
* Calibration from dispense volume to pump time will be accounted for in BruControl.
* Create a script to time how long it takes to fill a container to a desire volume.
* Use a button to capture the time once the calibration volume is reached.
*
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>


/**********************************************************************************
* BruControl Settings
*
* Modify the following code for the number of globals you want to read and update
* from/to BruControl, with they names of each global as it is named in BruControl.
*
* Set the server IP address and port as needed.
*
***********************************************************************************/
// The following are used to define what global variables in BruControl to monitor and update.
#define READSIZE 3  // Number of global variables to read
#define WRITESIZE 1  // Number of global variables to update
// Optional to define indices for variables to make it easier to use them
// Read Array Indices
#define DOSINGPUMPSENDINDEX 0
#define DOSINGPUMPINDEX 1
#define DOSINGTIMEINDEX 2
// Write Array Indices
#define DOSINGPUMPSENDINDEX 0
// Create arrays
String globalsToRead[READSIZE] = { "DosingPumpSend", "DosingPump", "DosingTime" }; // List of global variables to read as they are named in BruControl
String globalReadValues[READSIZE]; // Array to store read values in
String globalsToWrite[WRITESIZE] = { "DosingPumpSend" }; // List of global variables to update as they are named in BruControl
String globalValuesToWrite[WRITESIZE]; // Array to store write values in

// BruControl Server settings
char serverAddress[] = "xxx.xxx.xxx.xxx"; // BruControl Server IP Address
int port = 8000; // BruControl Server port

// Scheduling interval
unsigned long int delayInterval = 1000;  // milliseconds between each time the main loop runs
/**********************************************************************************
* End BruControl Settings
***********************************************************************************/

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
* Place user defined initialization code below
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

//Pin connected to latch pin (ST_CP) of 74HC595
#define LATCHPIN 12
//Pin connected to clock pin (SH_CP) of 74HC595
#define CLOCKPIN 14
////Pin connected to Data in (DS) of 74HC595
#define DATAPIN 13

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
*  End User defined/modifiable variables
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/


String readString; //String loaded with results from HTTP get requests
char temp_string[300]; // temp string used for sprintf's and other crap
ESP8266WiFiMulti WiFiMulti;

void setup() {
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
  * Place user defined setup code below
  *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
  // moved user defined setup first so pumps don't turn on randomly when powering on.
  //set pins to output because they are addressed in the main loop
  pinMode(LATCHPIN, OUTPUT);
  pinMode(DATAPIN, OUTPUT);
  pinMode(CLOCKPIN, OUTPUT);
  registerWrite(8, HIGH); // clear register so no pumps are on

  /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
  * End user defined setup code
  *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

  Serial.begin(115200);
  Serial.println();
  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP("SSID", "PASSWORD"); //Change this to your Wifi settings
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println(WiFi.localIP().toString());


  delay(5000);
}


/**********************************************************************************
*  Main Loop to get inputs from BruControl, process them, calculate outputs,
*  and send updates back to BruControl
*
*  This allows you to use global variables in BruControl to interface with
*  unsupported devices.
*    
***********************************************************************************/
void loop() {
  Serial.println("### Starting Main Loop ###################################################");
  Serial.println("  ## Starting to read variables from BruControl #####");
  getGlobals(); // get updates from BruControl
  Serial.println("  ## Done reading variables from BruControl #####");
  Serial.println("  @@ Starting to Parse and Caculate user code @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@U@@@@@@@@@@@@");
  /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
  * Place user function calls here
  *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

  if(globalReadValues[DOSINGPUMPSENDINDEX] == "True") {
    registerWrite(globalReadValues[DOSINGPUMPINDEX].toInt(), HIGH); // turn on pump
    delay(globalReadValues[DOSINGTIMEINDEX].toInt()); // wait correct amount of time
    registerWrite(8, HIGH);  // Turn off pump
   
    globalValuesToWrite[DOSINGPUMPSENDINDEX] = "False";  // Tell BruControl we are done
  }


  /*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
  * End user function calls
  *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
  Serial.println("  @@ Done with user code @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
  Serial.println("  ## Starting to write outputs back to BruControl #####");
  sendGlobals();  // send updates to BruControl
  Serial.println("  ## Done writing outputs to BruControl #####");
  delay(delayInterval);  // set delayInterval to how long you want to wait between executing the main loop
}
/**********************************************************************************
*  End Main Loop
***********************************************************************************/


/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
*  Place user defined functions below for processing inputs, interfacing with
*  devices, and calculating return values.
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/



void registerWrite(int whichPin, int whichState) {
// the bits you want to send
  byte bitsToSend = 0;

  // turn off the output so the pins don't light up
  // while you're shifting bits:
  digitalWrite(LATCHPIN, LOW);

  // turn off clock before writing since we clock on rising edge.
  digitalWrite(CLOCKPIN, LOW);

  // turn on the next highest bit in bitsToSend:
  bitWrite(bitsToSend, whichPin, whichState);

  // shift the bits out:
  shiftOut(DATAPIN, CLOCKPIN, MSBFIRST, bitsToSend);

    // turn on the output so the LEDs can light up:
  digitalWrite(LATCHPIN, HIGH);
}



/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
*  End user defined functions
*
*  Start of framework functions
*    Don't modify the code below here!!!!
*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/


/**********************************************************************************
* getGlobals()
*
* Framework function to iterate through the array of BruControl global variables
* to get current values.
*
* This function will read all global variables in the globalsToRead array
* and fill the globalReadValues arrays with their current values.
*
* Do not modify this function. Instead set the following at the top of this file:
*   READSIZE - number of global variables to update
*   globalsToRead - names of global variables as they are named in BruControl
*   globalReadValues - Values for each global variable
*
***********************************************************************************/
void getGlobals() {
  int i;
  for(i=0; i<READSIZE; i++) {
    globalReadValues[i] = getVariableValue(globalsToRead[i]);
    Serial.print("     readString Is: ");
    Serial.print(globalsToRead[i]);
    Serial.print(", ");
    Serial.println(globalReadValues[i]);
  }
}


/**********************************************************************************
* sendGlobals()
*
* Framework function to iterate through the array of BruControl global variables
* to send updates to.
*
* This function will send all global variables in the globalsToWrite array with
* corresponding values from the globalValuesToWrite array.
*
* Do not modify this function. Instead set the following at the top of this file:
*   WRITESIZE - number of global variables to update
*   globalsToWrite - names of global variables as they are named in BruControl
*   globalValuestoWrite - Values for each global variable
*
***********************************************************************************/
void sendGlobals() {
  int i;
  for(i=0; i<WRITESIZE; i++) {
    sendVariableValue(globalsToWrite[i], globalValuesToWrite[i]);
    Serial.print("     Write: ");
    Serial.print(globalsToWrite[i]);
    Serial.print(", ");
    Serial.println(globalValuesToWrite[i]);
  }
}


/**********************************************************************************
* getVariableValue()
*   globalVariable - name of global variable as it appear in BruControl.
*
* Framework function to get values of individual BruControl global variables.
* This function is called by the getGlobals() framework function.
* The user should not call this function directly
*
* returns value of global variable in String form
*
***********************************************************************************/
String getVariableValue(String globalVariable) {
  String payload = "";
  StaticJsonDocument<512> jsonDoc;
  char temp1[100];
  char temp2[100];

  // wait for WiFi connection
  if ((WiFiMulti.run() == WL_CONNECTED)) {
    WiFiClient client;
    HTTPClient http;
   
    globalVariable.toCharArray(temp1,100);
    sprintf(temp2, "/global/%s", temp1);
    if (http.begin(client, serverAddress, port, temp2)) {
      // start connection and send HTTP header
      int httpCode = http.GET();

      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          payload = http.getString();
        }
      } else {
        Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
      http.end();
    } else {
      Serial.printf("[HTTP} Unable to connect\n");
    }
  }  
  payload.toCharArray(temp1,300);
  DeserializationError error = deserializeJson(jsonDoc, temp1);
  if(error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return "";
  }
  const char* returnValue = jsonDoc["Value"];
  return returnValue;
}


/**********************************************************************************
* sendVariableValue()
*   globalVariable - name of global variable as it appear in BruControl.
*   variableValue - value of variable in string form to send back to BruControl.
*
* Framework function to send updates to individual BruControl global variables.
* This function is called by the sendGlobals() framework function.
* The user should not call this function directly
*
***********************************************************************************/
void sendVariableValue(String globalVariable, String variableValue) {
  char temp1[100];
  char temp2[100];
  char temp3[100];

  if ((WiFiMulti.run() == WL_CONNECTED)) {
    WiFiClient client;
    HTTPClient http;

    globalVariable.toCharArray(temp1,100);
    variableValue.toCharArray(temp2,100);
    sprintf(temp3, "[{\"Name\":\"%s\",\"Value\":\"%s\"}]", temp1, temp2);
    String jsonToWrite = temp3;

    if (http.begin(client, serverAddress, port, "/globals")) {  // HTTP
      http.addHeader("Content-Type", "application/json");
      http.addHeader("Content-Length", String(jsonToWrite.length()));
      // start connection and send HTTP header
      int httpCode = http.PUT(jsonToWrite);
      // httpCode will be negative on error
      if (httpCode > 0) {
        // HTTP header has been send and Server response header has been handled
        if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
          String payload = http.getString();
        }
      } else {
        Serial.printf("[HTTP] PUT... failed, error: %s\n", http.errorToString(httpCode).c_str());
      }
      http.end();
    } else {
      Serial.printf("[HTTP} Unable to connect\n");
    }
  }
}
 
I got the nodeMCU mounted into the case nice and clean by reusing the ribbon cable from the original control board. I added a USB connector so I can change the FW without having to open it up.

I decided to go a different route for calibrating it. In favor of laziness and increased accuracy, I filled a beaker for a fixed time and measured the volume transferred. This removed any delay between my eagle eyes and pressing a key making it more accurate and it didn't require any special calibration script.

IMG_20200718_171912.jpg


MVIMG_20200718_171950.jpg


IMG_20200718_172543.jpg


IMG_20200719_140630.jpg


IMG_20200719_141955.jpg
 
Here is the dosing pump ready for action.

stand.jpg


And the accompanying dashboard graphics update. I had a nice open space in the bottom right corner to add in the dosing pump. I do have to say my Paint 3D skills are becoming more proficient. Did not take much time at all to whip those renderings together.

dashboard.PNG


And finally the code in node-Red to parse the miscellaneous ingredient list from the BeerXml file to find the amounts for the strike and sparge acid additions. The parseFloat() function is great for stripping off the units as it converts from string to float. "9.6 mL"=> 9.6

nodeRed.PNG
 
I was never really thrilled about the first mini PC I had for running BruControl. I bought a minis forum pc for the remote display in the garage and was satisfied with it. I then bought another one with more horsepower. The first one I bought had the bios setting to automatically boot whenever AC power is applied, but the second one for running BruControl did not have this option in the bios. It also was somewhat sluggish when running BruControl. I ended up getting a thinkcenter mini PC. This now has all the features I need for my main BruControl PC.

On the first PC I used, I didn't have any issues with having multiple devices communicate back to BruControl using the data exchange. However, on this new one I wasn't able to get this to work out of the box. From a web browser on the BruControl PC I was able to see all my globals with http://localhost:8000/globals. But when I changed localhost to the IP address of the BruControl PC, I got a connection refused error. In the end I needed to setup inbound and outbound rules to the windows firewall to open port 8000.

Below is the original pc for running BruControl. One nice thing about that PC is that it came with a bracket to mount it off the side of the VESA mount on the back of the monitor. The new PC did not come with such a thing. Most of the VESA mounts don't allow you to mount a mini PC and use a monitor stand simultaneously.

IMG_20200314_085824.jpg


I found this mount on Amazon that allows you to sandwich the mini PC in between the monitor and the monitor stand.

IMG_20200906_181243.jpg


And this is the brew command center.

IMG_20200906_181329.jpg
 
A bunch of new things for the brewery have come in. I wasn't getting a very tight hop/trub cone from whirlpooling so I picked up the larger 65 watt MKII pump on a black Friday deal. Now I need to silver solder some TC fittings on and it will be ready to speed things up.

PXL_20201224_004401558.jpg


The plastic push fittings I was using for the acid dosing kept cracking and breaking. I found some stainless ones from automation direct that will hopefully hold up much better.

PXL_20201216_011609850.jpg


PXL_20201216_013053929.jpg


PXL_20201216_012811024.jpg
 
Last edited:
I have been planning out a new control panel build that will hopefully be future proof enough to last me a long time. Once I started accumulating parts for the build, I went ape **** on ebay. I got some really good deals on about half of these transmitters. 3 PH, 5 DO, and 1 conductivity.

PXL_20201214_020843099.jpg


And to go along with that we need sensors. Again, I got some good deals on ebay, like these conductivity sensors.

PXL_20201212_233450611.jpg


I picked up some PH sensors that were new in their boxes for a fraction of their retail cost. I also found 3 matching PH probe holders that I will convert from 25mm threaded to tri clamp.

PXL_20201125_221418681.jpg


PXL_20201125_220957822.jpg


PXL_20201126_162109673.jpg


PXL_20201125_221201650.jpg
 
And to round things out I got another steal of a deal on these DO probes. The majority of the cost for these probes is the $100 per probe rebuild kit. And these will also be converted from 25mm to tri clamp.

PXL_20201212_234054409.jpg

PXL_20201213_023628567.jpg

PXL_20201213_024344775.jpg

PXL_20201213_024543092.jpg
 
Nice eBay finds! I thought I was the only one who has a problem with collecting future parts on eBay. But yeah, the InPro rebuild kits are dang expensive, my pricelist has them for $516 for a 4 pack of T-96... Ugh. Anyway, I love your build, keep up the good work. You saved me time and Arduino inputs by pointing out the over voltage when a SM6004 goes over its high threshold. If you've ever thought about having welded tri-clamps on the SM6004, let me know. You can find pictures on my instagram @benchmadebeer if you're curious. Cheers!
 
Thanks for the compliments. Glad my testing of those SM6004s has helped others. I checked out your Instagram. I never heard of an orbital welder before. Look pretty interesting for tubing butt welds.
 
While we are on the topic of over volting analog inputs, I had an incident where one of my pressure sensor went above 5V and burnt up that input on the mega. I chose to go with the rugged circuit's megas for this build. They have better onboard power supplies that I can reliably run on 12-24V, dedicated screw terminals for power input, holes for DIN mounts, and over voltage protection on the IO. However, these are almost 10x the cost of a cheapo mega.

IMG_20201226_190721_234.jpg
 
Love this thread, and great job. As if you didn't already know.

I'm an engineer at a medical device manufacturer and fairly familiar with automation equipment. I mention it only to say - wow - you've got a pretty incredible setup!
 
Great idea on the rugged boards, voltage spikes sure can wreak havoc with the boards. I sometimes get some flyback spikes form my natural gas ignitors, even though its all shielded... A Hot Surface Ignitor would fix that issue, but thats a bit of rework. I'm prototyping with my 11gal batch system using traditional MEGAs, my 1.5bbl automated rig will be on the AutomationDirect P1AM-100 Arduino platform. It is UL listed, which has a benefit if I decide to partner with a fabricator to build pilot brewing systems.
 
Still pretty awesome! (I think I already commented earlier.)
Regarding oxygen sensors: if I remember correctly, the oxygen measurement heads were going bad and had to be replaced with some regularity (every two years?) on the ODH (oxygen deficiency hazard) monitoring system of a large installation I was working on a decade ago. Now maybe/hopefully the dissolved oxygen detectors are different.
 
From what I have read rebuilding doesn't always require replacing the membrane. It may only need to be cleaned and refilled with new electrolyte. Also the rebuild time is dependent on many factors like heat cycling, vibration, and pressure. But yes you are correct that these do have an additional cost of periodic maintenance.
 
Back
Top