BruControl: Brewery control & automation software

Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum

Help Support Homebrew Talk - Beer, Wine, Mead, & Cider Brewing Discussion Forum:

This site may earn a commission from merchant affiliate links, including eBay, Amazon, and others.
After the native RTD calibration, if you want to match a certified thermometer, I suppose a lookup table would be best. You can start with just a few values then add more over time.

Using linear calculations... keep in mind if you are not at 0 and add a multiplier, it will move off zero further. So I think its better to use an offset to get to zero, then multiply, then another offset if absolutely needed (shouldn't).
 
After the native RTD calibration, if you want to match a certified thermometer, I suppose a lookup table would be best. You can start with just a few values then add more over time.

Using linear calculations... keep in mind if you are not at 0 and add a multiplier, it will move off zero further. So I think its better to use an offset to get to zero, then multiply, then another offset if absolutely needed (shouldn't).

I have a $$$ certified thermometer, but thinking linear is not going to cut it if I want good accuracy... after 4-5 rounds, the 32f and 170ish F are right on, but the 100-140 temps are not... there is a curve to that linear slope

yes, being at zero would be best, but I think the zero is zero kelvin, and I cannot get that :) this is where a calibration tool like BCS had would really shine...

also interesting is the three aliexpress RTD amp units are staying pretty tight with each other, but not the same as the adafruit one, and they actually seem to be closer to the calibrated temp. All 4 temp probes are "TOPINCN RTD PT100 Thermocouple Temperature Sensor Probe 1/2" NPT Thread Connector with 3 Wires 2M Cable, -58~572°F (-50~300°C)" from amazon.
 
I would strongly assume the amps are the same... but the probes aren't. Since those probes came from you-know-where, they are likely not very good quality or consistency. I'd be surprised if there were any actual platinum in there.
 
three are acting the same, one is different, I will do some swapping to see where differrence really is.. I will also set it up with 4 more different style but identical to each other units.. Any luck in the ESP32 firmware working with the RTD amps?

upload_2019-12-21_14-57-6.png
 
TILTS are on the way! In prep, I am working on my new script. Can someone help push me in the right direction?

The goal is to script an automatic cold crash when there is no longer a change in measured SG (FV-1 ACTUAL SG). Id like the script to start a counter (CrashCounter) and when a counter threshold is met, I can then tell the hysteresis device (FV-1 HYSTERESIS) to lower the temperature. I understand a threshold would likely need to be incorporated as we are dealing with computers and exact numbers.

What I currently have is for the counter to begin when it reaches a certain sum value based on user input estimated FG (CrashGravity). So CrashGravity is essentially .003 above estimated final gravity. This was my idea to ensure this condition is met and not get stuck (if the actual FG ends up being higher than estimated FG).

In an effort to improve this, I feel a continual 'check' for a static (or no change) actual gravity would be a better way to approach this. Basically, I want the temp change to occur is there is no change to gravity in a 48hr period.

[Setup]
new value CrashCounter
CrashCounter = 0
CrashCounter precision = 0

new value CrashGravity
CrashGravity = "FV-1 EST. FG" value
CrashGravity += .003

[Ramp-ColdCrash]
wait "FV-1 ACTUAL SG" value <= CrashGravity //I WANT THIS TO CHECK FOR A NO CHANGE IN GRAVITY

// The below gives a time delay prior to changing temperature..after delay is met, temperature will begin to ramp down
if "FV-1 ACTUAL SG" value < CrashGravity //I WANT THIS TO CHECK FOR A NO CHANGE IN GRAVITY
if CrashCounter < 3 // ensures loop once this condition is met interpreter will proceed
CrashCounter += 1
sleep 5000 // this is the time delay for CrashCounter (5 seconds for testing - change to days)
goto "Ramp-ColdCrash"
endif
endif

if CrashCounter >= 3
CrashCounter += 1
"FV-1 HYSTERESIS" value = 50
sleep 5000
endif

[Hold-ColdCrash]
if CrashCounter >= 5
CrashCounter += 1
"FV-1 HYSTERESIS" value = 30
sleep 5000
endif
goto "Hold-ColdCrash"

Perhaps using sleep is a poor way to drive the CrashCounter?
 
You can set the projected as above and then check the Tilt value . In fact, you could create an offset FG where it starts to check.

You could have a day counter so that the FG value = the same for 3 days then cold crash.

If the checked FG changes, the Day counter resets to 0.


new value vVdaycounter
new value vVSavedFG
"vVdaycounter" = 0
new value vVOrangeTiltSG
[Loop]
vVOrangeTltSG = “Orange Tilt” sg
//Returns the Specific Gravity as a Precision 3 number.
//Example: 1.011
if vVdaycounter == 0
if vVOrangeTiltSG <= CrashGravity
vVdaycounter = 1
"vVSavedFG" = vVOrangeTiltSG
endif
endif

// Add a Timer Delay of 24 hours here
sleep 86400000 //( I would use a timer)
if vVdaycounter == 1
if vVOrangeTiltSG == vVSavedFG
vVdaycounter = 2
"vVSavedFG" = vVOrangeTiltSG
else
vVdaycounter = 0
endif
endif
// Add a Timer Delay of 24 hours here
sleep 86400000 //( I would use a timer)
if vVdaycounter == 2
if vVOrangeTiltSG == vVSavedFG
goto "ColdCrash"
else
vVdaycounter = 0
endif
endif

goto "Loop"

[ColdCrash]

//set the temp to cold crash on the fermentor
 
Why not calculate a running derivative (difference) of the gravity and cold crash when that gets to some threshold for some number of cycles rather than relying on an absolute number? What if the FG isn't what you expected by 2 points?

Maybe something like:
Code:
new value d_SG
new value last_SG
new value done_count

[loop]

//Calculate change in gravity
d_SG = "FV1 Actual SG" value - last_SG

//Remember for next loop
last_SG = "FV1 Actual SG" value

if d_SG < 0.003
  done_count += 1
endif

if done_count > N
  goto "Crash_Fermenter"
else
  sleep (some amount of time)
  goto "loop"
endif

[Crash_Fermenter]
<some stuff>

Just a thought.
 
OK, I did a quick test of the 4 RTD probes, and it is definitely the RTD boards being different, not the probes. the Standard deviation of all 4 of my probes across a single board is only .4F (pretty darn good IMHO!)
The Standard deviation of a single probe across 4 boards, however is 2.7 degrees F... This is with no calibrations other than the RTD 430 and CtoF.

the temp with a glass thermometer known to be good within a few temps was 65.8 I can break out the calibrated one, but will round up all my RTD's for that, and will test at both 32 and 170 to get a better picture before making judgments on the boards..

Board 1 is the Adafruit, the others are aliexpress..

upload_2019-12-22_7-52-37.png
 
Interesting. The variations across the probes are consistent independent of the amplifier. I assume all the probes were in the same medium.

Do you have the right pad resistor values for each board? Some like the adafruit board uses a 430 ohm resistor where others might be 400.

I find this odd because they all use the same chip and the supporting circuitry shouldn’t add much variation (other than the resistor value).

Might be a worthwhile test to take the probes out altogether and wire in a 100 ohm resistor. This would eliminate wiring, connectors, and any self-heating that is happening in the probe I know the probes were consistent but isolation might tell you more.

All interesting stuff - RTDs should be dead-nuts, otherwise what’s the point?
 
One my ESP32, I have DC Pump PWM pins set up on pins 16 and 17. While pin 16 behaves as expected, pin 17 displays some weird behavior. I can change the PWM value, but when 0 is entered, it remains at its last value and does not shut off. Disabling the PWM element does not turn it off. The only way to stop the pump is to reboot the esp32. I have tried swapping pumps, pins, and plugs, so it is either the ESP32 has some weird behavior for that pin, or there is a bug in the firmware.
 
Why not calculate a running derivative (difference) of the gravity and cold crash when that gets to some threshold for some number of cycles rather than relying on an absolute number? What if the FG isn't what you expected by 2 points?

Maybe something like:
Code:
new value d_SG
new value last_SG
new value done_count

[loop]

//Calculate change in gravity
d_SG = "FV1 Actual SG" value - last_SG

//Remember for next loop
last_SG = "FV1 Actual SG" value

if d_SG < 0.003
  done_count += 1
endif

if done_count > N
  goto "Crash_Fermenter"
else
  sleep (some amount of time)
  goto "loop"
endif

[Crash_Fermenter]
<some stuff>

Just a thought.
This is continuing to count regardless of the change in gravity.Perhaps the problem lies in the d_SG = "FV-1 ACTUAL SG" value - last_SG? How can this be solved in the first 'scan' if last_SG has no value? I tried defining it as '0' in setup but that didnt help.

[setup]
new value d_SG
new value last_SG
new value done_count
last_SG = 0

[loop]

//Calculate change in gravity
d_SG = "FV-1 ACTUAL SG" value - last_SG

//Remember for next loop
last_SG = "FV-1 ACTUAL SG" value

if d_SG < 0.003
done_count += 1
endif

if done_count > 5
goto "Crash_Fermenter"
else
sleep 5000 //This is the delay
goto "loop"
endif

[Crash_Fermenter]
<some stuff>

[/code]
 
I'm not sure why...except that the loop time is 5 seconds and I don't know how much change you would see in that time, likely below the precision of the measurement. I don't have a Tilt, so I don't know how much noise there is in the measurement, but you might need to put a smoothing function in there for it (or maybe that can be done in the SG measurement).

I just kind of wrote that script out. I'll try out some experiments when I get a chance and try it, but I think that it is reasonable. The big thing is the time and how much the gravity moves in that time.
 
I'm not sure why...except that the loop time is 5 seconds and I don't know how much change you would see in that time, likely below the precision of the measurement. I don't have a Tilt, so I don't know how much noise there is in the measurement, but you might need to put a smoothing function in there for it (or maybe that can be done in the SG measurement).

I just kind of wrote that script out. I'll try out some experiments when I get a chance and try it, but I think that it is reasonable. The big thing is the time and how much the gravity moves in that time.
Well, I am not using the TILT yet. I am testing it with a global in which I manually change the gravity (more than .003 within 5 seconds).
 
Huh, alright. I'll try to figure out what I messed up...certainly wouldn't be the first time.
 
Interesting. The variations across the probes are consistent independent of the amplifier. I assume all the probes were in the same medium.

Do you have the right pad resistor values for each board? Some like the adafruit board uses a 430 ohm resistor where others might be 400.

I find this odd because they all use the same chip and the supporting circuitry shouldn’t add much variation (other than the resistor value).

Might be a worthwhile test to take the probes out altogether and wire in a 100 ohm resistor. This would eliminate wiring, connectors, and any self-heating that is happening in the probe I know the probes were consistent but isolation might tell you more.

All interesting stuff - RTDs should be dead-nuts, otherwise what’s the point?


Probes all in same medium, pic shows my setup, will check pad resistor, I wonder how that affects things vs a offset/multiplier.. wondering if I could use same resistor tied to all 4... Need to think about that, but likely the differences are in tolerances, and we know the adafruit ones are likely made in the same county as the others.... I made a little spreadsheet that helps me calibrate, now, sipping a beer, thinking that a script for calibration that uses either ice and boiling/altitude, a known calibrated RTD or input from a analog thermometer might be really cool thing to make. Of course, I came up with that idea while drinking a beer, so I need to remember in the AM!
 
Huh, alright. I'll try to figure out what I messed up...certainly wouldn't be the first time.

The test I ran on it seems ok.

The orange is the "done_count > 5" indicator
blue is the gravity.
Screen Shot 2019-12-22 at 6.02.09 PM.png
I generated it with two globals, one is "fermDone" (the orange) and the other global is the "FV-1 ACTUAL SG" counted down by a script.

EDIT: nope, I just happened to get it to line up right due to the counters...sorry

EDIT2: Silly me.

"FV-1 ACTUAL SG" - last_SG

will be negative as long as the gravity is falling, so it is always less than 0.003. So if you just change it to
//Calculate change in gravity
d_SG = last_SG - "FV-1 ACTUAL SG" value

I think it will be OK. Also, initialize last_SG to something like 2 so it is big to start.
 
Last edited:
What do you mean by

Also, initialize last_SG to something like 2 so it is big to start?

Are you saying in [Setup] to write
last_SG = 2

EDIT: got it, seems to be working now. Ill try to incorporate this into my Fermentation script. Thankyou for the help
 
Are you saying in [Setup] to write
last_SG = 2

Yup, just like that. It is only so that on the first iteration through the loop it doesn't think that the gravity went from 0 up to the first reading. It probably doesn't matter much, but it's good practice.
 
Yup, just like that. It is only so that on the first iteration through the loop it doesn't think that the gravity went from 0 up to the first reading. It probably doesn't matter much, but it's good practice.

Thanks brotha!
 
Just tested... pin 17 will respond to all value changes, including 0, but does not turn off when the element is disabled. 16 does. So this is odd but will take a look to see the root cause.

Not sure what is going on, but it does seem to be working on 17 now. Could have been some error in the ESP library, which has since been updated. Will be curious your test when we push updated FW per my next post.
 
In an effort to make some moves toward the 1-wire addressing some have requested... in the interim, we are adding the ability to have 1-wire sensors on any digital I/O pin up to 15. This should give everyone the flexibility to wire 1W sensors where they like. Specifically, it will help those using Sonoff or Wyze plugs where accessible I/O may be limited.

Upon initialization (startup or forced initialization via control code), the digital I/O pins will be scanned for any 1-wire temperature sensors. The pin where the first one is found will be the pin where 1-wire sensors are indexed.

This will be included in 45E, which we'll get online in the next couple of days.
 
Are the amplifiers needed for RTD on ESP32 or do they wire direct?

You need amplifiers to talk to the SPI bus in the ESP, and I use the 4-amp RP-3 board from BruControl for a nice package.... post #3142 has pic

Thinking, You could use the RTD's that have the amplifier in the housing to convert to analog and take analog in to the ESP32 on 32-36,and 39, but this is easy...
 
Last edited:
Can someone help me through an issue I'm having with my Alarm script? This script is designed to count (AlarmCounter) when a high or low value is read. Basically my attempt at not throwing an alarm if I get a spike. TEMP TEST and TARGET TEST are setup as global for testing. I basically change the TEMP TEST manually to test if its working. When I simulate the first spike (by adding or subtracting 20 to TEMP TEST from TARGET TEST value) it works as expected, the counter starts and if timer condition is met, alarm will sound. As intended, the alarm will shut off if returned within TARGET TEST range. The issue I am seeing is the alarm will sound prior to the counter running this occurs on the second iteration. After a few seconds, the alarm shuts off and performs as intended.

In other words its prematurely jumping to Alarm High/Low [Alarm-Fault] without cycling through [Alarm-Count] but only on the second iteration.

FV-1 TEMP TEST = Global
FV-1 TARGET TEST = Global
ALARM COUNTER = Inspector
FV-1 ALARM = ALARM



[Alarm-Setup]
new value AlarmLow
new value AlarmHigh
new value AlarmCounter
new value AlarmDelay
new string FV-1AlarmStatusTest

AlarmLow = "FV-1 TARGET TEST" value - 10
AlarmHigh = "FV-1 TARGET TEST" value + 10
AlarmDelay = 4 // This value is in seconds
AlarmCounter precision = 0

[Alarm-Check]
if "FV-1 TEMP TEST" value <= "FV-1 TARGET TEST" value
if "FV-1 TEMP TEST" value > AlarmLow
FV-1AlarmStatusTest = "SYSTEM OK"
"FV-1 ALARM" active = false
sleep 500
goto "Alarm-Check"
endif
endif

if "FV-1 TEMP TEST" value >= "FV-1 TARGET TEST" value
if "FV-1 TEMP TEST" value < AlarmHigh
FV-1AlarmStatusTest = "SYSTEM OK"
sleep 500
goto "Alarm-Check"
endif
endif

[Alarm-Count]
if "FV-1 TEMP TEST" value <= AlarmLow
if AlarmCounter < AlarmDelay
AlarmCounter += 1
print AlarmCounter
"FV-1 ALARM" active = false
FV-1AlarmStatusTest = "ALARM DELAY"
sleep 1000 // Defines AlarmDelay unit as 1 second
goto "Alarm-Count"
endif
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
if AlarmCounter < AlarmDelay
AlarmCounter += 1
print AlarmCounter
"FV-1 ALARM" active = false
FV-1AlarmStatusTest = "ALARM DELAY"
sleep 1000 // Defines AlarmDelay unit as 1 second
goto "Alarm-Count"
endif
endif

[Alarm-Fault]
if "FV-1 TEMP TEST" value <= AlarmLow
"FV-1 ALARM" active = true
FV-1AlarmStatusTest = "LOW ALARM"
sleep 5000
goto "Alarm-Count"
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
"FV-1 ALARM" active = true
FV-1AlarmStatusTest = "HIGH ALARM"
sleep 5000
goto "Alarm-Count"
else
AlarmCounter = 0
goto "Alarm-Check"
endif
 
I think it is that the reset for AlarmCounter is looped in here:

Code:
[Alarm-Fault]
if "FV-1 TEMP TEST" value <= AlarmLow
  "FV-1 ALARM" active = true 
  FV-1AlarmStatusTest = "LOW ALARM"
  sleep 5000
  goto "Alarm-Count"
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
  "FV-1 ALARM" active = true
  FV-1AlarmStatusTest = "HIGH ALARM"
  sleep 5000
  goto "Alarm-Count"
else
  AlarmCounter = 0   <<<<<<<-------
  goto "Alarm-Check"
endif

and so requires that the line below is true
Code:
if "FV-1 TEMP TEST" value >= AlarmHigh

but what if you are in AlarmLow and then come out of alarm? I don't think anything resets AlarmCounter, and so you would alarm immediately. It looks like you can't get back to [Alarm-Check] unless you have an AlarmHigh, so maybe that is it.
 
Last edited:
I think it is that the reset for AlarmCounter is looped in here:

Code:
[Alarm-Fault]
if "FV-1 TEMP TEST" value <= AlarmLow
  "FV-1 ALARM" active = true
  FV-1AlarmStatusTest = "LOW ALARM"
  sleep 5000
  goto "Alarm-Count"
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
  "FV-1 ALARM" active = true
  FV-1AlarmStatusTest = "HIGH ALARM"
  sleep 5000
  goto "Alarm-Count"
else
  AlarmCounter = 0   <<<<<<<-------
  goto "Alarm-Check"
endif

and so requires that the line below is true
Code:
if "FV-1 TEMP TEST" value >= AlarmHigh

but what if you are in AlarmLow and then come out of alarm? I don't think anything resets AlarmCounter, and so you would alarm immediately. It looks like you can't get back to [Alarm-Check] unless you have an AlarmHigh, so maybe that is it.

When i disabled the sleep commands in Alarm-Fault i got it to work. Perhaps I was changing the values before the sleep had a chance to move causing confusion with the interpreter?

Code:
    [Alarm-Setup]
new value AlarmLow
new value AlarmHigh
new value AlarmCounter
new value AlarmDelay
new string FV-1AlarmStatusTest

AlarmLow = "FV-1 TARGET TEST" value - 10
AlarmHigh = "FV-1 TARGET TEST" value + 10
AlarmDelay = 4                    // This value is in seconds
AlarmCounter precision = 0

   [Alarm-Check]
if "FV-1 TEMP TEST" value <= "FV-1 TARGET TEST" value
   if "FV-1 TEMP TEST" value > AlarmLow
   FV-1AlarmStatusTest = "SYSTEM OK"
   "FV-1 ALARM" active = false
   sleep 5000
   goto "Alarm-Check"
   endif
endif

if "FV-1 TEMP TEST" value >= "FV-1 TARGET TEST" value
   if "FV-1 TEMP TEST" value < AlarmHigh
   FV-1AlarmStatusTest = "SYSTEM OK"
   sleep 500
   goto "Alarm-Check"
   endif
endif

   [Alarm-Count]
if "FV-1 TEMP TEST" value <= AlarmLow
   if AlarmCounter < AlarmDelay
   AlarmCounter += 1
   print AlarmCounter
   "FV-1 ALARM" active = false
   FV-1AlarmStatusTest = "ALARM DELAY"
   sleep 1000                       // Defines AlarmDelay unit as 1 second
   goto "Alarm-Count"
   endif
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
   if AlarmCounter < AlarmDelay
   AlarmCounter += 1
   print AlarmCounter
   "FV-1 ALARM" active = false
   FV-1AlarmStatusTest = "ALARM DELAY"
   sleep 1000                       // Defines AlarmDelay unit as 1 second
   goto "Alarm-Count"
   endif
endif

   [Alarm-Fault]
if "FV-1 TEMP TEST" value <= AlarmLow
   "FV-1 ALARM" active = true
   FV-1AlarmStatusTest = "LOW ALARM"
   //sleep 5000    <<<<<<<<<<<-----------
   goto "Alarm-Count"
endif

if "FV-1 TEMP TEST" value >= AlarmHigh
   "FV-1 ALARM" active = true
   FV-1AlarmStatusTest = "HIGH ALARM"
   //sleep 5000
   goto "Alarm-Count"
else
   AlarmCounter = 0
   goto "Alarm-Check"
endif
 
I'm starting to have scripts reference other scripts. Start, stop, pause and resume make sense but...how does loading a script differ from starting a script?
 
Two questions...
1. Can i make a statement that says something along the lines...
if "script" = paused
inspector status = "script paused"
endif

2. Would the interpreter understand something like this?
if "Timer" == 00:00:00:30
inspector status = "time elapsed"
endif

I don't see much examples for if statements when checking against a defined time elapsed time

Merry Christmas All!
 
You caught after much imbibing. However. Yes.


1 if “script” state != running


2 need more details. Time elapsed means?
 
You caught after much imbibing. However. Yes.
::Google search: imbibing.... Nice [emoji4]
1 if “script” state != running
Thanks, ill give this a shot. So we have running, stopped (?), paused (?) and loaded (?) I don’t see much mention of this in the manual.
2 need more details. Time elapsed means?
Like if 20sec has went by then turn on pump..Id like to use an if statement when a certain value has been reached on timer.
 
Last edited:
Back
Top