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.
I'm not sure if there is a more elegant way to do it; however, you can write some scripts that run on a loop to achieve what you're asking about I believe. Example:

[ACTIVATELOOP]
wait "Active Switch" State == on
"Device Element" enabled = true
start "Device Element Script"
goto "ACTIVATELOOP"

And in a separate script:
[DEACTIVATELOOP]
wait "Active Switch" State == off
"Device Element" enabled = false
stop "Device Element Script"
goto "DEACTIVATELOOP"

You need to turn the switch off, otherwise it will continue to restart the script or element.


[ACTIVATELOOP]
if "Active Switch" State == true
start "Device Element Script"
"Active Switch" State = false
goto "ACTIVATELOOP"

or to just turn on and element

But why a switch for that. You can just click on the Element to control it.

[ACTIVATELOOP]
if "Active Switch" State == true
"Device Element" state = true
"Active Switch" State = false
goto "ACTIVATELOOP"


You can use a "toogle" to control several elements

create a global value named something like
ACTIVATELOOPTOGGLE

It can be any unique name you want

set precision as 0

[ACTIVATELOOP]
if "Active Switch" State == true
if "ACTIVATELOOPTOGGLE" value == 0
"Device Element1" state = true
"Device Element2" state = true
"ACTIVATELOOPTOGGLE" value == 1
else
"Device Element1" state = false
"Device Element2" state = false
"ACTIVATELOOPTOGGLE" value == 0
endif
"Active Switch" State = false
goto "ACTIVATELOOP"
 
As a general comment on controlling some things automatically or with switches, I have a script I named 'scrAutoSwitch"

It is run constantly in the Brew and just loops the entire time.

It controls switches and some backgrounds of elements depending on the state they are in

As an example, a pump has a different background depending on the state of the digital out.

My red pump Off:
Pump_Red_Rip_Off.png


My red Pump on:

Pump_Red_Rip_On.png


it is easy to see the state of the pump and the looping script puts in the correct background.

I also use the visibility to display or not a global with a background for an element.

My Quadzilla Control Switch does several things.

It sets the valves correctly by setting a a valve control number (a global) and calling and script to set the valves according to the valve control number.

The valve backgrounds are set within the Auto Script to the correct background (different part of the script).

it sets the visibility for the elements to be visible when the Heating elements are enabled (on)

it may do other things but you have good control of the visual of the workspace

x.png
.
 
@BrunDog
It would be nice to have the Script Edit Mode independent of the Lock feature. I regularly move or resize elements when editing scripts. This is almost certain to happen if I increase the script window to 300 or above, If I could lock the screen, and then be able to edit the Scripts, it would prevent that issue.
 
Global Timers

Tried searching and could not find the answer. (still very new to scripting) My goal is to have a cluster of hop addition countdowns that all start when I start the boil process.

I'm able to create a timer and set the time and display name via a script no prob but while reading about it, it sounded like the experts are using globals as timers when creating multiple timers. I got as far as setting the time value for the global but got stuck.

In addition to setting the time, is it possible to set the display name and whether it counts up or down as well as start it via a script?
 
Global Timers

Tried searching and could not find the answer. (still very new to scripting) My goal is to have a cluster of hop addition countdowns that all start when I start the boil process.

I'm able to create a timer and set the time and display name via a script no prob but while reading about it, it sounded like the experts are using globals as timers when creating multiple timers. I got as far as setting the time value for the global but got stuck.

In addition to setting the time, is it possible to set the display name and whether it counts up or down as well as start it via a script?
Global variables don’t count up or down. You can change the display name though.

I use one timer element for boil/mash step time. One timer element is the easiest way in my opinion. I set the value of the timer element using a global variable in a script. The same script watches the timer element’s value (wait or if statement) for the end condition. This is either <= O (end of step) or the hop addition time (also a global variable). One can use global variables or script variables. I use a combination of both depending on what I am trying to do. Start with one type and play with it till you get it to function the way you want. Then refine/over complicate it later.
 
Global variables don’t count up or down. You can change the display name though.

I use one timer element for boil/mash step time. One timer element is the easiest way in my opinion. I set the value of the timer element using a global variable in a script. The same script watches the timer element’s value (wait or if statement) for the end condition. This is either <= O (end of step) or the hop addition time (also a global variable). One can use global variables or script variables. I use a combination of both depending on what I am trying to do. Start with one type and play with it till you get it to function the way you want. Then refine/over complicate it later.
Thanks! I think I will revise my screen to do just that. Use that same timer and repurpose it for each step....especially now that I know I can change the display name if I want to.
 
ok one more :)

Trying to set up a PWM PID for controlling my HLT. When updating the target in the device box, the Output (have converted to %) updates correctly.

