brewby 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/.gitignore +17 -0
 - data/Gemfile +3 -0
 - data/LICENSE +22 -0
 - data/README.md +112 -0
 - data/Rakefile +6 -0
 - data/brewby.gemspec +20 -0
 - data/examples/basic_control.rb +24 -0
 - data/examples/brewby_recipe.rb +35 -0
 - data/examples/config.json +21 -0
 - data/examples/recipe_loader.rb +28 -0
 - data/lib/brewby.rb +6 -0
 - data/lib/brewby/application.rb +88 -0
 - data/lib/brewby/heating_element.rb +61 -0
 - data/lib/brewby/inputs.rb +15 -0
 - data/lib/brewby/inputs/ds18b20.rb +51 -0
 - data/lib/brewby/inputs/test.rb +14 -0
 - data/lib/brewby/outputs.rb +15 -0
 - data/lib/brewby/outputs/gpio.rb +40 -0
 - data/lib/brewby/outputs/test.rb +23 -0
 - data/lib/brewby/step_loader.rb +27 -0
 - data/lib/brewby/steps.rb +8 -0
 - data/lib/brewby/steps/dsl/step.rb +48 -0
 - data/lib/brewby/steps/temp_control.rb +111 -0
 - data/lib/brewby/temp_sensor.rb +13 -0
 - data/lib/brewby/timed.rb +50 -0
 - data/lib/brewby/version.rb +3 -0
 - data/spec/application_spec.rb +49 -0
 - data/spec/heating_element_spec.rb +44 -0
 - data/spec/inputs/ds18b20_spec.rb +39 -0
 - data/spec/inputs_spec.rb +8 -0
 - data/spec/outputs/gpio_spec.rb +65 -0
 - data/spec/outputs_spec.rb +8 -0
 - data/spec/spec_helper.rb +6 -0
 - data/spec/step_loader_spec.rb +18 -0
 - data/spec/steps/dsl/step_spec.rb +61 -0
 - data/spec/steps/temp_control_spec.rb +187 -0
 - data/spec/support/sample_recipe.rb +32 -0
 - data/spec/support/virtual_view.rb +31 -0
 - data/spec/timed_spec.rb +110 -0
 - metadata +151 -0
 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Inputs
         
     | 
| 
      
 3 
     | 
    
         
            +
                class DS18B20
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :name, :hardware_id, :device_path
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize options = {}
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @name = options[:name]
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @device_path = options[:device_path] || "/sys/bus/w1/devices"
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @hardware_id = options[:hardware_id] || find_hardware_id
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def find_hardware_id
         
     | 
| 
      
 12 
     | 
    
         
            +
                    w1_devices[0].gsub("#{device_path}/",'')
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def w1_devices
         
     | 
| 
      
 16 
     | 
    
         
            +
                    Dir["#{device_path}/28*"]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def read
         
     | 
| 
      
 20 
     | 
    
         
            +
                    raw = read_raw
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    if tempC = parse(raw)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      tempF = to_fahrenheit tempC
         
     | 
| 
      
 24 
     | 
    
         
            +
                    else
         
     | 
| 
      
 25 
     | 
    
         
            +
                      tempC
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def parse raw_data
         
     | 
| 
      
 30 
     | 
    
         
            +
                    if temp_data = raw_data.match(/t=([0-9]+)/)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      temp_data[1].to_f / 1000
         
     | 
| 
      
 32 
     | 
    
         
            +
                    else
         
     | 
| 
      
 33 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def to_fahrenheit temp
         
     | 
| 
      
 38 
     | 
    
         
            +
                    ((temp * 1.8) + 32).round(3)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  def read_raw
         
     | 
| 
      
 42 
     | 
    
         
            +
                    File.read device_file
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def device_file
         
     | 
| 
      
 46 
     | 
    
         
            +
                    "/sys/bus/w1/devices/#{@hardware_id}/w1_slave"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Outputs
         
     | 
| 
      
 3 
     | 
    
         
            +
                class GPIO
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :gpio_path, :pin
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize options = {}
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @pin = options[:pin]
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @gpio_path = options[:gpio_path] || '/sys/class/gpio'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    initialize_gpio_pin
         
     | 
