Beispiel #1
0
class TrailingAverageSensor(SensorPassive):
    sensor_prop = Property.Sensor("Sensor", description="Select a sensor to average readings of.")
    count_prop = Property.Number("Count", configurable=True, default_value=12, description="Number of readings to average.")
    decimals_prop = Property.Number("Decimals", configurable=True, default_value=1, description="How many decimals to round the average to.")

    #-------------------------------------------------------------------------------
    def init(self):
        self.values = list()
        self.sensor_id = int(self.sensor_prop)
        self.count = int(self.count_prop)
        self.weight = 1.0/self.count
        self.decimals = int(self.decimals_prop)

    #-------------------------------------------------------------------------------
    def read(self):
        self.values.append(float(cbpi.cache.get("sensors")[int(self.sensor_id)].instance.last_value))
        while len(self.values) > self.count:
            self.values.pop(0)
        numerator = 0.0
        denominator = 0.0
        weight = 1.0
        for value in reversed(self.values):
            numerator += value * weight
            denominator += weight
            weight = weight - self.weight
        self.data_received(round(numerator/denominator, self.decimals))

    #-------------------------------------------------------------------------------
    def get_unit(self):
        return cbpi.cache.get("sensors")[int(self.sensor_id)].instance.get_unit()

    #-------------------------------------------------------------------------------
    def stop(self):
        pass
Beispiel #2
0
class Hysteresis(KettleController):

    # Custom Properties

    on = Property.Number("Offset On", True, 0, description="Offset below target temp when heater should switched on. Should be bigger then Offset Off")
    off = Property.Number("Offset Off", True, 0, description="Offset below target temp when heater should switched off. Should be smaller then Offset Off")

    def stop(self):
        '''
        Invoked when the automatic is stopped.
        Normally you switch off the actors and clean up everything
        :return: None
        '''
        super(KettleController, self).stop()
        self.heater_off()




    def run(self):
        '''
        Each controller is exectuted in its own thread. The run method is the entry point
        :return: 
        '''
        while self.is_running():

            if self.get_temp() < self.get_target_temp() - float(self.on):
                self.heater_on(100)
            elif self.get_temp() >= self.get_target_temp() - float(self.off):
                self.heater_off()
            else:
                self.heater_off()
            self.sleep(1)
Beispiel #3
0
class Hysteresis(FermenterController):

    heater_offset_min = Property.Number("Heater Offset min", True, 0)
    heater_offset_max = Property.Number("Heater Offset max", True, 0)
    cooler_offset_min = Property.Number("Cooler Offset min", True, 0)
    cooler_offset_max = Property.Number("Cooler Offset max", True, 0)

    def stop(self):
        super(FermenterController, self).stop()

        self.heater_off()
        self.cooler_off()

    def run(self):
        while self.is_running():

            target_temp = self.get_target_temp()
            temp = self.get_temp()

            if temp + int(self.heater_offset_min) < target_temp:
                self.heater_on(100)

            if temp + int(self.heater_offset_max) > target_temp:
                self.heater_off()

            if temp > target_temp + int(self.cooler_offset_min):
                self.cooler_on(100)

            if temp < target_temp + int(self.cooler_offset_max):
                self.cooler_off()

            self.sleep(1)
Beispiel #4
0
class PIDPWM(KettleController):

    a_p = Property.Number("P", True, 0)
    b_i = Property.Number("I", True, 0)
    c_d = Property.Number("D", True, 0)
    d_max_out = Property.Number("max. output %", True, 100)

    def run(self):
        sampleTime = 5
        p = float(self.a_p)
        i = float(self.b_i)
        d = float(self.c_d)
        maxout = float(self.d_max_out)
        pid = PIDArduino(sampleTime, p, i, d, 0, maxout)
        self.heater_on(0)

        while self.is_running():
            heat_percent = pid.calc(self.get_temp(), self.get_target_temp())
            print(heat_percent)
            self.actor_power(round(heat_percent))
            self.sleep(sampleTime)

    def stop(self):

        super(KettleController, self).stop()
        self.heater_off()
Beispiel #5
0
class SimpleBoilLogic(KettleController):

    ramp_power = Property.Number("Ramp Up Power %", True, 100)
    boil_power = Property.Number("Boil Power %", True, 70)

    def stop(self):

        super(KettleController, self).stop()
        self.heater_off()

    def run(self):

        r_power = int(self.ramp_power)
        b_power = int(self.boil_power)

        while self.is_running():
            temp = self.get_temp()
            r_limit = self.get_target_temp()
            if temp < r_limit and r_limit > 0:
                self.heater_on(r_power)
                self.actor_power(r_power)
            if temp >= r_limit and r_limit > 0:
                self.heater_on(b_power)
                self.actor_power(b_power)
            self.sleep(1)