When I have a global in a script setting the target, the target updates correctly as well as temp if I hold the probe but the output does not update until I stop the script. What am I missing in the script or is it not possible?
 
The output of the PID element is independent of scripts. The output will scale between 0-100% based on the actual temp and target temp. I don’t think you are missing anything. Try water testing…Does the pid element behave as expected when not using a script to set the target?
 
Global variables don’t count up or down. You can change the display name though.

I use one timer element for boil/mash step time. One timer element is the easiest way in my opinion. I set the value of the timer element using a global variable in a script. The same script watches the timer element’s value (wait or if statement) for the end condition. This is either <= O (end of step) or the hop addition time (also a global variable). One can use global variables or script variables. I use a combination of both depending on what I am trying to do. Start with one type and play with it till you get it to function the way you want. Then refine/over complicate it later.
I use one timer for almost every thing. I have been working on a complex hop script that add hops in groups (at the same time). It is a work in progress.

But basically I have a hop script that triggers an alarm at Hop Group1, Hop Group 2 ...... based upon the "boil mash whirlpool settle" timer. We use addition timers for
"fill transfer".

We do use a incremental Global value to control our Brew Script ( and therefore able to jump steps like adding distilled water or not).

You can also use a global value or a timer to control one script from another script based upon the value of the global or the timer value which can be set in the second script for different conditions to affect the first script.
 
Last edited:
Does the pid element behave as expected when not using a script to set the target?

Correct. If just controlling it via the element control settings with a temp probe plugged in, it works as expected. If the temp is 68 and I set it for 69, I see about 30% power. If I up it to 90, it goes to 100% power.

If I try to do target changes via a script and a global, the target value changes in the box as expected each time but the output remains at 0. It's only until I stop the script that the output updates in the element box.

Have not water tested yet. Was trying to get everything set up before taking my control box out to the garage. If it still works as a PWM element, not the end of the world if I can't see the output, just figured I was missing something in the script causing it to behave that way.
 
Correct. If just controlling it via the element control settings with a temp probe plugged in, it works as expected. If the temp is 68 and I set it for 69, I see about 30% power. If I up it to 90, it goes to 100% power.

If I try to do target changes via a script and a global, the target value changes in the box as expected each time but the output remains at 0. It's only until I stop the script that the output updates in the element box.

Have not water tested yet. Was trying to get everything set up before taking my control box out to the garage. If it still works as a PWM element, not the end of the world if I can't see the output, just figured I was missing something in the script causing it to behave that way.
PID Element output is controlled by the BruControl firmware. you can set different parameters and set the target temp by script, but not the output


I have never used them, but I think

PWM Elements can be controlled by scripts where the output is set by the user.
 
Script is below. I got it working. Most likely it was due to how I wrote it. :) I ended up adding another if and it works fine now.

[loop]
"ele_HLT" Target = "glo_HLTTarget" Value

if "sw_Strike" state == false
stop "tmr_Timer"
wait "sw_Strike" state == true
reset "tmr_Timer"
"tmr_Timer" DisplayName = STRIKE
start "tmr_Timer"

endif

sleep 1000
goto loop


This works

[loop]
if "sw_Strike" state == false
stop "tmr_Timer"
wait "sw_Strike" state == true

endif
sleep 5000

if "sw_Strike" state == true
"tmr_Timer" DisplayName = STRIKE
start "tmr_Timer"
"ele_HLT" Target = "glo_HLTTarget" Value

endif
goto loop
 
It appears that the sleep 1000 was the culprit. I added another half second and the original script works. I also messed with the Calc Time and the Out Time on the element but those didnt seem to make a different.
 
I’d set your target temp before the loop instead of in it. As written, you are continually resetting the target temp during each loop.
 
I’d set your target temp before the loop instead of in it. As written, you are continually resetting the target temp during each loop.
I am not sure exactly what @cdug619 is trying to do exactly.

If trying to set a timer for Strike and heat the water in his HLT to his target

I would do it this way:

// Time to Strike Timer
"tmr_Timer" value = 00:00:00
"tmr_Timer" type countup
"tmr_Timer" DisplayName = "TIME TO STRIKE"
"ele_HLT" Target = "glo_HLTTarget" Value
wait "sw_Strike" state == true
start "tmr_Timer"
"ele_HLT" enabled = true
// Exit Loop if Switch is False
[LoopTimetoStrike]
sleep 100
if "sw_Strike" state == false
goto "EndStrikeTimer"
endif
// Have the Switch Blink if Temp is reached
if "probe_HLT" value >= "glo_HLTTarget" Value
"sw_Strike" visibility = hidden
sleep 500
"sw_Strike" visibility = visible
sleep 2000
endif
goto "LoopTimetoStrike"
[EndStrikeTimer]
stop "tmr_Timer"
"ele_HLT" enabled = false
"sw_Strike" visibility = visible



