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.
*feature request* - I would really like the ability to export just a single 'DevicePort' and 'Element' from a running config to a file, then to change configurations and import that to the new configuration... just a single element, not changing interfaces or doing any fancy error checking other than 'port in use, element name exists, and maybe needs z-order changed), but it would save hours of work in keeping my 4-5 configurations up to date...
 
OK, appreciate the tip. I suppose we could add 'Export Element' and 'Import Element' functions. Would have to think through interface compatibility. I would honestly not call this a high priority for things being added to the 1.2 list... but will add it!

That said, maybe there is a better way than using multiple configurations?
 
call and return

Assumptions:

The call command will call a section in its own script.

It cannot call a section in a different Script.

The return command will return to the line following the call command.


new value CountX

CountX = 1

Lots of code

call “add CountX"

//return comes to here

lots of other code

call “add CountX"

//return comes to here

More code

call “add CountX"

//return comes to here

Even More code

//Sub Routine

[add CountX]

CountX =+ 1

return
 
ditto Clearwatersbrewer request:

I use different configurations for different Brews that we repeat. Right now, I just make a copy of a config file and rename it.


I would also love to have better control of Elements, Workspaces and Interfaces. In addition to Export and Import, Cloning an Element on a Workspace would be great with 99% of the properties. Just leave the Name, Port and Interface to be assigned.

Which brings in a second point. Move an Element to a different Port and or Port and Interface rather than being read only.

Would also like the manual Workspace... button on an Element to also be a command in a script

move workspace "My Element" = "Workspace 2"
 
call and return

Assumptions:

The call command will call a section in its own script.

It cannot call a section in a different Script.

The return command will return to the line following the call command.


new value CountX

CountX = 1

Lots of code

call “add CountX"

//return comes to here

lots of other code

call “add CountX"

//return comes to here

More code

call “add CountX"

//return comes to here

Even More code

//Sub Routine

[add CountX]

CountX =+ 1

return

Hi. Not sure what you are saying here... is this a request? The subroutine function was added in v1.1, so this exists as you have written it. You cannot call a section in a different script - variables like your "CountX" are local to the script and will not cross scripts. If you want to run a different script, you can use the 'start' command to do it (and use a Global to cross data back and forth).
 
ditto Clearwatersbrewer request:

I use different configurations for different Brews that we repeat. Right now, I just make a copy of a config file and rename it.


I would also love to have better control of Elements, Workspaces and Interfaces. In addition to Export and Import, Cloning an Element on a Workspace would be great with 99% of the properties. Just leave the Name, Port and Interface to be assigned.

Which brings in a second point. Move an Element to a different Port and or Port and Interface rather than being read only.

Would also like the manual Workspace... button on an Element to also be a command in a script

move workspace "My Element" = "Workspace 2"

I agree that cloning an element would be beneficial. Would facilitate setting up multiple of the same types. Moving the element to a different port should be possible too, so long as that port has that capacity.
 
ditto Clearwatersbrewer request:

I use different configurations for different Brews that we repeat. Right now, I just make a copy of a config file and rename it.

"

All of this is can be done via an xml import, using node red and using global variables. I seeent it. Maybe direct interface functionality will be enabled on a future release. Which would allow say a beermith ( or any other brewing program that can spit out an xml file) to dynamically change the session for the day.
 
The easy way would be to have RPi3B run BC natively and I have 3-4 of them on a pro-license ;-)

I guess I could have one config and scripts that hide/deactivate elements, and I guess scripts could allow a single config to handle switching temp sensors if we could assign them by hardware address, not order of appearance... I have upwards of 20 1-wire sensors, but only 8-10 plugged in at any one time..
 
