class PressureSensor(StepBase): volume = Property.Number("volume", configurable=True) sensor = StepProperty.Sensor("Sensor") actor = StepProperty.Actor("Actor") def init(self): if self.actor is not None: self.actor_on(int(self.actor)) @cbpi.action("Turn Actor OFF") def start(self): if self.actor is not None: self.actor_off(int(self.actor)) def reset(self): if self.actor is not None: self.actor_off(int(self.actor)) def finish(self): if self.actor is not None: self.actor_off(int(self.actor)) def execute(self): for key, value in cbpi.cache.get("sensors").iteritems(): if key == int(self.sensor): sensorValue = value.instance.last_value if float(sensorValue) >= float(self.volume): self.next()
class Chill_CG(StepBase): kettle = StepProperty.Kettle("Kettle", description="Kettle in which the chilling takes place") chiller = StepProperty.Actor("Chiller", description="Actor that controls the Chiller") chillerPump = StepProperty.Actor("chillerPump", description="Actor that controls the chillerPump") chillerTemp = StepProperty.Sensor("Chiller Temp", description="Sensor that shows the chiller temperature") cutoutvariance = Property.Number("Variance between kettle and chiller for end", configurable=True, default_value=0.3, description="The step will end when the kettle temp falls to within this much of the chiller temp.") def init(self): self.actor_on(int(self.chillerPump)) self.actor_on(int(self.chiller)) self.set_target_temp(0, self.kettle) def start(self): pass def reset(self): pass def finish(self): self.actor_off(int(self.chillerPump)) self.actor_off(int(self.chiller)) def execute(self): if self.get_kettle_temp(self.kettle) <= (self.get_sensor_value(self.chillerTemp)+float(self.cutoutvariance)): self.notify("Chill Stage Complete", "Kettle reached: " + str(self.get_kettle_temp(self.kettle)), type="success", timeout=None) self.actor_off(int(self.chiller)) self.actor_off(int(self.chillerPump)) self.next()
class HeartsStep(StepBase, BaseColletingStep): temperatureSensor = StepProperty.Sensor( "Датчик температуры", description="Датчик температуры в кубе") initialCollecting = Property.Number("Стартовая скорость отбора, мл/ч", configurable=True, default_value=1000) endTemp = Property.Number("Температура завершения отбора", configurable=True, default_value=93) collectingSpeed = 0.0 temperature = 0 def finish(self): self.actor_off(int(self.collectingActor)) self.notify("", "Отбор тела завершен", type="success", timeout=2000) def execute(self): self.updateAndCheckTemperature() self.recountCollecting() self.notifySensor() self.updateMaxCollectingSpeed() self.calculateActorPower() self.manageActor() def recountCollecting(self): self.collectingSpeed = int( self.initialCollecting) * (6.04 - 0.06 * float(self.temperature)) def updateAndCheckTemperature(self): self.temperature = float( self.get_sensor_value(int(self.temperatureSensor))) if self.temperature >= int(self.endTemp): next(self)
class FlowSensorReset(StepBase): sensor_prop = StepProperty.Sensor("Sensor") #------------------------------------------------------------------------------- def init(self): self.sensor = cbpi.cache.get("sensors")[int(self.sensor_prop)].instance self.sensor.reset_volume() self.next()
class BaseColletingStep(object): collectingActor = StepProperty.Actor( "Устройство отбора", description="Исполнительное устройство отбора") collectingSensor = StepProperty.Sensor( "Индикатор отбора", description="Индикатор скорости отбора") isPaused = False power = 0 maxSpeed = 0 @cbpi.action("Начать отбор") def start(self): if self.isPaused: self.time = datetime.utcnow() self.notify("", "Отбор продолжен", type="success", timeout=2000) self.isPaused = False @cbpi.action("Остановить отбор") def stop(self): if not self.isPaused: self.notify("", "Отбор приостановлен", type="success", timeout=2000) self.isPaused = True def notifySensor(self): try: sensor = self.api.cache.get("sensors").get( int(self.collectingSensor)).instance sensor.collecting = int(self.collectingSpeed) except: pass def updateMaxCollectingSpeed(self): try: actor = self.api.cache.get("actors").get(int( self.collectingActor)).instance self.maxSpeed = actor.get_max_speed() except: self.maxSpeed = 0 def manageActor(self): actorId = int(self.collectingActor) self.actor_power(power=self.power, id=actorId) if self.isPaused: self.actor_off(actorId) else: self.actor_on(power=self.power, id=actorId) def calculateActorPower(self): if self.maxSpeed > 0: self.power = min( round(float(self.collectingSpeed) / self.maxSpeed * 100), 100)
class StartStopStep(StepBase, BaseColletingStep): temperatureSensor = StepProperty.Sensor( "Датчик температуры", description="Датчик температуры в царге") initialCollecting = Property.Number("Стартовая скорость отбора, мл/ч", configurable=True, default_value=1000) deltaTemp = Property.Number("Разрешенный залет температуры, °C", configurable=True, default_value=0.3) decrement = Property.Number("Уменьшение отбора при залете температуры, %", configurable=True, default_value=10) endTemp = Property.Number("Температура завершения отбора", configurable=True, default_value=93) initialTemp = None currentCollecting = None collectingSpeed = 0.0 temperature = 0 stopped = False def finish(self): self.actor_off(int(self.collectingActor)) self.notify("", "Отбор тела завершен", type="success", timeout=2000) def execute(self): self.updateAndCheckTemperature() self.recountCollecting() self.notifySensor() self.updateMaxCollectingSpeed() self.calculateActorPower() self.manageActor() def recountCollecting(self): if not self.currentCollecting: self.currentCollecting = int(initialCollecting) if not self.initialTemp: self.initialTemp = float(self.temperature) excess = float(self.temperature) - self.initialTemp > float( self.deltaTemp) if excess and not self.stopped: self.currentCollecting = self.currentCollecting * ( 100 - int(decrement)) / 100 self.stopped = excess self.collectingSpeed = 0 if self.stopped else self.currentCollecting def updateAndCheckTemperature(self): self.temperature = float( self.get_sensor_value(int(self.temperatureSensor))) if self.temperature >= int(self.endTemp): next(self)
class KettleVolumeStep(StepBase): ''' Just put the decorator @cbpi.step on top of a method. The class name must be unique in the system ''' # Properties temp = Property.Number("Temperature", configurable=True) kettle = StepProperty.Kettle("Kettle") timer = Property.Number("Timer in Minutes", configurable=True) sensor = StepProperty.Sensor("Sensor") volume = Property.Number("Volume", configurable=True) def init(self): ''' Initialize Step. This method is called once at the beginning of the step :return: ''' # set target tep #self.set_target_temp(self.temp, self.kettle) def finish(self): self.set_target_temp(0, self.kettle) def execute(self): ''' This method is execute in an interval :return: ''' for key, value in cbpi.cache.get("sensors").iteritems(): if key == int(self.sensor): sensorValue = value.instance.last_value # Check if timer finished and go to next step if float(sensorValue) <= float(self.volume): self.set_target_temp(self.temp, self.kettle) kettle_state = cbpi.cache.get("kettle")[int(self.kettle)].state if kettle_state is True: Kettle2View().toggle(int(self.kettle)) self.notify("Kettle Update", "Auto is off. Timer started.", timeout=None) if self.is_timer_finished() is None: self.start_timer(int(self.timer) * 60) if self.is_timer_finished() == True: self.notify("Mash-in Complete!", "Starting the next step.", timeout=None) self.next()
class Flowmeter(StepBase): sensor = StepProperty.Sensor("Sensor") actorA = StepProperty.Actor("Actor") volume = Property.Number("Volume", configurable=True) resetFlowmeter = Property.Number( "Reset flowmeter when done. 1 = Yes 0 = No", configurable=True, default_value="1") def init(self): if int(self.actorA) is not None: self.actor_on(int(self.actorA)) @cbpi.action("Turn Actor OFF") def start(self): if self.actorA is not None: self.actor_off(int(self.actorA)) def reset(self): if self.actorA is not None: self.actor_off(int(self.actorA)) def finish(self): if self.actorA is not None: self.actor_off(int(self.actorA)) if self.resetFlowmeter == "1": for key, value in list(cbpi.cache.get("sensors").items()): if key == int(self.sensor): value.instance.reset() def execute(self): for key, value in list(cbpi.cache.get("sensors").items()): if key == int(self.sensor): sensorValue = value.instance.getValue() if float(sensorValue) >= float(self.volume): next(self)
class KRimsMashStep(StepBase): ''' Just put the decorator @cbpi.step on top of a method ''' # Properties temp = Property.Number("Kettle Temperature", configurable=True, description="Target Temperature of the Kettle") mash_temp = Property.Number( "Mash Temperature", configurable=True, description="Target Temperature of the Mash Step") kettle = StepProperty.Kettle( "Kettle", description="Kettle in which the mashing takes place") timer = Property.Number( "Timer in Minutes", configurable=True, description="Timer is started when the target temperature is reached") sensor = StepProperty.Sensor("Sensor", description="Selectable secondary sensor") pump = StepProperty.Actor("Pump, etc.") mode = Property.Select("Mode", ["Timer", "User input"], "Selects how the step operates") def init(self): ''' Initialize Step. This method is called once at the beginning of the step :return: ''' # set target tep self.set_target_temp(self.temp, self.kettle) self.actor_on(int(self.pump)) @cbpi.action("Start Timer Now") def start(self): ''' Custom Action which can be execute form the brewing dashboard. All method with decorator @cbpi.action("YOUR CUSTOM NAME") will be available in the user interface :return: ''' if self.is_timer_finished() is None: self.start_timer(int(self.timer) * 60) def reset(self): self.stop_timer() self.set_target_temp(self.temp, self.kettle) def finish(self): self.set_target_temp(0, self.kettle) self.actor_off(int(self.pump)) def execute(self): ''' This method is execute in an interval :return: ''' # Check if Target Temp is reached if self.mode == "Timer": if cbpi.get_sensor_value(int(self.sensor)) >= float( self.mash_temp): if self.is_timer_finished() is None: self.start_timer(int(self.timer) * 60) # Check if timer finished and go to next step if self.is_timer_finished() == True: self.notify("Mash Step Completed!", "Starting the next step", timeout=None) self.next() if self.mode == "User input": if cbpi.get_sensor_value(int(self.sensor)) >= float( self.mash_temp): self.notify("Mash Temp reached!", "User input needed to proceed to next step", timeout=None) self.mode = "All done. Wait for user"
class SpargeStep(StepBase): ''' Just put the decorator @cbpi.step on top of a method. The class name must be unique in the system ''' # Properties kettle1 = StepProperty.Kettle("Boil Kettle") kettle2 = StepProperty.Kettle("HLT Kettle") actor1 = StepProperty.Actor("Wort Pump") actor2 = StepProperty.Actor("Water Pump") sensor1 = StepProperty.Sensor("BK Volume Sensor") sensor2 = StepProperty.Sensor("HLT Volume Sensor") volume1 = Property.Number("BK Volume Target", configurable=True) volume2 = Property.Number("HLT Volume Min", configurable=True) volumeStart = Property.Number("HLT Volume Start", configurable=True) volumeDiff = Property.Number("Volume Difference", configurable=True) timer = Property.Number("Timer in Minutes", configurable=True) temp = Property.Number("BK Temp", configurable=True) volumeBoil = Property.Number("BK Boil Volume", configurable=True) volumeState1 = 0 volumeState2 = 0 def init(self): ''' Initialize Step. This method is called once at the beginning of the step :return: ''' # set target tep #self.set_target_temp(self.temp, self.kettle) def finish(self): self.set_target_temp(0, self.kettle2) def execute(self): ''' This method is execute in an interval :return: ''' sensorValue1 = cbpi.get_sensor_value(int(self.sensor1)) sensorValue2 = cbpi.get_sensor_value(int(self.sensor2)) volumeChange1 = float(sensorValue1) - float(self.volumeState1) volumeChange2 = float(self.volumeState2) - float(sensorValue2) kettle1_state = cbpi.cache.get("kettle")[int(self.kettle1)].state kettle2_state = cbpi.cache.get("kettle")[int(self.kettle2)].state for key, value in cbpi.cache["actors"].iteritems(): if key == int(self.actor1): actorState1 = value.state if key == int(self.actor2): actorState2 = value.state if float(sensorValue1) >= float( self.volumeBoil) and kettle1_state is False: Kettle2View().toggle(int(self.kettle1)) self.notify("Kettle Update", "Kettle 1 Auto is on.", timeout=None) self.set_target_temp(self.temp, self.kettle1) # Check if kettle2 volume limit reached if float(sensorValue2) <= float(self.volume2): if kettle2_state is True: self.set_target_temp(0, self.kettle2) Kettle2View().toggle(int(self.kettle2)) self.notify("Kettle Update", "Kettle 2 Auto is off.", timeout=None) if self.is_timer_finished() is None: self.start_timer(int(self.timer) * 60) # Make sure kettle1 hasn't reached target if float(sensorValue1) < float(self.volume1): self.actor_on(int(self.actor1)) if self.is_timer_finished() == True: self.actor_off(int(self.actor2)) else: self.actor_on(int(self.actor2)) else: if self.volumeState1 > 0: totalDiff = float(volumeChange2) - float(volumeChange1) if totalDiff > 0: if abs(totalDiff) > float(self.volumeDiff): self.actor_off(int(self.actor2)) self.actor_on(int(self.actor1)) else: self.actor_on(int(self.actor2)) else: if abs(totalDiff) > float(self.volumeDiff): self.actor_off(int(self.actor1)) self.actor_on(int(self.actor2)) else: self.actor_on(int(self.actor1)) else: if volumeChange >= 10: self.volumeState2 = sensorValue2 self.volumeState1 = sensorValue1 # Check if kettle1 target volume has been reached if float(sensorValue1) >= float(self.volume1): self.set_target_temp(0, self.kettle2) self.stop_timer() self.start_timer(0) self.notify("Sparge Complete!", "Starting the next step.", timeout=None) self.next()
class FlowSensorCalibrate(StepBase): # properties actor_prop = StepProperty.Actor("Actor") sensor_prop = StepProperty.Sensor("Sensor") timer_prop = Property.Number("Timer", configurable=True, default_value=10) threshold_prop = Property.Number( "Flow threshold", configurable=True, default_value=0.1, description="Value at which flow is considered stopped") #------------------------------------------------------------------------------- def init(self): # convert properties to usable attributes self.actor = int(self.actor_prop) self.sensor = cbpi.cache.get("sensors")[int(self.sensor_prop)].instance self.threshold = float(self.threshold_prop) self.flowing = False # reset sensor volume to start calibration self.sensor.reset_volume() # turn on actor self.actor_on(self.actor) # start timer if self.is_timer_finished() is None: self.start_timer(float(self.timer_prop) * 60) #------------------------------------------------------------------------------- def execute(self): sensor_data = self.sensor.read_sensor_data() if (not self.flowing) and (sensor_data['flow'] >= self.threshold): # flow has started cbpi.app.logger.info( "FlowSensor '{}' calibrate flow started".format( self.sensor.name)) self.flowing = True elif (self.flowing) and (sensor_data['flow'] <= self.threshold): # flow has stopped cbpi.app.logger.info( "FlowSensor '{}' calibrate flow stopped".format( self.sensor.name)) self.next() elif self.is_timer_finished() == True: # timer has expired cbpi.app.logger.info( "FlowSensor '{}' calibrate timer expired".format( self.sensor.name)) self.next() #------------------------------------------------------------------------------- def finish(self): # turn off actor self.actor_off(self.actor) # notify complete and total pulses sensor_data = self.sensor.read_sensor_data() self.notify("Flow Sensor Calibration Complete", self.sensor.name, type="success", timeout=None) self.notify("Pulse Count: {}".format(sensor_data['count']), self.sensor.name, type="info", timeout=None) #------------------------------------------------------------------------------- def reset(self): self.actor_off(self.actor)
class FlowSensorTransfer(StepBase): a_sensor_prop = StepProperty.Sensor( "Flow Sensor", description="Sensor that contols this step") b_actor1_prop = StepProperty.Actor( "Actor 1", description="Actor to turn on for the duration of this step") c_actor2_prop = StepProperty.Actor( "Actor 2", description="Actor to turn on for the duration of this step") d_volume_prop = Property.Number( "Target Volume", configurable=True, description="Leave blank to continue until flow stops") e_reset_start_prop = Property.Select("Reset sensor at start?", options=["Yes", "No"]) f_reset_finish_prop = Property.Select("Reset sensor at finish?", options=["Yes", "No"]) g_threshold_prop = Property.Number( "Flow threshold", configurable=True, default_value=0.1, description="Value at which flow is considered stopped") #------------------------------------------------------------------------------- def init(self): # convert properties to usable attributes self.sensor = cbpi.cache.get("sensors")[int( self.a_sensor_prop)].instance self.actors = [self.b_actor1_prop, self.c_actor2_prop] try: self.target_volume = float(self.d_volume_prop) except: self.target_volume = 0.0 self.reset_start = self.e_reset_start_prop == "Yes" self.reset_finish = self.f_reset_finish_prop == "Yes" try: self.threshold = float(self.g_threshold_prop) except: self.threshold = 0.1 self.flowing = False # reset sensor volume if indicated if self.reset_start: self.sensor.reset_volume() # turn on actors self.actors_on() #------------------------------------------------------------------------------- def execute(self): sensor_data = self.sensor.read_sensor_data() if (not self.flowing) and (sensor_data['flow'] >= self.threshold): # flow has started cbpi.app.logger.info( "FlowSensor '{}' transfer flow started".format( self.sensor.name)) self.flowing = True elif (self.flowing) and (sensor_data['flow'] <= self.threshold): # flow has stopped cbpi.app.logger.info( "FlowSensor '{}' transfer flow stopped".format( self.sensor.name)) self.next() elif self.target_volume and (sensor_data['volume'] >= self.target_volume): # target volume reached cbpi.app.logger.info( "FlowSensor '{}' transfer target volume reached".format( self.sensor.name)) self.next() #------------------------------------------------------------------------------- def finish(self): # turn actors off self.actors_off() # notify complete and total volume sensor_data = self.sensor.read_sensor_data() self.notify("{} complete".format(self.name), "Total Volume: {:.2f}{}".format(sensor_data['volume'], self.sensor.volume_units), timeout=None) # reset sensor volume if indicated if self.reset_finish: self.sensor.reset_volume() #------------------------------------------------------------------------------- def reset(self): self.actors_off() #------------------------------------------------------------------------------- def actors_on(self): for actor in self.actors: try: self.actor_on(int(actor)) except: pass def actors_off(self): for actor in self.actors: try: self.actor_off(int(actor)) except: pass