Since you can reuse the "tmr_Timer" i generally do not do a reset but set according to the way I want the timer to act:

for Time to strike :

"tmr_Timer" value = 00:00:00
"tmr_Timer" type countup
"tmr_Timer" DisplayName = "TIME TO STRIKE"

For 90 minute Mash:

"tmr_Timer" value = 01:30:00
"tmr_Timer" type countdown
"tmr_Timer" DisplayName = "MASH"

Also about exiting Timers

wait "tmr_Timer" value <= 00:00:00

You must use the <= or >=.

== will NOT work.

Any timer is based upon milliseconds (which you cannot see), and since Scripts also use milliseconds to recheck something like a wait command, the timer must be exactly 00:00:00 at :0000 milliseconds at the exact same time as the check of the wait command. You likely have better odds at Powerball.

I always put a sleep 100 at the start of any loop. It makes stopping a script manually much easier.
It is such a small time it does not really effect the script, but does allow you to exit the script in the Script Pane.

[LoopTimetoStrike]
sleep 100


I also have different backgrounds for things like switches where I might have
background 1 is blue
background 2 is red

So rather than blink by visibility, I switch the backgrounds

// Have the Switch Blink if Temp is reached
if "probe_HLT" value >= "glo_HLTTarget" Value
"sw_Strike" background = 2
sleep 500
"sw_Strike" background = 1
sleep 400
endif

This has my switch blink Red and Blue after the Strike is reached.


You would need to set the

"sw_Strike" background = 1
when starting your Script and also after exiting a loop
 
Thanks! The goal was to just set and view the status of the HLT via globals. Thanks for the tips on the timer. Script was still a work in progress but good to know. I like the different colors on the switch as well!
 
Trying to get back into node red. I am having an issue with the service in BruControl.

When I go to Setting . Data Exchange the service is stopped. I have tried rebooting and clicking the buttons on the dialog, but the service does not start.

I left the port as 8000