| 
      
 10 
     | 
    
         
            +
                    initialize_gpio_direction
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def initialize_gpio_pin
         
     | 
| 
      
 14 
     | 
    
         
            +
                    unless File.exists? File.join(gpio_path, "gpio#{pin}", "value")
         
     | 
| 
      
 15 
     | 
    
         
            +
                      File.write File.join(gpio_path, "export"), pin
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def initialize_gpio_direction
         
     | 
| 
      
 20 
     | 
    
         
            +
                    File.write File.join(gpio_path, "gpio#{pin}", "direction"), 'out'
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def on
         
     | 
| 
      
 24 
     | 
    
         
            +
                    write(1)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def off
         
     | 
| 
      
 28 
     | 
    
         
            +
                    write(0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def on?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    '1' == File.read(File.join(gpio_path, "gpio#{pin}", "value"))
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def write value
         
     | 
| 
      
 36 
     | 
    
         
            +
                    File.write File.join(gpio_path, "gpio#{pin}", "value"), value
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Outputs
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Test
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :name
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def initialize options = {}
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @on = false
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @name = options[:name]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def on
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @on = true
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def off
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @on = false
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def on?
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @on
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              class StepLoader
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize application
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @application = application
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def load_file file
         
     | 
| 
      
 8 
     | 
    
         
            +
                  instance_eval File.read(file), file
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                def recipe name, &block
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @application.name = name
         
     | 
| 
      
 13 
     | 
    
         
            +
                  yield self
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def step name, &block
         
     | 
| 
      
 17 
     | 
    
         
            +
                  step = generate_step name, &block
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @application.steps.push step
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def generate_step name, &block
         
     | 
| 
      
 22 
     | 
    
         
            +
                  step_generator = Brewby::Steps::DSL::Step.new name, @application
         
     | 
| 
      
 23 
     | 
    
         
            +
                  step_generator.instance_eval &block
         
     | 
| 
      
 24 
     | 
    
         
            +
                  step_generator.create!
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/brewby/steps.rb
    ADDED
    
    
| 
         @@ -0,0 +1,48 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Steps
         
     | 
| 
      
 3 
     | 
    
         
            +
                module DSL
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class Step
         
     | 
| 
      
 5 
     | 
    
         
            +
                    attr_reader :step_class, :options
         
     | 
| 
      
 6 
     | 
    
         
            +
                    def initialize name, application
         
     | 
| 
      
 7 
     | 
    
         
            +
                      @application = application
         
     | 
| 
      
 8 
     | 
    
         
            +
                      @options = {}
         
     | 
| 
      
 9 
     | 
    
         
            +
                      @options[:name] = name
         
     | 
| 
      
 10 
     | 
    
         
            +
                    end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    def type symbol, options = {}
         
     | 
| 
      
 13 
     | 
    
         
            +
                      @step_class = case symbol
         
     | 
| 
      
 14 
     | 
    
         
            +
                      when :temp_control
         
     | 
| 
      
 15 
     | 
    
         
            +
                        Brewby::Steps::TempControl
         
     | 
| 
      
 16 
     | 
    
         
            +
                      end
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @options.merge!(options)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def mode m
         
     | 
| 
      
 21 
     | 
    
         
            +
                      @options[:mode] = m
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    def target t
         
     | 
| 
      
 25 
     | 
    
         
            +
                      @options[:target] = t
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    def hold_duration d
         
     | 
| 
      
 29 
     | 
    
         
            +
                      @options[:duration] = d
         
     | 
| 
      
 30 
     | 
    
         
            +
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    def input i
         
     | 
| 
      
 33 
     | 
    
         
            +
                      @options[:input] = i
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    def output o
         
     | 
| 
      
 37 
     | 
    
         
            +
                      @options[:output] = o
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def create!
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @options[:input] = @application.inputs.find { |i| i.name.to_sym == @options[:input] }
         
     | 
| 
      
 42 
     | 
    
         
            +
                      @options[:output] = @application.outputs.find { |o| o.name.to_sym == @options[:output] }
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @step_class.new @options
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,111 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'brewby/temp_sensor'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'brewby/heating_element'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'brewby/timed'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'temper'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Steps
         
     | 
| 
      
 8 
     | 
    
         
            +
                class TempControl
         
     | 
| 
      
 9 
     | 
    
         
            +
                  attr_reader :input, :output, :pid, :target, :duration, :mode, :last_reading, :threshold_reached, :name
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  include Brewby::Timed
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def initialize options = {}
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @mode = options[:mode] || :manual
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @output = 0
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @pulse_range = options[:pulse_range] || 5000
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    @input = options[:input]
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @output = options[:output]
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @threshold_reached = false
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @name = options[:name]
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @last_reading = 0.0
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    if automatic_control?
         
     | 
| 
      
 25 
     | 
    
         
            +
                      configure_automatic_control options
         
     | 
| 
      
 26 
     | 
    
         
            +
                    else
         
     | 
| 
      
 27 
     | 
    
         
            +
                      set_power_level options[:power_level] || 1.0
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def configure_automatic_control options
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @target = options[:target]
         
     | 
| 
      
 33 
     | 
    
         
            +
                    @duration = options[:duration] || 1
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    @pid = Temper::PID.new maximum: @pulse_range
         
     | 
| 
      
 36 
     | 
    
         
            +
                    @pid.tune 44, 165, 4
         
     | 
| 
      
 37 
     | 
    
         
            +
                    @pid.setpoint = @target
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def manual_control?
         
     | 
| 
      
 41 
     | 
    
         
            +
                    !automatic_control?
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  def automatic_control?
         
     | 
| 
      
 45 
     | 
    
         
            +
                    @mode == :auto
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  def read_input
         
     | 
| 
      
 49 
     | 
    
         
            +
                    reading = input.read
         
     | 
| 
      
 50 
     | 
    
         
            +
                    @last_reading = reading if reading
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  def set_power_level level
         
     | 
| 
      
 54 
     | 
    
         
            +
                    set_pulse_width (level * @pulse_range).to_i
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def calculate_power_level
         
     | 
| 
      
 58 
     | 
    
         
            +
                    if read_input
         
     | 
| 
      
 59 
     | 
    
         
            +
                      set_pulse_width pid.control @last_reading
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  def set_pulse_width width
         
     | 
| 
      
 64 
     | 
    
         
            +
                    if width
         
     | 
| 
      
 65 
     | 
    
         
            +
                      output.pulse_width = width
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  def power_level
         
     | 
| 
      
 70 
     | 
    
         
            +
                    output.pulse_width / @pulse_range.to_f
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def step_iteration
         
     | 
| 
      
 74 
     | 
    
         
            +
                    if automatic_control?
         
     | 
| 
      
 75 
     | 
    
         
            +
                      calculate_power_level
         
     | 
| 
      
 76 
     | 
    
         
            +
                      output.pulse
         
     | 
| 
      
 77 
     | 
    
         
            +
                      check_temp_threshold unless threshold_reached
         
     | 
| 
      
 78 
     | 
    
         
            +
                      check_step_completion
         
     | 
| 
      
 79 
     | 
    
         
            +
                    else
         
     | 
| 
      
 80 
     | 
    
         
            +
                      read_input if input
         
     | 
| 
      
 81 
     | 
    
         
            +
                      output.pulse
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                  def check_step_completion
         
     | 
| 
      
 86 
     | 
    
         
            +
                    if threshold_reached && Time.now.to_i > @step_finishes_at
         
     | 
| 
      
 87 
     | 
    
         
            +
                      stop_timer
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  def time_remaining
         
     | 
| 
      
 92 
     | 
    
         
            +
                    if @step_finishes_at
         
     | 
| 
      
 93 
     | 
    
         
            +
                      @step_finishes_at - Time.now.to_i
         
     | 
| 
      
 94 
     | 
    
         
            +
                    else
         
     | 
| 
      
 95 
     | 
    
         
            +
                      duration_in_seconds
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  def check_temp_threshold
         
     | 
| 
      
 100 
     | 
    
         
            +
                    if last_reading >= target
         
     | 
| 
      
 101 
     | 
    
         
            +
                      @threshold_reached = true
         
     | 
| 
      
 102 
     | 
    
         
            +
                      @step_finishes_at = Time.now.to_i + duration_in_seconds
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  def duration_in_seconds
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @duration * 60
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
              end
         
     | 
| 
      
 111 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/brewby/timed.rb
    ADDED
    
    | 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Brewby
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Timed
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :start_time, :end_time
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def started?
         
     | 
| 
      
 6 
     | 
    
         
            +
                  !@start_time.nil?
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                def ended?
         
     | 
| 
      
 10 
     | 
    
         
            +
                  !@end_time.nil?
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def in_progress?
         
     | 
| 
      
 14 
     | 
    
         
            +
                  started? && !ended?
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def start_timer
         
     | 
| 
      
 18 
     | 
    
         
            +
                  @start_time = Time.now
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def stop_timer
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @end_time = Time.now
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def elapsed
         
     | 
| 
      
 26 
     | 
    
         
            +
                  started? ? (@end_time || Time.now) - @start_time :  0
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def timer_for seconds
         
     | 
| 
      
 30 
     | 
    
         
            +
                  time = seconds > 0 ? time_from_seconds(seconds) : [0, 0, 0]
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  "%0.2d:%0.2d:%0.2d" % time
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                def countdown_for seconds
         
     | 
| 
      
 36 
     | 
    
         
            +
                  sign = seconds > 0 ? "" : "+"
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  sign + timer_for(seconds.abs)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def time_from_seconds seconds
         
     | 
| 
      
 42 
     | 
    
         
            +
                  hours = seconds / 3600
         
     | 
| 
      
 43 
     | 
    
         
            +
                  seconds -= (hours * 3600)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  minutes = seconds / 60
         
     | 
| 
      
 45 
     | 
    
         
            +
                  seconds -= minutes * 60
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  [hours, minutes, seconds]
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,49 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Brewby::Application do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before do
         
     | 
| 
      
 5 
     | 
    
         
            +
                @output = {
         
     | 
| 
      
 6 
     | 
    
         
            +
                  pin: 1,
         
     | 
| 
      
 7 
     | 
    
         
            +
                  pulse_range: 5000
         
     | 
| 
      
 8 
     | 
    
         
            +
                }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                Brewby::Application.any_instance.stub(:configure_view)
         
     | 
| 
      
 11 
     | 
    
         
            +
                @application = Brewby::Application.new adapter: :test, outputs: [@output], inputs: [{}, {hardware_id: '28-ba1c9d2e48'}]
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
              
         
     | 
| 
      
 14 
     | 
    
         
            +
              it 'should have one output' do
         
     | 
| 
      
 15 
     | 
    
         
            +
                @application.outputs.size.should == 1
         
     | 
| 
      
 16 
     | 
    
         
            +
                @application.outputs.first.should be_instance_of Brewby::HeatingElement
         
     | 
| 
      
 17 
     | 
    
         
            +
                @application.outputs.first.adapter.should be_instance_of Brewby::Outputs::Test
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              it 'should have two inputs' do
         
     | 
| 
      
 21 
     | 
    
         
            +
                @application.inputs.size.should == 2
         
     | 
| 
      
 22 
     | 
    
         
            +
                @application.inputs.each do |input|
         
     | 
| 
      
 23 
     | 
    
         
            +
                  input.should be_instance_of Brewby::Inputs::Test
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
              end
         
     | 
| 
      
 26 
     | 
    
         
            +
              
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              context 'adding steps' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                before do
         
     | 
| 
      
 30 
     | 
    
         
            +
                  @application.add_step :temp_control, mode: :auto, mode: :auto, target: 155.0, duration: 15
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @step = @application.steps.first
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                it 'creates a step object with passed configuration options' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @step.should be_instance_of Brewby::Steps::TempControl
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                it 'passes an input and an output to the step' do
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @step.input.should == @application.inputs.first
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @step.output.should == @application.outputs.first
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                it 'allows the step to specify the input/output objects to use' do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @application.add_step :temp_control, mode: :auto, mode: :auto, target: 155.0, duration: 15, input: @application.inputs.last
         
     | 
| 
      
 45 
     | 
    
         
            +
                  @step = @application.steps.last
         
     | 
| 
      
 46 
     | 
    
         
            +
                  @step.input.should == @application.inputs.last
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
            end
         
     |