Beispiel #6
0
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)
Beispiel #7
0
class Hysteresis(KettleController):

    # Custom Properties

    on = Property.Number("Offset On", True, 0)
    off = Property.Number("Offset Off", True, 0)

    def stop(self):
        '''
        Invoked when the automatic is stopped.
        Normally you switch off the actors and clean up everything
        :return: None
        '''
        super(KettleController, self).stop()
        self.heater_off()

    def run(self):
        '''
        Each controller is exectuted in its own thread. The run method is the entry point
        :return: 
        '''
        while self.is_running():

            self.actor_power(50)

            if self.get_temp() < self.get_target_temp() - int(self.on):
                self.heater_on(100)
            elif self.get_temp() >= self.get_target_temp() - int(self.off):
                self.heater_off()
            else:
                self.heater_off()
            self.sleep(1)
Beispiel #8
0
class PIDHendi(KettleController):

    P = Property.Number("P", configurable=True, default_value=40, unit="")
    I = Property.Number("I", configurable=True, default_value=140, unit="")
    D = Property.Number("D", configurable=True, default_value=0, unit="")
    Pmax = Property.Number("Max Power", configurable=True, default_value=100, unit="%")

    def run(self):
        p = float(self.P)
        i = float(self.I)
        d = float(self.D)
        pmax = int(self.Pmax)
        ts = 5

        print((p, i, d, pmax))
        pid = PID(ts, p, i, d, pmax)

        while self.is_running():
            heat_percent = pid.calc(self.get_sensor_value(), self.get_target_temp())
            if heat_percent == 0:
                self.actor_power(heat_percent)
                self.heater_off()
                cbpi.log_action("PIDHendi OFF {}")
            else:
                self.actor_power(heat_percent)
                self.heater_on(power=heat_percent)

                cbpi.log_action("PIDHendi calling heater_on(power={})".format(heat_percent))

            self.sleep(ts)

        self.heater_off()
Beispiel #9
0
class HeadsStep(StepBase, BaseColletingStep):
    collectingSpeed = Property.Number("Скорость отбора, мл/ч",
                                      configurable=True,
                                      default_value=100)
    headsTotal = Property.Number("Объем голов для отбора, мл",
                                 configurable=True,
                                 default_value=100)

    total = 0
    time = datetime.utcnow()

    def finish(self):
        self.actor_off(int(self.collectingActor))
        self.notify("", "Отбор голов завершен", type="success", timeout=2000)

    def execute(self):
        self.updateMaxCollectingSpeed()
        self.calculateActorPower()
        self.manageActor()
        self.checkTotalCollecting()
        self.notifySensor()

    def checkTotalCollecting(self):
        time = datetime.utcnow()
        if (time - self.time).total_seconds() >= 10:
            self.time = time
            self.total += float(self.collectingSpeed) / 360.0

        if self.total >= int(self.headsTotal):
            next(self)
Beispiel #10
0
class LauteringAutomation(KettleController):

    minSensorDistance = Property.Number(
        "Minimum Distance to Sensor (High Fill Level)", True, 0)
    maxSensorDistance = Property.Number(
        "Maximum Distance to Sensor (Low Fill Level)", True, 0)
    pumping = False
    currentFillLevel = 0

    def stop(self):
        super(KettleController, self).stop()
        self.heater_off()

    def run(self):
        self.sleep(1)
        while self.is_running():
            self.currentFillLevel = self.get_temp()
            if bool(self.pumping):
                if self.currentFillLevel >= float(self.maxSensorDistance):
                    self.heater_off()
                    self.pumping = False
                else:
                    self.heater_on(100)
            else:
                if self.currentFillLevel <= float(self.minSensorDistance):
                    self.heater_on(100)
                    self.pumping = True
                else:
                    self.heater_off()
            self.sleep(1)