so right now, after adding a new analog pressure sensor to one config, I want it in my other configs.. I could take the below and cut and paste it into another configuration, but I am afraid that 'z-order' or something else would break it, that is why the export/import would be handy.. (I do not see 'z-order' in my snippet, so not sure what else I am missing... I would personally export nearly every element and keep them in a folder as a library, then import is where the error checking intelligence is.....
Code:
<Configuration xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Devices>
    <Device>
      <Ports>
        <DevicePort xmlns="" i:type="AnalogInPort">
          <Enabled>true</Enabled>
          <ID>c7bd553e-3a0b-4d9b-8eba-78b974fe5663</ID>
          <Number>102</Number>
          <PrimaryDisplayChannel>0</PrimaryDisplayChannel>
          <RefreshMultiple>1</RefreshMultiple>
          <AvgWeight>25</AvgWeight>
          <CalValue>
            <Calibrations>
              <Calibration xmlns="" i:type="MultiplierCalibration">
                <Enabled>true</Enabled>
                <Multiplier>0.029297</Multiplier>
              </Calibration>
              <Calibration xmlns="" i:type="OffsetCalibration">
                <Enabled>true</Enabled>
                <Offset>-2</Offset>
              </Calibration>
            </Calibrations>
            <Precision>1</Precision>
            <Prefix></Prefix>
            <RequestedValue>0</RequestedValue>
            <Suffix>psi</Suffix>
          </CalValue>
          <PollRate>500</PollRate>
        </DevicePort>
      </Ports>
    </Device>
  </Devices>

  <Workspaces>
    <Workspace>
      <Elements>
        <Element xmlns="" i:type="DeviceElement">
          <Appearance>
            <BackgroundImageIndex>0</BackgroundImageIndex>
            <BackgroundImages xmlns:d7p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
              <d7p1:string></d7p1:string>
              <d7p1:string></d7p1:string>
              <d7p1:string></d7p1:string>
            </BackgroundImages>
            <BorderVisibility>Default</BorderVisibility>
            <CircularGaugeOptions>
              <Layout>Full</Layout>
              <MajorTickCount>11</MajorTickCount>
              <MaxValue>100</MaxValue>
              <MinValue>0</MinValue>
              <MinorTickCount>4</MinorTickCount>
              <Style>Default</Style>
            </CircularGaugeOptions>
            <DigitalGaugeOptions>
              <DigitCount>1</DigitCount>
              <Mode>Default</Mode>
              <Style>Default</Style>
            </DigitalGaugeOptions>
            <DisplayKind>Text</DisplayKind>
            <IndicatorOptions>
              <OffColor>Off</OffColor>
              <OnColor>Green</OnColor>
            </IndicatorOptions>
            <LinearGaugeOptions>
              <MajorTickCount>11</MajorTickCount>
              <MaxValue>100</MaxValue>
              <MinValue>0</MinValue>
              <MinorTickCount>4</MinorTickCount>
              <Orientation>Vertical</Orientation>
              <Style>Default</Style>
            </LinearGaugeOptions>
            <NameAlignment>Default</NameAlignment>
            <NameBackColor i:nil="true" />
            <NameFont i:nil="true" />
            <NameForeColor i:nil="true" />
            <NameVisibility>Default</NameVisibility>
            <TextDisplayOptions>
              <FalseText></FalseText>
              <Precision>0</Precision>
              <TrueText></TrueText>
            </TextDisplayOptions>
            <ValueAlignment>Default</ValueAlignment>
            <ValueBackColor i:nil="true" />
            <ValueEnlargement i:nil="true" />
            <ValueFont i:nil="true" />
            <ValueForeColor i:nil="true" />
            <Visibility>Default</Visibility>
          </Appearance>
          <Enabled>false</Enabled>
          <Height>140</Height>
          <ID>cebca8ea-4210-42bc-b0ff-964702240fea</ID>
          <Name>Bain Marie Pressure</Name>
          <UserControl>false</UserControl>
          <Width>180</Width>
          <X>600</X>
          <Y>310</Y>
          <PortID>c7bd553e-3a0b-4d9b-8eba-78b974fe5663</PortID>
        </Element>
        </Elements>
      <Name>Workspace 1</Name>
    </Workspace>
  </Workspaces>
</Configuration>
 
I guess we didn’t think or intend configurations to be used this way, but it makes sense! We’ll queue it - I don’t think it’s that tricky.

As far as hardware addressing... as I mentioned, we’ll look at, but it requires a different communication protocol.
 
Last edited:
Hi. Not sure what you are saying here... is this a request? The subroutine function was added in v1.1, so this exists as you have written it. You cannot call a section in a different script - variables like your "CountX" are local to the script and will not cross scripts. If you want to run a different script, you can use the 'start' command to do it (and use a Global to cross data back and forth).

Just wanted to make sure it was correct. I read the release notes and not much there.

I rewrote a test script and it did what I thought.

new value CountX
CountX = 0
new string "Return Text"
//write some code
call "add Countx"
print "Return Text"
call "add Countx"
print "Return Text"
call "add Countx"
print "Return Text"
call "add Countx"
print "Return Text"
stop "Call Test"
[add Countx]
CountX += 1
"Return Text"= "Return "
"Return Text" += CountX
return


It printed
Return 1
Return 2
Return 3
Return 4
 
Not to jump on the feature creep bandwagon, but I have noticed one thing that seems like it would be relatively simple and helpful for people building work spaces.

In the appearance tab for an element, it would be very useful to have the width/height as a text entry. I've been making some recipe controls and making lots of boxes that all need to be the line up correctly. Being able to just type that the width of them was 100 (or whatever) would be handy rather than trying to drag the mouse to just the right spot.

I do realize I could do this by editing the XML file.

If this is actually in there and I'm just too blind to see it, I apologize.
 
First... appreciate the feedback! Ideas to make it better are truly a gift.

Funny, we originally had the X, Y, width, and height in the element properties, then took them out in favor of the grid. We did that to be more touch friendly.

Just so I’m clear, do you know you can set the “snap to” grid in the main settings?

We could easily add them back. Would just want to keep the UI not to cumbersome, so would need to make it clean.
 
When I first set it up, I had set the grid to be pretty fine and had forgotten about it. I had it set at 5x5 in a 1920x1080 screen. If I change it up to 20 or 30 it made it much more reasonable. I think that is plenty sufficient. Thanks!
 
OK, rather than go down a rabbit hole, i figured that for time
"SomeTimeValue" += 00:00:00:01 //adds a second
"SomeTimeValue" += 1 //adds a day

What format for DateTime Values addition and subtraction? I have tried many with no success. I can set a Value for a datetime with
mm.dd.yyyy.HH:MM:SS but that format does not work in math.
 
Has anyone had an issue with an analog input on a MEGA reading 5v even with nothing connected? I know that the voltage can float with nothing connected, but when I put a meter on the input pin and ground with nothing connected, I read 5v. On other analog input pins I read a floating voltage (.01-.3v usually). When I power up a 0-5v pressure sensor it reads correctly at the sensor (.006v at atmosphere), but connected to the board it reads 4.3-4.5v. I'm suspecting I have a bad pin(s) on the MEGA, but wanted a sanity check.
 
Last edited:
The pin is very high impedance when it is in its default state, so reading the input with nothing connected or measuring its voltage with a meter on it won’t have much utility. The open pin will read differently just by touching it and/or local EMI.

Remember that AREF needs be connected to 5V or whatever voltage you want to consider max.
 
Yep, I had all that in consideration... turns out it is the Ethernet shield causing the issue. Its a seeedstudio W5500 board. Seems that SCL and SDA are directly shorted to A4 and A5, exactly the pins where I was having the issue. I suppose my options are to move my inputs to a different pin or clip the pins from the Ethernet shield to the MEGA. Any thoughts on clipping those pins?
 
That is odd. They should be pass-through as neither I2C nor analog outputs are used by the shield.

You can cut them, or try bending them slightly so they hug the header side rather than enter the header. Not classy, but won’t burn a bridge either.
 
Also found this which seems someone else had a similar issue... I'm wondering if its a cross compatibility thing gone wrong between the UNO and MEGA. I'll try flexing the pins out of the way and see if it'll seat that way.
 
To follow back up on this, bending the A4 and A5 pins out of the way slightly solved the issue. I do see the traces, but I had already seated the board.
 
I stumbled on that, too. I think he means that he bent the pins slightly and it solved the problem, not that the problem was slightly solved.

Let's eat mom!
 
Ha, sorry... grammer and punctuation was never my strength, and I can see how that could be taken either way. I meant that my issue was solved by bending the pins slightly as to not seat them.
 
I don't think so. I could be wrong, but I thought the point of the alarm/threshold values in the timers was so that you didn't have to use a script to make them do something.
 
What I thought. Related to using Scripts to reset an Element for a different brew. For example, a Bitter Hop Timer for 90 minutes vs 60 minutes. Would be nice if you could so as to create a Script for different Brews with its own Timers, Alarms and Temperatures. I know it can be done with Scripts as before 1.1x
 
What I thought. Related to using Scripts to reset an Element for a different brew. For example, a Bitter Hop Timer for 90 minutes vs 60 minutes. Would be nice if you could so as to create a Script for different Brews with its own Timers, Alarms and Temperatures. I know it can be done with Scripts as before 1.1x

Why not just leave the threshold at zero, then change the timer value with the script?
 
Why not just leave the threshold at zero, then change the timer value with the script?
You could do it with regular scripts and different timers quite a few different ways. It would just be nice to be able to change it where it is most easy and without a lot of script or thought. I think you added the Alarm on the Timer to make it more user friendly and it is. If we only brewed the same beer all the time, it would not be an issue at all. It is just that you created the "easy way" but only able to change manually.

I was rethinking about how to set up "configurations" for different brews and had come up with an idea to use scripts to reset all of the Times, Thresholds and Temperatures.

I will be using the pre v 1.1 ver to set Timers and use wait statements with a variable. Since you cannot set a script variable out side of the same script, I will use the new Global that can be set from any script.
 
Is there a v44 firmware package available for NodeMCU/8266 boards? Just went to flash one and realized there wasn't one in the download.
 
Hi BC users,

I received a couple of questions about date/time manipulation, so wanted to post up a sample that may shed some light. In this "Test" script example, we define a date/time variable named 'trigger', assign it to a date/time, then print it (to the Output tab). We then define a time variable 'change', and make it one hour. We then define another date/time, and add the 'change' time variable to it, then print it. Finally, we compare the two date/time variables and generate a print out as a result (will always resolve to "Yes" here).

If you wanted to do a comparison to the current time, use the intrinsic 'now' variable (for example: trigger = now). Also, if you wanted to add days rather than hours, you can include days in the time variable (for example: change = 1:00:00:00).

Hopefully this sheds some light. Please let us know if you have any questions, issues, or concerns!

Code:
new datetime trigger
trigger = "04-30-2019 10:00:00 PM"
print trigger

new time change
change = 1:00:00
new datetime future
future = trigger + change
print future

if future > trigger
print "Yes"
else
print "Nope"
endif

stop "Test"
 
Hi BC users,

I received a couple of questions about date/time manipulation, so wanted to post up a sample that may shed some light. In this "Test" script example, we define a date/time variable named 'trigger', assign it to a date/time, then print it (to the Output tab). We then define a time variable 'change', and make it one hour. We then define another date/time, and add the 'change' time variable to it, then print it. Finally, we compare the two date/time variables and generate a print out as a result (will always resolve to "Yes" here).

If you wanted to do a comparison to the current time, use the intrinsic 'now' variable (for example: trigger = now). Also, if you wanted to add days rather than hours, you can include days in the time variable (for example: change = 1:00:00:00).

Hopefully this sheds some light. Please let us know if you have any questions, issues, or concerns!

Code:
new datetime trigger
trigger = "04-30-2019 10:00:00 PM"
print trigger

new time change
change = 1:00:00
new datetime future
future = trigger + change
print future

if future > trigger
print "Yes"
else
print "Nope"
endif

stop "Test"

Thanks for the write up. Here is where I was getting hung up.

It looks like the following are valid:

future = trigger + change (datetime = datetime + time)
future = trigger + 1:00:00:00 (datetime = datetime + <time constant>)
trigger += change (datetime += time)

But this is not valid:

trigger += 1:00:00:00 (datetime += <time constant>)


Error.PNG


An easy workaround is to declare some time variables and use them as constants, similar to #defines in programming.

Capture.PNG
 

Latest posts

Back
Top