Monday 2 September 2013

The UI is Alive!

I've started working on the UI for the fermentation controller and thanks to Storyboard things are coming together very quickly.  I mentioned Crank Storyboard Suite in my first post and I'm going to go into some detail on how I'm putting together the interfaceand control logic using Storyboard.  As noted in my first post I've been a Crank Software employee since July 2010 and not only is it a really awesome place to work, we produce an incredible tool for designing and deploying UI applications to embedded targets.  A Storyboard deployment consists of two things, the Runtime which is a board specific package of binaries and libraries used to render the Storyboard Project you deploy to the target and the Project, which consists of the exported gapp file and the image assets and scripts.  Storyboard supports a wide variety of CPU/OS/Graphic chipsets.  For the Beaglebone Black I'm running the Linux Codesourcery Armle FBDev runtime, this allows me to run a GUI without having the overhead of X-windows as it renders content directly to the framebuffer on the target.  If my beaglebone image supported the SGX graphics processor and I had the right OpenGLES libraries installed I could also run the OpenGLES_2.0 runtime which would unlock some nifty 3D transition and animation options.  Unfortunately for me the Linux image I'm running doesn't currently support the SGX chipset yet, so I'll be running on FBDev for now.

Storyboard uses a WYSIWYG editor to enable the user to place the controls and graphics by dragging and dropping.  Variable's can be assigned to control data and then updated using either the integrated Lua scripting or by using the greio API provided in the runtime.  The API allows a user to write a native C application that can send data to and receive data from Storyboard, I had originally planned to write a small daemon that would read the 1-wire temperature data and pull up the proper GPIO line to enable the SSR which would switch on the cooling device plugged into it.  After a bit of research I discovered that Rsisto had published a free to use GPIO library for Lua.  Since Storyboard has full support for Lua baked right in, I can simply write all my code as a Lua script, making my application that much simpler as all my code now lives in a single Storyboard project!  I was pretty excited to get started so I whipped up the fastest thing I could, I honestly spent less than 10 minutes putting together the UI you see in the video below, I plan on making it a lot nicer in the coming days, but I wanted to get the bare minimum up to test the GPIO library and to make sure the temperature reporting was also working properly.  Check out the very quick demo below;


It's a little difficult to see in the video but I have a room lamp plugged into the outlet controlled by the SSR, when the GPIO line is pulled High the SSR enables the 110v circuit to complete energizing the plug and anything attached to it.  The idea here is that when we go above a certain set-point we want the fridge that acts as my cooling source to turn on which will drive the temperature in the fermentation chamber down to our set-point and keep it there ( within a couple of tenths of a degree ) so that the wort is fermented at exactly the temperature we want.  I will also be adding a heating element which will be controlled by another SSR which will turn on a heating element of some kind so I can manage my temperature exactly.

And now the Lua code that controls the GPIO and feeds the temperature display on the GUI.

require ("gpio") -- import library
local device_path = '/sys/bus/w1/devices/28-00000449da30/w1_slave'

-- setup the device defaults
local ssr_fired = false
configureOutGPIO(60)
writeGPIO(60,0)

-- timer callback function, read temp every second and update GPIO as required.
function read_temp()
 local f = assert(io.open(device_path, 'r'))
 local t = f:read("*all")
 local temp
 local data_table  = {}
 
 
 f:close()
 for w in string.gmatch(t,"t=*=(%d+)") do
  temp = w
 end
 local report_temp_c = string.format("%.2f",temp / 1000)
 data_table["probeTemp"] = report_temp_c
 gre.set_data(data_table)
 local temp_c = temp/1000
 --print (string.format("Got temp of %s C",temp_c))
 if ( temp_c > 24 ) then
  if ( ssr_fired == false ) then
   local data_table  = {}
   print("Turning on")
   ssr_fired = true
   data_table["Layer1.Cooling_On.grd_hidden"] = 0
   gre.set_data(data_table)
   writeGPIO(60,1)
  end 
 else
  if ( ssr_fired == true) then
   local data_table  = {}
   print("Turning off")
   ssr_fired = false
   writeGPIO(60,0)
   data_table["Layer1.Cooling_On.grd_hidden"] = 1
   gre.set_data(data_table)
  end
 end
 

end
This is a first cut at the logic behind the temperature controller, but all of the magic required to turn on and off the cooling element is already here, I just need to make it a bit smarter. The first thing I'll be adding is some hysteresis so that the system doesn't cycle the mini-fridge on and off constantly as the temperature hovers around the set point. The primary reason for this is that compressors in fridges don't take very well to being cycled on and off frequently. I will be building in a 2 minute delay to prevent burning out the compressor. I also plan on displaying the temperature values in a graph that will update constantly so you can get a quick overview of the fermentation schedule and see if there were any drastic changes due to a heating/cooling system failure. As it stands I've got a nearly functional fermentation controller application and I've spent more time writing this blog entry than I have building the GUI and control logic! I'll be spending the next couple of days polishing the GUI and rounding out the control logic and adding in the graphing of temperature values. After that I'll switch over to building out the Web interface which will allow for the uploading of Fermentation profiles and for controlling and viewing the fermentation from any Internet connected device.