Beispiel #11
0
class PIDArduino(KettleController):

    a_p = Property.Number("P", True, 0)
    b_i = Property.Number("I", True, 0)
    c_d = Property.Number("D", True, 0)
    d_max_out = Property.Number("max. output %", True, 100)

    def run(self):
        sampleTime = 5
        wait_time = 5
        p = float(self.a_p)
        i = float(self.b_i)
        d = float(self.c_d)
        maxout = float(self.d_max_out)
        pid = PIDArduino(sampleTime, p, i, d, 0, maxout)

        while self.is_running():
            heat_percent = pid.calc(self.get_temp(), self.get_target_temp())
            heating_time = sampleTime * heat_percent / 100
            wait_time = sampleTime - heating_time
            if heating_time == sampleTime:
                self.heater_on(100)
                self.sleep(heating_time)
            elif wait_time == sampleTime:
                self.heater_off()
                self.sleep(wait_time)
            else:
                self.heater_on(100)
                self.sleep(heating_time)
                self.heater_off()
                self.sleep(wait_time)
Beispiel #12
0
class Hysteresis(FermenterController):

    heater_offset_min = Property.Number("Heater Offset ON", True, 0, description="Offset as decimal number when the heater is switched on. Should be greater then 'Heater Offset OFF'. For example a value of 2 switches on the heater if the current temperature is 2 degrees below the target temperature")
    heater_offset_max = Property.Number("Heater Offset OFF", True, 0, description="Offset as decimal number when the heater is switched off. Should be smaller then 'Heater Offset ON'. For example a value of 1 switches off the heater if the current temperature is 1 degree below the target temperature")
    cooler_offset_min = Property.Number("Cooler Offset ON", True, 0, description="Offset as decimal number when the cooler is switched on. Should be greater then 'Cooler Offset OFF'. For example a value of 2 switches on the cooler if the current temperature is 2 degrees above the target temperature")
    cooler_offset_max = Property.Number("Cooler Offset OFF", True, 0, description="Offset as decimal number when the cooler is switched off. Should be less then 'Cooler Offset ON'. For example a value of 1 switches off the cooler if the current temperature is 1 degree above the target temperature")

    def stop(self):
        super(FermenterController, self).stop()

        self.heater_off()
        self.cooler_off()

    def run(self):
        while self.is_running():

            target_temp = self.get_target_temp()
            temp = self.get_temp()

            if temp + float(self.heater_offset_min) <= target_temp:
                self.heater_on(100)

            if temp + float(self.heater_offset_max) >= target_temp:
                self.heater_off()

            if temp >= target_temp + float(self.cooler_offset_min):
                self.cooler_on(100)

            if temp <= target_temp + float(self.cooler_offset_max):
                self.cooler_off()

            self.sleep(1)
Beispiel #13
0
class MashStep(StepBase):
    '''
    Just put the decorator @cbpi.step on top of a method
    '''
    # Properties
    temp = Property.Number("Temperature",
                           configurable=True,
                           description="Target Temperature of 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")

    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)

    @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)

    def execute(self):
        '''
        This method is execute in an interval
        :return:
        '''

        # Check if Target Temp is reached
        if self.get_kettle_temp(self.kettle) >= float(self.temp):
            # Check if Timer is Running
            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)
            # if you dont want a beep sound comment out like :  # cbpi.MashStepEndBeep()
            cbpi.MashStepEndBeep()
            self.next()
Beispiel #14
0
class GPIOinput(SensorActive):

    gpio = Property.Select("GPIO", options=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27])
    input_type = Property.Select("Input Type", options=["Momentary","Latch Rise", "Latch Fall"], description="Momentary - input high = high val. Latched - pulse on, pulse off")
    pud_type = Property.Select("Pull Up/Down", options=["Pull Up","Pull Down","Off"], description="Pull Up or down ressitor on input")

    on_val = Property.Number("High Value", configurable=True, default_value="0", description="Read value when input is high or Latch True(3.3V)")
    off_val = Property.Number("Low Value", configurable=True, default_value="100", description="Read value when sensor is low or Latch False (0V)")
    out_val = [0,1]

    input_on = False
    latch_val = False
    
    def init(self):
        self.input_on = False
        self.trigger_val = None
        try:                  
            GPIO.setup(int(self.gpio), GPIO.IN , pull_up_down = PUD_map[self.pud_type])
            GPIO.remove_event_detect(int(self.gpio))
            GPIO.add_event_detect(int(self.gpio), GPIO.BOTH, callback=self.IO_trigger, bouncetime=20)
            self.out_val = [self.off_val,self.on_val]
            self.latch_val = trig_level[self.input_type]
            super(GPIOinput,self).init()
            print "Init Complete"
            self.data_received(self.out_val[self.input_on])
        except Exception as e:
            print e

    def get_unit(self):
        unit = "NA"
        return unit
    
    def IO_trigger(self, channel):
        self.sleep(0.0005)
        self.trigger_val = GPIO.input(int(self.gpio))
        if self.input_type[0] == "L":
            if self.trigger_val != self.latch_val:
                self.trigger_val = None

    def execute(self): 
        while self.is_running():
            self.api.socketio.sleep(.1)
            #if GPIO.event_detected(int(self.gpio)):
            if self.trigger_val is not None:
                # if we're here, an edge was recognized
                #self.sleep(0.01) # debounce
                if self.input_type[0] == "M":
                    self.input_on = GPIO.input(int(self.gpio))
                else: #Latch
                    if self.trigger_val == self.latch_val:
                        self.input_on = not self.input_on
               
                self.data_received(self.out_val[self.input_on])
                self.trigger_val = None

    def stop(self):
        self.__running = False
        GPIO.cleanup([int(self.gpio)])
        GPIO.remove_event_detect(int(self.gpio))