I click the Reserve URL Button (It sorta blinks then appears to have the focus again.

I cannot get the Release URL or Service Enabled Switch to work.

I checked and I am sign in as an Administrator to my computer
 
Last edited:
Trying to get back into node red. I am having an issue with the service in BruControl.

When I go to Setting . Data Exchange the service is stopped. I have tried rebooting and clicking the buttons on the dialog, but the service does not start.

I left the port as 8000

I click the Reserve URL Button (It sorta blinks then appears to have the focus again.

I cannot get the Release URL or Service Enabled Switch to work.

I checked and I am sign in as an Administrator to my computer
Could it be the URL you have the service pointed to has an error in it. Not sure if this is related however back on post 7880 the user was able to correct the problem by changing the URL thru the command prompt. Just a thought
 
Last edited:
Trying to get back into node red. I am having an issue with the service in BruControl.

When I go to Setting . Data Exchange the service is stopped. I have tried rebooting and clicking the buttons on the dialog, but the service does not start.

I left the port as 8000

I click the Reserve URL Button (It sorta blinks then appears to have the focus again.

I cannot get the Release URL or Service Enabled Switch to work.

I checked and I am sign in as an Administrator to my computer
Solved!!!

@BrunDog

Perhaps this could be fixed in the program so that user names with spaces do not matter.

I found most of the solution with this post but found I needed to run PowerShell in admin mode.

https://www.homebrewtalk.com/thread...trol-automation-software.624198/post-10326168

The issue is that for the Data Exchange to be used:

You must reserve the URL.

Once you set the port on Settings -> Data Exchange
you will need to click the Reserve URL button.

If you have a user name with a SPACE, the button does not work.

It sorta blinks and remains highlighted,

The Release URL and the Service Switch are ONLY enabled when the URL is Reserved.

You cannot get the Service Switch to work until you reserve the URL!

As an example, my user name is John Smith.

it has a SPACE!

I have to manually reserve the URL.

You must use PowerShell as an administrator.

To open PowerShell as an administrator.

You need to be signed in as a user with Administrator privileges.

In Windows 10:
Windows Key + x
Select Windows PowerShell (Admin)

Windows 11:
Search for Windows Tools
Launch The Windows Tool App
Find Windows PowerShell
Right-Click
Run as administrator


Once PowerShell is up and running

use the following command


netsh http add urlacl url=http://+:8000/ user="John Smith"

Of course the URL Number should match the PORT used in Settings -> Data Exchange.

You also use "your name" instead of "John Smith"

Return to BruControl Settings -> Data Exchange and now the

Service Switch should be enabled.
Click to on.



The service should change from Service Stopped to Service Running

If the service is Service Stopped, you will see econnrefused under your function where you are trying to connect to the BruControl URL in Node Red.

Fortunately, the URL reserve is static and no affected by rebooting.
 
A Big THANKS to
@RiverCityBrewer
@CDCTx
@Tartan1

WE HAVE NODE RED UP AND RUNNING.

I am still in the process of creating "our" BeerSmith3 xml to BruControl using our Global Elements.

I understand Node Red much better now and have transferred data from BruControl using Node Red and transferred the XML Fields I want to BruControl (a work in progress but even if I do not see the light, I am in the tunnel heading towards it.)

I see the LIGHT! MY XML Flow is done!

I created my own FLOWS with help from the examples provided but I started from scratch to build them using our Global Element names.

Now that I know how to "get" and "put", I plan to create an ALEXA Skill to voice control my Brew Kettle Burner!
 
Last edited:
I would like to monitor the uptime of my connected interfaces thru Brucontrol. Two of my controllers are on 24/7 (both have battery backup) and I would like to monitor if any glitches occurred over a select time period of time. Is there a simple way of doing this, I do have additional MEGAS if 1 could be used as a device to monitor the other 2.
 
I would like to monitor the uptime of my connected interfaces thru Brucontrol. Two of my controllers are on 24/7 (both have battery backup) and I would like to monitor if any glitches occurred over a select time period of time. Is there a simple way of doing this, I do have additional MEGAS if 1 could be used as a device to monitor the other 2.
see BruControl: Brewery control & automation software

You could use this type of script to make what you want.
 
Thanks @oakbarn That looks like what Im after, I can customise the Element as required.
I would create global string to save the disconnect message . I think you need two separate scripts, one for each interface and put the disconnect message in that global string. It would be nice if there was a way to insert a line feed into a global string. I would put a wait at the end of my loop to get when the element is reconnected.
 
Put a \n in your string for a new line.
It works fine in BruControl but when exporting to a global string element value it produces a flat file with the \n in one of the cells. The flat file is a comma separated type with a comma delimiter but no line feed. I have tried various ALT + 13 and ALT + 13 and tried to embed those, but they are not giving the desired line feed.

I have attached a .txt csv file. I have put a ";" where I want the line feed.
 

Attachments

  • test_ispindel_sc.txt
    4.2 KB · Views: 0
Apologies, but I'm not following on what you want to achieve here. The newline or linefeed (\n) character is used in many applications, but if you are trying to import into Excel, it typically looks for a CR LF (\r\n) to signify the next row.
 
Help! Has anyone experienced anything like this?
Had a long vacation and have not brewed since December. Showed my system to my cousins last week and everything looked fine on my workspaces.
Today I powered up and logged in as usual, but when I started BruControl it opened a blank workspace and nothing is configured. I looked at the install directory and files located under my documents but do not understand what may have happened.
 
Try this.
1. Delete the settings file under
Documents/brucontrol folder

2. Reboot your computer
3 Start BruControl
4 . Go to Settings tab
5.Goto Configuration
6. Select your configuration
 
Try this.
1. Delete the settings file under
Documents/brucontrol folder

2. Reboot your computer
3 Start BruControl
4 . Go to Settings tab
5.Goto Configuration
6. Select your configuration
Thanks, but that's the weird part. There is nothing there under configuration. Its like I am logging in as a different user, but the is only one account. I use this computer only for BruControl. Microsoft Defender is reporting that it found malware Backdoor:MSIL/Bladabindi!atm and has quarantined it, so I have rebooted again and am doing a full scan now.
 
Node Red Gurus!

In Node Red Flow for the BeerSmithXML Flow to transfer data to BruControl, there are a couple of fields that I wonder why.

I obtained the flow (thanks @RiverCityBrewer ) years ago.

I was looking into it and cleaning some things up and adding some thing that I want.

For example there is a msg.PreBoil Volume that gets a String field from the XML file.

that has the JSONata

$number($trim($replace(msg.payload.RECIPES.RECIPE.DISPLAY_BOIL_SIZE, /[^0-9\.]/, "", limit)))
where it is parsing a String to a Number.



Yet in the top of the xml you have:

<BOIL_SIZE>94.1621181</BOIL_SIZE>

Of course this is in liters so it would need to be converted to Gallons in the US if you use gallons.

Is there a "good" reason to use the trimmed String instead the native Number in liters and convert it?


Perhaps another reason is that you can choose what standard you want displayed (gals vs liters) in BeerSmith, but the raw value is in liters regardless.
 
Last edited:
Those functions are there to remove whitespace and non-numeric characters that would break the process of converting the string to a number. The reason I went that way was to natively accept whatever displayed units the user operated in (defined in Beersmith or other program), vs the BeerXML standard (metric).
 
Back
Top