class SimpleManualStep(StepBase): # Properties heading = Property.Text("Heading", configurable=True, default_value="Step Alert", description="First line of notification.") message = Property.Text("Message", configurable=True, default_value="Press next button to continue", description="Second line of notification.") notifyType = Property.Select( "Type", options=["success", "info", "warning", "danger"]) proceed = Property.Select( "Next Step", options=["Pause", "Continue"], description= "Whether or not to automatically continue to the next brew step.") #------------------------------------------------------------------------------- def init(self): if self.notifyType not in ["success", "info", "warning", "danger"]: self.notifyType = "info" self.notify(self.heading, self.message, type=self.notifyType, timeout=None) if self.proceed == "Continue": next(self)
class iSpindel(SensorActive): key = Property.Text(label="iSpindel Name", configurable=True, description="Enter the name of your iSpindel") sensorType = Property.Select("Data Type", options=["Temperature", "Gravity", "Battery"], description="Select which type of data to register for this sensor") tuningPolynom = Property.Text(label="Tuning Polynomial", configurable=True, default_value="tilt", description="Enter your iSpindel polynomial. Use the variable tilt for the angle reading from iSpindel. Does not support ^ character.") unitsGravity = Property.Select("Gravity Units", options=["SG", "Brix", "°P"], description="Displays gravity reading with this unit if the Data Type is set to Gravity. Does not convert between units, to do that modify your polynomial.") def get_unit(self): if self.sensorType == "Temperature": return "°C" if self.get_config_parameter("unit", "C") == "C" else "°F" elif self.sensorType == "Gravity": return self.unitsGravity elif self.sensorType == "Battery": return "V" else: return " " def stop(self): pass def execute(self): global cache while self.is_running(): try: if cache[self.key] is not None: if self.sensorType == "Gravity": reading = calcGravity(self.tuningPolynom, cache[self.key]['Angle'], self.unitsGravity) else: reading = cache[self.key][self.sensorType] self.data_received(reading) except: pass self.api.socketio.sleep(1)
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))
class AtlasSensor(SensorActive): sensorSelect = Property.Select("Sensor Select", options=["0", "1", "2", "3"], description="Select available USB sensor") unitSelect = Property.Select("Unit Select", options=["Temp in F", "pH Value"], description="Select Unit") def get_unit(self): if self.unitSelect == "Temp in F": return " °F" elif self.unitSelect == "pH Value": return " pH" else: return "Select Data Type" def stop(self): ''' Stop the sensor. Is called when the sensor config is updated or the sensor is deleted :return: ''' print("Atlas Sensor Stopped") pass def execute(self): ''' Active sensor has to handle its own loop :return: ''' #dev_active.send_cmd("C,0") # turn off continuous mode #dev_active.flush() #cbpi.app.logger.info("Device %s Flushed" % dev_active) while self.is_running(): try: index = self.sensorSelect print("index = ", index) dev_active = get_sensor(index) #self.sleep(0.25) reading = run_Temp(dev_active) print("Sensor Reading = %s" % reading) self.data_received(reading) self.sleep(3) except: print("Error3: could not run execute loop.") self.sleep(2) #@classmethod #def init_global(self): #pass #@cbpi.initalizer() #def init(cbpi): #pass
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)
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 WiiSensor(SensorPassive): offset = Property.Number('Offset', True, 0) unit_of_measure = Property.Select('Unit of measure', ['KG', 'LBS']) def init(self): self.t = WiiThread() def shudown(): shudown.cb.shutdown() shudown.cb = self.t self.t.start() def stop(self): try: self.t.stop() except: pass def get_unit(self): if self.unit_of_measure == 'KG': return 'KG' else: return 'LBS' def read(self): if self.unit_of_measure == 'KG': self.data_received(round(self.t.value + float(self.offset), 2)) else: self.data_received( round(self.t.value * 2.20462262185 + float(self.offset), 2))
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)
class RelayBoard(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 ], description="GPIO to which the actor is connected") def init(self): GPIO.setup(int(self.gpio), GPIO.OUT) GPIO.output(int(self.gpio), 1) def on(self, power=0): GPIO.output(int(self.gpio), 0) state = "ON" filename = "./logs/%s_%s.log" % ("actor_gpio", int(self.gpio)) formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) msg = str(formatted_time) + "," + str(state) + "\n" with open(filename, "a") as file: file.write(msg) def off(self): GPIO.output(int(self.gpio), 1) state = "OFF" filename = "./logs/%s_%s.log" % ("actor_gpio", int(self.gpio)) formatted_time = strftime("%Y-%m-%d %H:%M:%S", localtime()) msg = str(formatted_time) + "," + str(state) + "\n" with open(filename, "a") as file: file.write(msg)
class eManometer(SensorActive): key = Property.Text(label="eManometer Name", configurable=True, description="Enter the name of your eManometer") sensorType = Property.Select( "Data Type", options=["Temperature", "Pressure", "CO2"], description="Select which type of data to register for this sensor") def get_unit(self): if self.sensorType == "Temperature": return "°C" if self.get_config_parameter("unit", "C") == "C" else "°F" elif self.sensorType == "Pressure": return "bar" elif self.sensorType == "CO2": return "g/l" else: return " " def stop(self): pass def execute(self): global cache while self.is_running(): try: if cache[self.key] is not None: reading = cache[self.key][self.sensorType] self.data_received(reading) except: pass self.api.socketio.sleep(1)
class brewBubbles(SensorActive): log("cbpi_brewbubbles Start Instancing") key = Property.Text(label="BrewBubbles Name", configurable=True, description="Enter the name of your BrewBubbles") sensorType = Property.Select( "Data Type", options=["BPM", "Room Temp.", "Vessel Temp."], description="Select which type of data to register for this sensor") log("cbpi_brewbubbles continue Instancing") def get_unit(self): if self.sensorType == "Temperature": if self.get_config_parameter("unit", "C") == "C": return "°C" else: return "°F" else: return " " def stop(self): pass def execute(self): global cache while self.is_running(): try: if cache[self.key] is not None: reading = cache[self.key][self.sensorType] self.data_received(reading) except: pass self.api.socketio.sleep(1)
class ONE_WIRE_SENSOR(SensorPassive): sensor_name = Property.Select("Sensor", getSensors()) def init(self): self.t = myThread(self.sensor_name) def shudown(): shudown.cb.shutdown() shudown.cb = self.t self.t.start() def stop(self): try: self.t.stop() except: pass def read(self): if self.get_config_parameter("unit", "C") == "C": self.data_received(self.t.value) else: self.data_received(format(9.0 / 5.0 * self.t.value + 32, '.2f')) @classmethod def init_global(self): try: call(["modprobe", "w1-gpio"]) call(["modprobe", "w1-therm"]) except Exception as e: pass
class GPIOPWM(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 ]) duty_cylce = Property.Number("Duty Cycle", configurable=True) p = None power = 100 def init(self): GPIO.setup(int(self.gpio), GPIO.OUT) GPIO.output(int(self.gpio), 0) def on(self, power=None): if power is not None: self.power = int(power) if self.duty_cylce is None: duty_cylce = 50 self.p = GPIO.PWM(int(self.gpio), int(self.duty_cylce)) self.p.start(int(self.power)) def set_power(self, power): if power is not None: self.power = int(power) self.p.ChangeDutyCycle(self.power) def off(self): print "GPIO OFF" self.p.stop()
class sense_emu(SensorPassive): type = Property.Select("TYPE", options=["humidity", "temperature"]) def get_unit(self): ''' :return: Unit of the sensor as string. Should not be longer than 3 characters ''' if self.type == "humidity": return "%" if self.type == "temperature": return "°C" if self.get_config_parameter("unit", "C") == "C" else "°F" def read(self): self.api.app.logger.info("Sense HAT Emulator") sensor = SenseHat() try: humidity = 64 * sensor.humidity / 100 temperature = sensor.temp self.api.app.logger.info(humidity) self.api.app.logger.info(temperature) if self.type == "humidity": self.data_received(round(humidity, 2)) if self.type == "temperature": if self.get_config_parameter("unit", "C") == "C": self.data_received(round(temperature, 2)) else: self.data_received(round((9.0 / 5.0 * temperature) + 32, 2)) except Exception as e: self.api.app.logger.error("Sense Hat Emulator error")
class GembirdUSB(ActorBase): socket_no = Property.Select(label="Socket No", options=[1, 2, 3, 4, 5]) def on(self, power=100): try: print((self.socket_no)) command = "sudo sispmctl -o " + str(self.socket_no) subprocess.call(command, shell=True) except Exception as e: self.api.notify( "Gembird Actor Error", "Faied to switch socket. Please check configuration", type="danger", timeout=None) self.api.app.logger.error("Failed to switch Socket") def off(self): try: command = "sudo sispmctl -f " + str(self.socket_no) subprocess.call(command, shell=True) except Exception as e: self.api.notify( "Gembird Actor Error", "Faied to switch socket. Please check configuration", type="danger", timeout=None) self.api.app.logger.error("Failed to switch Socket")
class Silvercrest433Mhz(ActorBase): socket = Property.Select("socket", options=["A", "B", "C", "D"]) on_codes = {'A': '1045296', 'B': '1045300', 'C': '1045308', 'D': '772370'} off_codes = {'A': '280608', 'B': '230816', 'C': '772380', 'D': '1045298'} def send(self, code): try: call([ "sudo /home/pi/433Utils/RPi_utils/./codesend %s 4 355" % (code) ], shell=True) except Exception as e: self.api.app.logger.error( "FAILED to switch Silvercrest 433Mhz Code: %s" % (code)) def on(self, power=100): self.send(self.on_codes[self.socket]) self.api.app.logger.info( "SWITCHED Silvercrest 433Mhz Socket: %s - %s" % (self.socket, self.on_codes[self.socket])) def off(self): self.send(self.off_codes[self.socket]) self.api.app.logger.info( "SWITCHED Silvercrest 433Mhz Socket: %s - %s" % (self.socket, self.off_codes[self.socket]))
class AutoSwitch(StepBase): # Properties a_id = StepProperty.Kettle("Kettle") b_auto = Property.Select("Auto Setting", options=["On", "Off"]) def init(self): if isinstance(self.a_id, unicode) and self.a_id: self.id = (int(self.a_id)) self.auto_type = self.b_auto try: kettle = cbpi.cache.get("kettle").get(self.id) if (kettle.state is False) and (self.auto_type = "On"): # Start controller if kettle.logic is not None: cfg = kettle.config.copy() cfg.update(dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor)) instance = cbpi.get_controller(kettle.logic).get("class")(**cfg) instance.init() kettle.instance = instance def run(instance): instance.run() t = self.api.socketio.start_background_task(target=run, instance=instance) kettle.state = True cbpi.emit("UPDATE_KETTLE", kettle) else (kettle.state is True) and (self.auto_type = "Off"): # Stop controller kettle.instance.stop() kettle.state = False cbpi.emit("UPDATE_KETTLE", kettle)
class HopDropperActor(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 ], description="GPIO to which the actor is connected") timeout = Property.Number( "Timeout", configurable=True, default_value=2, description="After how many seconds the actor should switch off again") def init(self): GPIO.setup(int(self.gpio), GPIO.OUT) GPIO.output(int(self.gpio), 0) def on(self, power=0): def toggleTimeJob(id, t): self.api.socketio.sleep(t) self.api.switch_actor_off(int(id)) if self.timeout: t = self.api.socketio.start_background_task(target=toggleTimeJob, id=self.id, t=int(self.timeout)) GPIO.output(int(self.gpio), 1) def off(self): GPIO.output(int(self.gpio), 0)
class SimpleMashInStep(StepBase): # Properties a_kettle_prop = StepProperty.Kettle( "Kettle", description="Kettle in which the mashing takes place") b_target_prop = Property.Number( "Temperature", configurable=True, description="Target Temperature of Mash Step") c_agitator_prop = Property.Select("Run agitator while heating?", options=["Yes", "No"]) d_kill_heat_prop = Property.Select("Turn off heater when target reached?", options=["Yes", "No"]) #------------------------------------------------------------------------------- def init(self): self.kettle = int(self.a_kettle_prop) self.target = float(self.b_target_prop) self.agitator_run = self.c_agitator_prop == "Yes" self.kill_heat = self.d_kill_heat_prop == "Yes" self.done = False self.agitator = getAgitator( cbpi.cache.get("kettle")[self.kettle].agitator) # set target temp self.set_target_temp(self.target, self.kettle) if self.agitator and self.agitator_run: self.actor_on(self.agitator) #------------------------------------------------------------------------------- def finish(self): self.set_target_temp(0, self.kettle) #------------------------------------------------------------------------------- def execute(self): # Check if Target Temp is reached if (self.get_kettle_temp(self.kettle) >= self.target) and (self.done is False): self.done = True if self.kill_heat: self.set_target_temp(0, self.kettle) if self.agitator: self.actor_off(self.agitator) self.notify("{} complete".format(self.name), "Press next button to continue", type='warning', timeout=None)
class SensorGroup(SensorPassive): sensordesc = "Select a sensor to be included in this group." sensor01 = Property.Sensor("Sensor 1", description=sensordesc) sensor02 = Property.Sensor("Sensor 2", description=sensordesc) sensor03 = Property.Sensor("Sensor 3", description=sensordesc) sensor04 = Property.Sensor("Sensor 4", description=sensordesc) sensor05 = Property.Sensor("Sensor 5", description=sensordesc) sensor06 = Property.Sensor("Sensor 6", description=sensordesc) sensor07 = Property.Sensor("Sensor 7", description=sensordesc) sensor08 = Property.Sensor("Sensor 8", description=sensordesc) value_type = Property.Select( "Value", options=["Average", "Minimum", "Maximum"], description="Select what data to return from the group.") def init(self): self.sensors = [] if isinstance(self.sensor01, unicode) and self.sensor01: self.sensors.append(int(self.sensor01)) if isinstance(self.sensor02, unicode) and self.sensor02: self.sensors.append(int(self.sensor02)) if isinstance(self.sensor03, unicode) and self.sensor03: self.sensors.append(int(self.sensor03)) if isinstance(self.sensor04, unicode) and self.sensor04: self.sensors.append(int(self.sensor04)) if isinstance(self.sensor05, unicode) and self.sensor05: self.sensors.append(int(self.sensor05)) if isinstance(self.sensor06, unicode) and self.sensor06: self.sensors.append(int(self.sensor06)) if isinstance(self.sensor07, unicode) and self.sensor07: self.sensors.append(int(self.sensor07)) if isinstance(self.sensor08, unicode) and self.sensor08: self.sensors.append(int(self.sensor08)) def stop(self): pass def read(self): values = [ float(cbpi.cache.get("sensors")[sensor].instance.last_value) for sensor in self.sensors ] if self.value_type == "Minimum": temp = min(values) elif self.value_type == "Maximum": temp = max(values) else: temp = sum(values) / len(values) self.data_received(round(temp, 2)) def get_unit(self): if len(self.sensors) > 0: return cbpi.cache.get("sensors")[ self.sensors[0]].instance.get_unit() else: return super(SensorBase, self).get_unit()
class MCP23017_TestActor(ActorBase): a_busad = Property.Select("Bus Address", options=["0x20","0x21","0x22","0x23","0x24","0x25","0x26","0x27"], description="Bus address setting of MCP based on A0 A1 A2.") b_chan = Property.Text("Channel", configurable=True, default_value="100", description="MCP Output channel 0-128") #c_pud = Property.Select("Pull up", options=["Off","Up"], default_value = "Off", description="Pull Up or down resisitor") f_inv = Property.Select("Invert Output", options=["No","Yes"], description="Invert the output so on means output at 0V") #initiasliser called when an actor is created or changed def init(self): try: self.busad = self.a_busad self.chan = int(self.b_chan) + 500 if self.f_inv == "Yes": self.on_pol = 0 self.off_pol = 1 else: self.on_pol = 1 self.off_pol = 0 #self.check_mcp() self.is_on = False mcp.pinMode(chan,1) mcp.digitalWrite(self.chan,self.off_pol) except Exception as e: traceback.print_exc() raise def on(self, power=100): self.is_on = True if power != None: self.power = power mcp.digitalWrite(self.chan,self.on_pol) def off(self): self.is_on = False self.mcp.digitalWrite(self.chan,self.off_pol) def set_power(self, power): self.power = power @cbpi.action("TODO: Reitialise MCP system") def recon(self): pass
class BM_ManualStep(StepBase): # Properties heading = Property.Text("Heading", configurable=True, default_value="Step Alert", description="First line of notification.") message = Property.Text("Message", configurable=True, default_value="Press next button to continue", description="Second line of notification.") notifyType = Property.Select( "Type", options=["success", "info", "warning", "danger"]) proceed = Property.Select( "Next Step", options=["Pause", "Continue"], description= "Whether or not to automatically continue to the next brew step.") s = False #------------------------------------------------------------------------------- @cbpi.action("Start Timer Now") def init(self): if self.notifyType not in ["success", "info", "warning", "danger"]: self.notifyType = "info" def execute(self): ''' This method is execute in an interval :return: ''' # Check if Target Temp is reached if self.s is False: self.s = True self.notify(self.heading, self.message, type=self.notifyType, timeout=None) if self.proceed == "Continue": #Python 2 try: self.next() #Python3 except: next(self) pass
class SerialSensors(SensorPassive): sensor_name = Property.Select( "arduino's /dev/ttyACM?", getTTYACM(), description= "Possible devices where an arduino is connected; if empty, no arduino connected." ) sensor_baud = Property.Select( "arduino's baud rate", getBaudRate(), description="Select the baud rate defined in your arduino program.") sensor_actv = Property.Select( "System Temperature", getYesNo(), description="Select to add CBP's system temperature or not.") sensor_strt = Property.Select( "Startup Message", getYesNo(), description= "Select to send the start up message: \"CBP3SerialSensors\"; to let arduino recognizing a starting point for data processing." ) def init(self): self.t = myThread(self.id, self.sensor_name, self.sensor_baud, self.sensor_actv, self.sensor_strt) def shutdown(): shutdown.cb.shutdown() shutdown.cb = self.t self.t.start() def stop(self): try: self.t.stop() except: pass def read(self): if self.get_config_parameter("unit", "C") == "C": self.data_received(round(self.t.value, 2)) else: self.data_received(round(9.0 / 5.0 * self.t.value + 32, 2))
class PT100(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") RefRest = Property.Number("Reference Resistor", configurable=True, description="Reference Resistor of the MAX31865 board (it's written on the resistor: 400 or 430 or 431,....)") misoPin = 9 mosiPin = 10 clkPin = 11 ConfigText = Property.Select("Conversion Mode & Wires", options=["[0xB2] Manual conversion, 3 wire @60Hz","[0xA2] Manual conversion, 2/4 wire @60Hz","[0xD2] Continuous (auto) conversion, 3 wire @60Hz","[0xC2] Continuous auto conversion, 2/4 wires @60Hz"], description="Select sensor conversion type") # # 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] print "Initialise MAX31865 at address" print hex(int(self.ConfigReg,16)) self.max = max31865.max31865(int(self.csPin),int(self.misoPin), int(self.mosiPin), int(self.clkPin), int(self.RefRest), int(self.ConfigReg,16)) def read(self): # READ SENSOR if self.get_config_parameter("unit", "C") == "C": self.data_received(round(self.max.readTemp(), 2)) else: self.data_received(round(9.0 / 5.0 * self.max.readTemp() + 32, 2))
class SimpleTargetStep(StepBase): # Properties auto_mode = Property.Select( "Auto Mode", options=["Set to ON", "Set to OFF", "No Change"]) kettle = StepProperty.Kettle("Kettle") target = Property.Number("Target Temp", configurable=True) #------------------------------------------------------------------------------- def init(self): self.set_target_temp(float(self.target), int(self.kettle)) if self.auto_mode == "Set to ON": self.setAutoMode(True) elif self.auto_mode == "Set to OFF": self.setAutoMode(False) next(self) #------------------------------------------------------------------------------- def setAutoMode(self, auto_state): try: kettle = cbpi.cache.get("kettle")[int(self.kettle)] if (kettle.state is False) and (auto_state is True): # turn on if kettle.logic is not None: cfg = kettle.config.copy() cfg.update( dict(api=cbpi, kettle_id=kettle.id, heater=kettle.heater, sensor=kettle.sensor)) instance = cbpi.get_controller( kettle.logic).get("class")(**cfg) instance.init() kettle.instance = instance def run(instance): instance.run() t = cbpi.socketio.start_background_task(target=run, instance=instance) kettle.state = not kettle.state cbpi.emit("UPDATE_KETTLE", cbpi.cache.get("kettle")[int(self.kettle)]) elif (kettle.state is True) and (auto_state is False): # turn off kettle.instance.stop() kettle.state = not kettle.state cbpi.emit("UPDATE_KETTLE", cbpi.cache.get("kettle")[int(self.kettle)]) except Exception as e: cbpi.notify("Error", "Failed to set Auto mode {}".format(["OFF", "ON" ][auto_state]), type="danger", timeout=None) cbpi.app.logger.error(e)
class TPLinkPlug(ActorBase): plug_name = Property.Select("Plug", [1,2,3,4,5], description="TPLink Plug") plug_time = Property.Number("Publish stats every minute", configurable = True, unit="s", default_value=0, description="Time in minutes to publish voltage stats, 0 is off") plug_ip = Property.Text("TP-Link Plug Local IP", configurable = True, default_value="", description="Local IP address is used instead of Cloud service, leave blank to use cloud service.") c_off = 0 d_on = 1 cnt_timer = 0 def on(self, power=100): try: send(command = self.d_on, plug = int(self.plug_name), ip = self.plug_ip) except: cbpi.notify("TPLinkPlug Error", "Device not correctly setup, go to Hardware settings and correct.", type="danger", timeout=10000) def off(self): try: send(command = self.c_off, plug = int(self.plug_name), ip=self.plug_ip) except: cbpi.notify("TPLinkPlug Error", "Device not correctly setup, go to Hardware settings and correct.", type="danger", timeout=10000) def set_power(self, power): pass def url(self): try: no = int(self.plug_name)-1 url = TPplugs[no]["appServerUrl"] except: url = "" return url def device(self): try: no = int(self.plug_name)-1 device = TPplugs[no]["deviceId"] except: device = "" return device def time(self): return self.plug_time def showstats(self): plug_time = int(self.plug_time) if plug_time == 0: return False self.cnt_timer += 1 if (self.cnt_timer >= plug_time): self.cnt_timer = 0 return True return False def ip(self): return self.plug_ip
class EnergenieSocket(ActorBase): socket = Property.Select("socket", options=[0,1,2,3,4]) @classmethod def init_global(cls): pass def on(self, power=100): switch(int(self.socket), True, False) def off(self): switch(int(self.socket), False, True)
class GPIODelay(ActorBase): gpio = Property.Select("GPIO", options=range(28), description="GPIO pin number") delay = Property.Number( "Minimum delay", configurable=True, default_value=300, unit="s", description="Minimum wait time before switching on (s)", ) switched_off_at = None def init(self): gpio = int(self.gpio) GPIO.setup(gpio, GPIO.OUT) GPIO.output(gpio, 0) def on(self, power=0): gpio = int(self.gpio) cbpi.app.logger.info("Request to switch on GPIO %d" % gpio) if GPIO.input(gpio) == 1: cbpi.app.logger.info("GPIO %d already on" % gpio) return if self.switched_off_at is not None: since_last_off = time.time() - self.switched_off_at cbpi.app.logger.info( "GPIO %d last switched off %d seconds ago" % (gpio, since_last_off) ) if since_last_off < float(self.delay): cbpi.app.logger.info( "Not enough time since last switched off GPIO %d" % gpio ) return cbpi.app.logger.info("Switching on GPIO %d" % gpio) GPIO.output(gpio, 1) def off(self): gpio = int(self.gpio) cbpi.app.logger.info("Request to switch off GPIO %d" % gpio) if GPIO.input(gpio) == 0: cbpi.app.logger.info("GPIO already off %d" % gpio) return cbpi.app.logger.info("Switching off GPIO %d" % gpio) self.switched_off_at = time.time() GPIO.output(gpio, 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()
class GPIOSimple(ActorBase): """ Simple GPIO Actor """ 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 ], description="GPIO to which the actor is connected") mode = Property.Select( "Mode", options=["regular", "inverse"], description= "regular means 'ON' is GPIO 'High' and inverse means 'ON' is GPIO 'Low'" ) def init(self): GPIO.setup(int(self.gpio), GPIO.OUT) if self.mode == "regular": GPIO.output(int(self.gpio), 0) else: GPIO.output(int(self.gpio), 1) def on(self, power=0): print(("GPIO ON %s" % str(self.gpio))) if self.mode == "regular": GPIO.output(int(self.gpio), 1) else: GPIO.output(int(self.gpio), 0) def off(self): print("GPIO OFF") if self.mode == "regular": GPIO.output(int(self.gpio), 0) else: GPIO.output(int(self.gpio), 1)