Beispiel #15
0
class Cooling(StepBase):
    '''
    Just put the decorator @cbpi.step on top of a method
    '''
    # Properties
    temp = Property.Number("Temperature",
                           configurable=True,
                           description="Target Temperature")
    kettle = StepProperty.Kettle(
        "Kettle", description="Kettle in which the Chilling takes place")
    timer = Property.Number(
        "Timer in Seconds",
        configurable=True,
        description="Timer is started when the target temperature is reached")

    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)

    @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))

    def reset(self):
        self.stop_timer()
        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:
        '''

        # Check if Target Temp is reached
        if self.get_kettle_temp(self.kettle) <= float(self.temp):
            # Check if Timer is Running
            if self.is_timer_finished() is None:
                self.start_timer(int(self.timer))

        # Check if timer finished and go to next step
        if self.is_timer_finished() == True:
            self.notify(
                "Cooling Step Completed! Target temp is: %s C" % (self.temp),
                "Current temp is: %s C" % (self.get_kettle_temp(self.kettle)),
                timeout=10000)
            self.next()
Beispiel #16
0
class Timer(object):
    timer_end = Property.Number("TIMER_END", configurable=False)
    stopwatch_started = Property.Number("STOPWATCH_START", configurable=False)

    def start_stopwatch(self):
        if self.stopwatch_started is not None:
            return
        self.stopwatch_started = time.time()


#        cbpi.app.logger.info("Stopwatch: Started %s" % str(self.stopwatch_started))

    def stop_stopwatch(self):
        if self.stopwatch_started is not None:
            end_time = time.time()
            elapsed_time = str(end_time - self.stopwatch_started)
            cbpi.app.logger.info("Stopwatch: Stopped, Elapsed Time: %s" %
                                 (elapsed_time))
            self.stopwatch_started = None
            return elapsed_time
        else:
            return 0

    def is_stopwatch_running(self):
        #        cbpi.app.logger.info("Stopwatch: Running")
        if self.stopwatch_started is not None:
            return True
        else:
            return False

    def start_timer(self, timer):
        cbpi.app.logger.info("Started Timer ...")
        if self.timer_end is not None:
            return
        self.timer_end = int(time.time()) + timer

    def stop_timer(self):
        if self.timer_end is not None:
            self.timer_end = None

    def is_timer_running(self):
        if self.timer_end is not None:
            return True
        else:
            return False

    def timer_remaining(self):
        if self.timer_end is not None:
            return self.timer_end - int(time.time())
        else:
            return None

    def is_timer_finished(self):
        if self.timer_end is None:
            return None
        if self.timer_end <= int(time.time()):
            return True
        else:
            return False
Beispiel #17
0
class PIDPWMAutoTune(KettleController):

    a_outstep = Property.Number("output step %", True, 100, description="Default: 100. Sets the output when stepping up/down.")
    b_maxout = Property.Number("max. output %", True, 100, description="Default: 100. Sets the max power output.")
    c_lookback = Property.Number("lookback seconds", True, 30, description="Default: 30. How far back to look for min/max temps.")

    def autoOff(self):
        cbpi.cache.get("kettle")[self.kettle_id].state = False
        super(KettleController, self).stop()
        cbpi.emit("UPDATE_KETTLE", cbpi.cache.get("kettle").get(self.kettle_id))

    def stop(self):
        if self.is_running():
            self.notify("AutoTune Interrupted", "AutoTune has been interrupted and was not able to finish", type="danger", timeout=None)

        super(KettleController, self).stop()

    def run(self):
        self.notify("AutoTune In Progress", "Do not turn off Auto mode until AutoTuning is complete", type="success", timeout=None)

        sampleTime = 5
        wait_time = 5
        outstep = float(self.a_outstep)
        outmax = float(self.b_maxout)
        lookbackSec = float(self.c_lookback)
        setpoint = self.get_target_temp()
        try:
            atune = AutoTuner(setpoint, outstep, sampleTime, lookbackSec, 0, outmax)
        except Exception as e:
            self.notify("AutoTune Error", str(e), type="danger", timeout=None)
            atune.log(str(e))
            self.autoOff()
        atune.log("AutoTune will now begin")
        self.heater_on(0)
        while self.is_running() and not atune.run(self.get_temp()):
            heat_percent = atune.output
            print(heat_percent)
            self.actor_power(round(heat_percent))
            self.sleep(sampleTime)

        self.autoOff()

        if atune.state == atune.STATE_SUCCEEDED:
            atune.log("AutoTune has succeeded")
            self.notify("AutoTune Complete", "PID AutoTune was successful", type="success", timeout=None)
            for rule in atune.tuningRules:
                params = atune.getPIDParameters(rule)
                atune.log('rule: {0}'.format(rule))
                atune.log('P: {0}'.format(params.Kp))
                atune.log('I: {0}'.format(params.Ki))
                atune.log('D: {0}'.format(params.Kd))
                if rule == "brewing":
                    self.notify("AutoTune P Value", str(params.Kp), type="info", timeout=None)
                    self.notify("AutoTune I Value", str(params.Ki), type="info", timeout=None)
                    self.notify("AutoTune D Value", str(params.Kd), type="info", timeout=None)
        elif atune.state == atune.STATE_FAILED:
            atune.log("AutoTune has failed")
            self.notify("AutoTune Failed", "PID AutoTune has failed", type="danger", timeout=None)
class PT100X(SensorPassive):
    # CONFIG PARAMETER & PROPERTIES
    csPin  = Property.Select("csPin", options=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], description="GPIO Pin connected to the CS Pin of the MAX31865 - For MISO, MOSI, CLK no choice by default it's PIN 9, 10, 11")
    ResSens = Property.Select("Sensor Type", options=[100,1000],description="Select 100 for PT100 or 1000 for PT1000")
    RefRest = Property.Number("Reference Resistor", configurable=True, description="Reference Resistor of the MAX31865 board (it's written on the resistor: 430 or 4300,....)")
    offset = Property.Number("Offset", True, 0, description="Offset which is added to the received sensor data. Positive and negative values are both allowed.")
    ignore_below = Property.Number(ifelse_celcius("Low value filter threshold (°C)", "Low value filter threshold (°F)"), True, ifelse_celcius(0,32), description="Readings below this value will be ignored")
    ignore_above = Property.Number(ifelse_celcius("High value filter threshold (°C)", "High value filter threshold (°F)"), True,ifelse_celcius(100,212), description="Readings above this value will be ignored")
    misoPin = 9
    mosiPin = 10
    clkPin = 11
    ConfigText = Property.Select("Conversion Mode & Wires", options=["[0xB2] - 3 Wires Manual","[0xD2] - 3 Wires Auto","[0xA2] - 2 or 4 Wires Manual","[0xC2] - 2 or 4 Wires Auto"], description="Choose beetween 2, 3 or 4 wire PT100 & the Conversion mode at 60 Hz beetween Manual or Continuous Auto")

		#
		# Config Register
		# ---------------
		# bit 7: Vbias -> 1 (ON), 0 (OFF)
		# bit 6: Conversion Mode -> 0 (MANUAL), 1 (AUTO) !!don't change the noch fequency 60Hz when auto
		# bit5: 1-shot ->1 (ON)
		# bit4: 3-wire select -> 1 (3 wires config), 0 (2 or 4 wires)
		# bits 3-2: fault detection cycle -> 0 (none)
		# bit 1: fault status clear -> 1 (clear any fault)
		# bit 0: 50/60 Hz filter select -> 0 (60Hz - Faster converson), 1 (50Hz)
		#
		# 0b10110010 = 0xB2     (Manual conversion, 3 wires at 60Hz)
		# 0b10100010 = 0xA2     (Manual conversion, 2 or 4 wires at 60Hz)
		# 0b11010010 = 0xD2     (Continuous auto conversion, 3 wires at 60 Hz) 
		# 0b11000010 = 0xC2     (Continuous auto conversion, 2 or 4 wires at 60 Hz) 
		#


    def init(self):

        # INIT SENSOR
        self.ConfigReg = self.ConfigText[1:5]
        self.max = max31865.max31865(int(self.csPin),int(self.misoPin), int(self.mosiPin), int(self.clkPin), int(self.ResSens), int(self.RefRest), int(self.ConfigReg,16))

#        low_filter = float(self.ignore_below)
#        high_filter = float(self.ignore_above)  

    # READ SENSOR
    def read(self):
        low_filter = float(self.ignore_below)
        high_filter = float(self.ignore_above) 
        value = self.max.readTemp()

        if value < low_filter or value > high_filter:
            return

        if self.get_config_parameter("unit", "C") == "C":
            self.data_received(round(value + self.offset_value(), 2))
        else:
            self.data_received(round(9.0 / 5.0 * value + 32 + self.offset_value(), 2))

    @cbpi.try_catch(0)
    def offset_value(self):
        return float(self.offset)
Beispiel #19
0
class Rast(StepBase):
    '''
    Just put the decorator @cbpi.step on top of a method
    '''
    # Properties
    temp = Property.Number("Temperatur",
                           configurable=True,
                           description="Zieltemperatur des Schritts")
    kettle = StepProperty.Kettle("Kessel",
                                 description="Auswahl des Braukessels")
    timer = Property.Number(
        "Timer in Minuten",
        configurable=True,
        description="Timer startet, wenn die Zieltemperatur erreicht wurde")

    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)


#    @cbpi.action("Timer manuell starten")
#    def start(self):
#        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):
        pass

    def execute(self):
        '''
        This method is execute in an interval
        :return:
        '''

        # Check if Target Temp is reached
        if self.get_kettle_temp(self.kettle) >= float(self.temp):
            # Check if Timer is Running
            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("Rast beendet!",
                        "Beginne nächsten Schritt",
                        timeout=None)
            self.next()
Beispiel #20
0
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)
Beispiel #21
0
class BoilStep(StepBase):
    '''
    Just put the decorator @cbpi.step on top of a method
    '''
    # Properties
    power = Property.Number("Power", configurable=True)
    kettle = StepProperty.Kettle("Kettle")
    timer = Property.Number("Timer in Minutes", configurable=True)

    def init(self):
        '''
        Initialize Step. This method is called once at the beginning of the step
        :return:
        '''
        # set target tep
        print(("class BoilStep(StepBase): power = {}".format(self.kettle)))
        self.actor_power(1, self.power)
        #self.set_target_temp(self.power, self.kettle)

    @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.actor_power(0, self.power)
        #self.set_target_temp(self.temp, self.kettle)

    def finish(self):
        self.actor_power(0, 0)
        self.set_target_temp(0, self.kettle)

    def execute(self):
        '''
        This method is execute in an interval
        :return:
        '''

        # Check if Timer is Running
        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:
            next(self)
Beispiel #22
0
class Mod_PWM_Logic(KettleController):

    TempDiff = Property.Number("Degrees from target to start Reduction", True,
                               2)
    PowDiff = Property.Number("Percent of power deduction", True, 50)
    RampUp = Property.Number("Percent of power increase per 1/10 sec", True, 2)
    Checking = Property.Select(
        "This logic only works with heater running Mod_PWM", options=["OK"])

    def stop(self):
        self.actor_power(int(Mod_PWM.power))
        super(KettleController, self).stop()
        self.heater_off()

    def run(self):
        x = Mod_PWM()
        top = x.power
        ramp = 0

        if self.TempDiff is None:
            self.TempDiff = 2
        if self.PowDiff is None:
            self.PowDiff = 50
        if self.RampUp is None:
            self.RampUp = 2

        while self.is_running():
            if self.get_temp() >= self.get_target_temp():
                ramp = 0
                self.heater_off()
            elif self.get_temp() < self.get_target_temp() - int(self.TempDiff):
                self.heater_on(0)
                while int(ramp) < int(top):
                    self.actor_power(int(ramp))
                    ramp = ramp + int(self.RampUp)
                    self.sleep(.1)
                self.actor_power(int(top))
            else:
                self.heater_on(0)
                while int(ramp) < int(top - (top * int(self.PowDiff) / 100)):
                    self.actor_power(int(ramp))
                    ramp = ramp + int(self.RampUp)
                    self.sleep(.1)
                self.actor_power(int(top - (top * int(self.PowDiff) / 100)))
                ramp = x.power
                Mod_PWM.power = top
            self.sleep(1)
            Ntop = x.power
            if int(Ntop) <> int(top):
                top = Ntop
            self.heater_off()
Beispiel #23
0
class HendiControl(ActorBase):
    power_pin = Property.Select("Power control GPIO",
                                options=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
                                         20, 21, 22, 23, 24, 25, 26, 27], )
    onoff_pin = Property.Select("On/Off control GPIO",
                                options=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
                                         20, 21, 22, 23, 24, 25, 26, 27])
    freq = Property.Number("PWM frequency", configurable=True)
    Pmax = Property.Number("Max Power", configurable=True, default_value=100, unit="%")

    power = 0
    pwm = None
    stopped = True

    def init(self):
        GPIO.setmode(GPIO.BCM)
        # setup pins for power control
        GPIO.setup(int(self.power_pin), GPIO.OUT)
        # setup pins for on/off control
        GPIO.setup(int(self.onoff_pin), GPIO.OUT)
        GPIO.output(int(self.onoff_pin), 0)
        HendiControl.power =  int(self.Pmax)

    def on(self, power=None):
        HendiControl.stopped = False
        if HendiControl.pwm is None:
            if HendiControl.freq is None:
                HendiControl.freq = 100
            HendiControl.pwm = GPIO.PWM(int(self.power_pin), int(self.freq))
            HendiControl.pwm.start(int(HendiControl.power))
        if(0 == HendiControl.power):
            GPIO.output(int(self.onoff_pin), 0)
        else:
            GPIO.output(int(self.onoff_pin), 1)
            HendiControl.pwm.start(1)
            HendiControl.pwm.ChangeDutyCycle(int(HendiControl.power))
            cbpi.log_action("ON, Set power {}".format(HendiControl.power))

    def set_power(self, power):
        HendiControl.power = min(int(power), int(self.Pmax))
        cbpi.log_action("Set power {}".format(HendiControl.power))
        self.pwm.ChangeDutyCycle(HendiControl.power)



    def off(self):
        cbpi.log_action("off")
        self.stopped = True
        self.pwm.ChangeDutyCycle(0)
        self.pwm.stop()
        GPIO.output(int(self.onoff_pin), 0)
class GlycolChillerController(FermenterController):

    chiller_offset_min = Property.Number(
        "Cooler Offset ON",
        True,
        0,
        description=
        "Offset as decimal number when the cooler is switched on. Should be greater then 'Cooler Offset OFF'. For example a value of 2 switches on the cooler if the current temperature is 2 degrees above the target temperature"
    )
    chiller_offset_max = Property.Number(
        "Cooler Offset OFF",
        True,
        0,
        description=
        "Offset as decimal number when the cooler is switched off. Should be less then 'Cooler Offset ON'. For example a value of 1 switches off the cooler if the current temperature is 1 degree above the target temperature"
    )

    def stop(self):
        '''
        switch the chiller off when controller stops
        :return: 
        '''
        super(FermenterController, self).stop()
        self.cooler_off()

    def run(self):
        '''
        controller logic 
        :return: 
        '''
        while self.is_running():
            # Read current target temp
            target_temp = self.get_target_temp()

            # Read current temp of the fermenter (sensor1)
            temp = self.get_temp()

            # offset 1 - cast to float value
            offset1 = float(self.chiller_offset_min)

            # offset 2 - cast to float value
            offset2 = float(self.chiller_offset_max)

            if temp >= target_temp + offset1:
                self.cooler_on()

            if temp <= target_temp + offset2:
                self.cooler_off()

            # wait for 1 second
            self.sleep(1)
Beispiel #25
0
class UARTSimple(ActorBase):
    maxRPM = Property.Number("Max RPM",
                             configurable=True,
                             description="Maximale Rührgeschwindigkeit")
    stdRPM = Property.Number("Standard RPM",
                             configurable=True,
                             description="Standard Geschwindigkeit")
    power = 10  #stdRPM
    state = 0
    ser = serial.Serial("/dev/serial0", 1000000)

    def init(self):
        #start and reset sensor
        pwr = float(self.stdRPM) * 100.0 / float(self.maxRPM)
        self.set_power(int(pwr))
        try:
            ser.write('s\n')
        except:
            cbpi.notify("Rührwerk Error",
                        "Unable to open serial connection",
                        type="danger",
                        timeout=None)

    def on(self, power=None):
        rpm = int(self.power) * int(self.maxRPM) / 100.0
        try:
            ser.write(str(rpm) + '\n')
            self.state = 1
        except:
            cbpi.notify("Rührwerk Error",
                        "Unable to write to UART",
                        type="danger",
                        timeout=None)

    def set_power(self, power):
        '''
        Optional: Set the power of your actor
        :param power: int value between 0 - maxRPM
        :return:
        '''
        if power is not None:
            self.power = power
            rpm = int(self.power) * int(self.maxRPM) / 100.0
            if self.state == 1:
                ser.write(str(rpm) + '\n')

    def off(self):
        rpm = 0
        self.state = 0
        ser.write(str(0) + '\n')
Beispiel #26
0
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()
Beispiel #27
0
class Timer(object):
    timer_end = Property.Number("TIMER_END", configurable=False)

    def start_timer(self, timer):

        if self.timer_end is not None:
            return
        self.timer_end = int(time.time()) + timer

    def stop_timer(self):
        if self.timer_end is not None:
            self.timer_end = None

    def is_timer_running(self):
        if self.timer_end is not None:
            return True
        else:
            return False

    def timer_remaining(self):
        if self.timer_end is not None:
            return self.timer_end - int(time.time())
        else:
            return None

    def is_timer_finished(self):
        if self.timer_end is None:
            return None
        if self.timer_end <= int(time.time()):
            return True
        else:
            return False
Beispiel #28
0
class MashInStep(StepBase):
    '''
    Just put the decorator @cbpi.step on top of a method
    '''
    # Properties
    temp = Property.Number("Temperature", configurable=True,  description="Target Temperature of Mash Step")
    kettle = StepProperty.Kettle("Kettle", description="Kettle in which the mashing takes place")
    s = False

    @cbpi.action("Change Power")
    def change_power(self):
        self.actor_power(1, 50)

    def init(self):
        '''
        Initialize Step. This method is called once at the beginning of the step
        :return:
        '''
        # set target step
        self.s = False
        self.set_target_temp(self.temp, self.kettle)



    def execute(self):
        '''
        This method is execute in an interval
        :return:
        '''

        # Check if Target Temp is reached
        if self.get_kettle_temp(self.kettle) >= float(self.temp) and self.s is False:
            self.s = True
            #DBK_added self.actor_off(1)
            self.notify("Step Temp Reached!", "Please press the next button to continue", timeout=None)
Beispiel #29
0
class PumpStep(StepBase):

    pump = StepProperty.Actor("Pump", description="Pump actor gets toogled")
    timer = Property.Number("Timer in Minutes", configurable=True, default_value=0, description="Timer is started immediately")

    @cbpi.action("Start Timer")
    def start(self):
        if self.is_timer_finished() is None:
            self.start_timer(int(self.timer) * 60)
        #self.start_stopwatch()

    def reset(self):
        self.stop_timer()
        #self.stop_stopwatch()

    def finish(self):
        self.actor_off(int(self.pump))
        #self.stop_stopwatch()

    def init(self):
        self.actor_on(int(self.pump))

    def execute(self):
        if self.is_timer_finished() is None:
            self.start_timer(int(self.timer) * 60)

        if self.is_timer_finished() == True:
            self.next()
Beispiel #30
0
class Mod_PWM(ActorBase):

    gpio = Property.Select("GPIO", options=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27])
    frequency = Property.Number("Cycles Per Second", configurable=True)
    
    power = 100
    p = None
    stopped = True
    
    def init(self):
        GPIO.setup(int(self.gpio), GPIO.OUT)
        GPIO.output(int(self.gpio), 0)

    def on(self, power):
        self.stopped = False
        if self.p is None:
            if self.frequency is None:
                self.frequency = 50
            self.p = GPIO.PWM(int(self.gpio), int(self.frequency))
            self.p.start(int(Mod_PWM.power))
        if power is not None:
            self.p.ChangeDutyCycle(int(power))
        else:
            self.p.ChangeDutyCycle(int(Mod_PWM.power))
    
    def set_power(self, power):
        if power is not None:
            Mod_PWM.power = power
        if self.stopped is False:
            self.p.ChangeDutyCycle(int(Mod_PWM.power))

    def off(self):
        self.stopped = True
        self.p.ChangeDutyCycle(0)