def run(self): try: on = float(self.config["ON"]) except Exception as e: on = 0 app.logger.error("Wrong ON parameter for hysteresis! Set ON parameter to 0") socketio.emit('message', {"headline": "WRONG_HYSTERESIS_PARAMETER", "message": "WRONG_ON_PARAMETER"}, namespace='/brew') try: off = float(self.config["OFF"]) except Exception as e: off = 0 app.logger.error("Wrong max parameter!") socketio.emit('message', {"headline": "WRONG_HYSTERESIS_PARAMETER", "message": "WRONG_OFF_PARAMETER"}, namespace='/brew') while self.isRunning(): currentTemp = self.getCurrentTemp() ## Current temperature targetTemp = self.getTargetTemp() ## Target Temperature if currentTemp + on < targetTemp: self.switchHeaterON() if currentTemp + off > targetTemp: self.switchHeaterOFF() socketio.sleep(1) self.switchHeaterOFF()
def stepjob(): ## Skip if no step is active if(app.brewapp_current_step == None): return ## current step cs = app.brewapp_current_step; ## get current temp of target kettle try: ct = app.brewapp_kettle_state[cs.get("kettleid")]["temp"] except: ct = 0 ## check if target temp reached and timer can be started if(cs.get("timer") > 0 and cs.get("timer_start") == None and ct >= cs.get("temp")): s = Step.query.get(cs.get("id")) s.timer_start = datetime.utcnow() app.brewapp_current_step = to_dict(s) if(s.timer_start != None): app.brewapp_current_step["endunix"] = int((s.timer_start - datetime(1970,1,1)).total_seconds())*1000 db.session.add(s) db.session.commit() socketio.emit('step_update', getAsArray(Step), namespace ='/brew') ## if Automatic step and timer is started if(cs.get("type") == 'A' and cs.get("timer_start") != None): # check if timer elapsed end = cs.get("endunix") + cs.get("timer")*60000 now = int((datetime.utcnow() - datetime(1970,1,1)).total_seconds())*1000 ## switch to next step if timer is over if(end < now): nextStep()
def readKettleTemp(): for vid in app.brewapp_kettle_state: temp = app.brewapp_thermometer.readTemp( app.brewapp_kettle_state[vid]["sensorid"]) if temp is None: return if (app.brewapp_config.get("UNIT", "C") == "F"): temp = float(format(9.0 / 5.0 * temp + 32, '.2f')) if (app.brewapp_kettle_state[vid]["sensoroffset"] != None): app.brewapp_kettle_state[vid][ "temp"] = temp + app.brewapp_kettle_state[vid]["sensoroffset"] else: app.brewapp_kettle_state[vid]["temp"] = temp timestamp = int( (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()) * 1000 app.brewapp_kettle_temps_log[vid] += [[ timestamp, app.brewapp_kettle_state[vid]["temp"] ]] socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace='/brew')
def nextStep(): active = Step.query.filter_by(state='A').first() inactive = Step.query.filter_by(state='I').order_by(Step.order).first() if(inactive == None): socketio.emit('message', {"headline": "Brewing Finished", "message": "Brew Process Finished"}, namespace ='/brew') if(active != None): active.state = 'D' active.end = datetime.utcnow() setTargetTemp(active.kettleid, 0) db.session.add(active) db.session.commit() app.brewapp_current_step = None if(inactive != None): inactive.state = 'A' inactive.start = datetime.utcnow() setTargetTemp(inactive.kettleid, inactive.temp) db.session.add(inactive) db.session.commit() app.brewapp_current_step = to_dict(inactive) if(inactive.timer_start != None): app.brewapp_current_step["endunix"] = int((inactive.timer_start - datetime(1970,1,1)).total_seconds())*1000 nextStepBeep() socketio.emit('step_update', getSteps(), namespace ='/brew')
def nextStep(): active = Step.query.filter_by(state='A').first() inactive = Step.query.filter_by(state='I').order_by(Step.order).first() if(inactive == None): socketio.emit('message', {"headline": "Brewing Finished", "message": "Brew Process Finished"}, namespace ='/brew') if(active != None): active.state = 'D' active.end = datetime.utcnow() setTargetTemp(active.kettleid, 0) db.session.add(active) db.session.commit() app.brewapp_current_step = None if(inactive != None): inactive.state = 'A' inactive.start = datetime.utcnow() setTargetTemp(inactive.kettleid, inactive.temp) db.session.add(inactive) db.session.commit() app.brewapp_current_step = to_dict(inactive) if(inactive.timer_start != None): app.brewapp_current_step["endunix"] = int((inactive.timer_start - datetime(1970,1,1)).total_seconds())*1000 nextStepBeep() socketio.emit('step_update', getAsArray(Step, order = "order"), namespace ='/brew')
def receive_spindle_data(): data = request.get_json() id = getOrNewHydrometerId(data["name"]) wort = calc_wort(app.brewapp_hydrometer_cfg[id]["tuning"], data["angle"]) timestamp = int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds()) * 1000 app.brewapp_hydrometer_cfg[id].update({ "temp": data["temperature"], "timestamp": timestamp, "wort": wort }) app.brewapp_hydrometer_temps[id] = { "temp": data["temperature"], "timestamp": timestamp, "wort": wort } writeSpindle("S_" + str(id), timestamp, data["temperature"], wort, data["battery"]) socketio.emit('hydrometer_update', app.brewapp_hydrometer_cfg, namespace='/brew') return ('', 204)
def run(self): sampleTime = 5 wait_time = 5 outstep = float(self.config[self.KEY_OUTSTEP]) outmax = float(self.config[self.KEY_MAXOUT]) lookbackSec = float(self.config[self.KEY_LOOKBACK]) setpoint = self.getTargetTemp() atune = PIDAutotune(setpoint, outstep, sampleTime, lookbackSec, 0, outmax) while self.isRunning() and not atune.run(self.getCurrentTemp()): heat_percent = atune.output heating_time = sampleTime * heat_percent / 100 wait_time = sampleTime - heating_time self.switchHeaterON() socketio.sleep(heating_time) self.switchHeaterOFF() socketio.sleep(wait_time) app.brewapp_kettle_state[self.kid]["automatic"] = False stopPID(self.kid) socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace ='/brew') if atune.state == atune.STATE_SUCCEEDED: with io.FileIO('pidparams.txt', 'w') as file: for rule in atune.tuningRules: params = atune.getPIDParameters(rule) file.write('rule: {0}\n'.format(rule)) file.write('P: {0}\n'.format(params.Kp)) file.write('I: {0}\n'.format(params.Ki)) file.write('D: {0}\n\n'.format(params.Kd))
def setTargetTemp(id, temp): kettle = Kettle.query.get(id) if(kettle != None): kettle.target_temp = temp db.session.add(kettle) db.session.commit() app.brewapp_kettle_state[id]["target_temp"] = temp socketio.emit('kettle_update', getAsArray(Kettle), namespace ='/brew')
def setTargetTemp(vid, temp): kettle = Kettle.query.get(vid) if(kettle != None): kettle.target_temp = temp db.session.add(kettle) db.session.commit() app.brewapp_kettle_state[vid]["target_temp"] = temp socketio.emit('kettle_update', getAsArray(Kettle), namespace ='/brew')
def fermenter_automatic(id): if not app.brewapp_automatic_state.get("F" + id, False): app.brewapp_automatic_state["F" + id] = True t = socketio.start_background_task(hystresis, id) else: app.brewapp_automatic_state["F" + id] = False socketio.emit('fermenter_state_update', app.brewapp_automatic_state, namespace='/brew') return ('', 204)
def ws_switch_automatic(data): vid = data["vid"] if(app.brewapp_kettle_state[vid]["automatic"] == True): app.brewapp_kettle_state[vid]["automatic"] = False stopPID(vid) else: app.brewapp_kettle_state[vid]["automatic"]= True startAutomatic(vid) socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace ='/brew')
def switch_automatic(id): id = int(id) if(app.brewapp_kettle_state[id]["automatic"] == True): app.brewapp_kettle_state[id]["automatic"] = False stopPID(id) else: app.brewapp_kettle_state[id]["automatic"]= True startAutomatic(id) socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace ='/brew') return ('',204)
def start_timer_of_current_step(): resetBeep() active = Step.query.filter_by(state='A').first() active.timer_start = datetime.utcnow() setTargetTemp(active.kettleid, active.temp) app.brewapp_current_step = to_dict(active) app.brewapp_current_step["endunix"] = int((active.timer_start - datetime(1970, 1, 1)).total_seconds()) * 1000 db.session.add(active) db.session.commit() socketio.emit('step_update', getSteps(), namespace ='/brew')
def resetCurrentSteps(): resetBeep() active = Step.query.filter_by(state='A').first() active.start = datetime.utcnow() active.end = None active.timer_start = None setTargetTemp(active.kettleid, active.temp) app.brewapp_current_step = to_dict(active) db.session.add(active) db.session.commit() socketio.emit('step_update', getSteps(), namespace='/brew')
def ws_switch_automatic(data): vid = data["vid"] if (app.brewapp_kettle_state[vid]["automatic"] == True): app.brewapp_kettle_state[vid]["automatic"] = False stopPID(vid) else: app.brewapp_kettle_state[vid]["automatic"] = True startAutomatic(vid) socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace='/brew')
def resetCurrentSteps(): resetBeep() active = Step.query.filter_by(state='A').first() active.start = datetime.utcnow() active.end = None active.timer_start = None setTargetTemp(active.kettleid, active.temp) app.brewapp_current_step = to_dict(active) db.session.add(active) db.session.commit() socketio.emit('step_update', getSteps(), namespace ='/brew')
def start_timer_of_current_step(): resetBeep() active = Step.query.filter_by(state='A').first() active.timer_start = datetime.utcnow() setTargetTemp(active.kettleid, active.temp) app.brewapp_current_step = to_dict(active) app.brewapp_current_step["endunix"] = int( (active.timer_start - datetime(1970, 1, 1)).total_seconds()) * 1000 db.session.add(active) db.session.commit() socketio.emit('step_update', getSteps(), namespace='/brew')
def resetSteps(): resetBeep() db.session.query(Step).update( { 'state': 'I', 'start': None, 'end': None, 'timer_start': None }, synchronize_session='evaluate') db.session.commit() socketio.emit('step_update', getSteps(), namespace='/brew')
def ws_switch(data): s = data["switch"] if(app.brewapp_switch_state[s] == True): app.logger.info("Switch off: " + str(s)) app.brewapp_hardware.switchOFF(s); app.brewapp_switch_state[s] = False else: app.logger.info("Switch on: " + str(s)) app.brewapp_hardware.switchON(s); app.brewapp_switch_state[s] = True socketio.emit('switch_state_update', app.brewapp_switch_state, namespace ='/brew')
def stepjob(): ## Skip if no step is active if (app.brewapp_current_step == None): return ## current step cs = app.brewapp_current_step ## get current temp of target kettle try: id = int(app.brewapp_kettle_state[cs.get("kettleid")]["sensorid"]) ct = app.brewapp_thermometer_last[id] except: ct = 0 #print cs.get("timer") #print cs.get("timer_start") #print cs.get("temp") #print ct ## check if target temp reached and timer can be started if (cs.get("timer") is not None and cs.get("timer_start") == None and ct >= cs.get("temp")): s = Step.query.get(cs.get("id")) s.timer_start = datetime.utcnow() app.brewapp_current_step = to_dict(s) if (s.timer_start != None): app.brewapp_current_step["endunix"] = int( (s.timer_start - datetime(1970, 1, 1)).total_seconds()) * 1000 timerBeep() db.session.add(s) db.session.commit() socketio.emit('step_update', getSteps(), namespace='/brew', broadcast=True) ## if Automatic step and timer is started if (cs.get("timer_start") != None): # check if timer elapsed end = cs.get("endunix") + cs.get("timer") * 60000 now = int( (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()) * 1000 ## switch to next step if timer is over if (end < now): if (cs.get("type") == 'A'): nextStep() if (cs.get("type") == 'M' and app.brewapp_current_step.get( "finished", False) == False): nextStepBeep() app.brewapp_current_step["finished"] = True
def receive_spindle_data(): data = request.get_json() id = getOrNewHydrometerId(data["name"]) wort = calc_wort(app.brewapp_hydrometer_cfg[id]["tuning"], data["angle"]) timestamp = int((datetime.datetime.utcnow() - datetime.datetime(1970, 1, 1)).total_seconds()) * 1000 app.brewapp_hydrometer_cfg[id].update({"temp": data["temperature"], "timestamp": timestamp, "wort": wort}) app.brewapp_hydrometer_temps[id] = {"temp": data["temperature"], "timestamp": timestamp, "wort": wort} writeSpindle("S_"+str(id), timestamp, data["temperature"], wort, data["battery"]) socketio.emit('hydrometer_update', app.brewapp_hydrometer_cfg, namespace='/brew') return ('', 204)
def hystresis(id): while app.brewapp_automatic_state["F" + id]: fermenter = app.cbp['FERMENTERS'][int(id)] if type(fermenter["sensorid"]) is not int: socketio.emit('message', { "headline": "NO_TERMOMETER", "message": "NO_THERMOMETER_DEFINED" }, namespace='/brew') break temp = app.brewapp_thermometer_last[fermenter["sensorid"]] target_temp = fermenter["target_temp"] heater_min = fermenter["heateroffset_min"] heater_max = fermenter["heateroffset_max"] cooler_min = fermenter["cooleroffset_min"] cooler_max = fermenter["cooleroffset_max"] heater_id = fermenter["heaterid"] if type( fermenter["heaterid"]) is int else None cooler_id = fermenter["coolerid"] if type( fermenter["coolerid"]) is int else None if heater_id is not None: if temp + heater_min < target_temp: switchOn(fermenter["heaterid"]) if temp + heater_max > target_temp: switchOff(fermenter["heaterid"]) if cooler_id is not None: if temp > target_temp + cooler_min: switchOn(fermenter["coolerid"]) if temp < target_temp + cooler_max: switchOff(fermenter["coolerid"]) socketio.sleep(1) app.brewapp_automatic_state["F" + id] = False if type(fermenter["heaterid"]) is int: switchOff(fermenter["heaterid"]) if type(fermenter["coolerid"]) is int: switchOff(fermenter["coolerid"])
def readKettleTemp(): for vid in app.brewapp_kettle_state: temp = app.brewapp_thermometer.readTemp(app.brewapp_kettle_state[vid]["sensorid"]) if(app.brewapp_config.get("UNIT", "C") == "F"): temp = float(format(9.0/5.0 * temp + 32, '.2f')) if(app.brewapp_kettle_state[vid]["sensoroffset"] != None): app.brewapp_kettle_state[vid]["temp"] = float(format(temp + app.brewapp_kettle_state[vid]["sensoroffset"], '.2f')) else: app.brewapp_kettle_state[vid]["temp"] = float(format(temp, '.2f')) timestamp = int((datetime.utcnow() - datetime(1970,1,1)).total_seconds())*1000 app.brewapp_kettle_temps_log[vid] += [[timestamp, app.brewapp_kettle_state[vid]["temp"] ]] socketio.emit('kettle_state_update', app.brewapp_kettle_state, namespace ='/brew')
def stepjob(): ## Skip if no step is active if(app.brewapp_current_step == None): return ## current step cs = app.brewapp_current_step; ## get current temp of target kettle try: id = int(app.brewapp_kettle_state[cs.get("kettleid")]["sensorid"]) ct = app.brewapp_thermometer_last[id]; except: ct = 0 #print cs.get("timer") #print cs.get("timer_start") #print cs.get("temp") #print ct ## check if target temp reached and timer can be started if(cs.get("timer") is not None and cs.get("timer_start") == None and ct >= cs.get("temp")): s = Step.query.get(cs.get("id")) s.timer_start = datetime.utcnow() app.brewapp_current_step = to_dict(s) if(s.timer_start != None): app.brewapp_current_step["endunix"] = int((s.timer_start - datetime(1970,1,1)).total_seconds())*1000 timerBeep() db.session.add(s) db.session.commit() socketio.emit('step_update', getSteps(), namespace ='/brew', broadcast=True) ## if Automatic step and timer is started if(cs.get("timer_start") != None): # check if timer elapsed end = cs.get("endunix") + cs.get("timer")*60000 now = int((datetime.utcnow() - datetime(1970,1,1)).total_seconds())*1000 ## switch to next step if timer is over if(end < now ): if(cs.get("type") == 'A'): nextStep() if(cs.get("type") == 'M' and app.brewapp_current_step.get("finished", False) == False): nextStepBeep() app.brewapp_current_step["finished"] = True
def hystresis(id): while app.brewapp_automatic_state["F" + id]: fermenter = app.cbp['FERMENTERS'][int(id)] if type(fermenter["sensorid"]) is not int: socketio.emit('message', {"headline": "NO_TERMOMETER", "message": "NO_THERMOMETER_DEFINED"}, namespace='/brew') break temp = app.brewapp_thermometer_last[fermenter["sensorid"]] target_temp = fermenter["target_temp"] heater_min = fermenter["heateroffset_min"] heater_max = fermenter["heateroffset_max"] cooler_min = fermenter["cooleroffset_min"] cooler_max = fermenter["cooleroffset_max"] heater_id = fermenter["heaterid"] if type(fermenter["heaterid"]) is int else None cooler_id = fermenter["coolerid"] if type(fermenter["coolerid"]) is int else None if heater_id is not None: if temp + heater_min < target_temp: switchOn(fermenter["heaterid"]) if temp + heater_max > target_temp: switchOff(fermenter["heaterid"]) if cooler_id is not None: if temp > target_temp + cooler_min: switchOn(fermenter["coolerid"]) if temp < target_temp + cooler_max: switchOff(fermenter["coolerid"]) socketio.sleep(1) app.brewapp_automatic_state["F" + id] = False if type(fermenter["heaterid"]) is int: switchOff(fermenter["heaterid"]) if type(fermenter["coolerid"]) is int: switchOff(fermenter["coolerid"])
def playSound(melodie): socketio.emit('beep', {"melodie": melodie}, namespace='/brew') try: buzzer_gpio = app.brewapp_config.get("BUZZER_GPIO", None) if (buzzer_gpio == None): return for i in melodie: if (isinstance(i, str)): if i == "H": GPIO.output(int(buzzer_gpio), GPIO.HIGH) else: GPIO.output(int(buzzer_gpio), GPIO.LOW) else: time.sleep(i) except Exception as e: app.logger.error("BUZZER ERROR " + str(e))
def pidjob(kid): app.logger.info("Start PID - Kettle Id: "+ str(kid)) while isRunning(kid): ## Current temperature currentTemp = getCurrentTemp(kid) ## Target Temperature targetTemp = getTargetTemp(kid) ## Current Temp is below Target Temp ... switch heater on if(currentTemp < targetTemp and app.brewapp_pid_state.get(kid, False) == False): app.brewapp_pid_state[kid] = True switchHeaterON(kid) socketio.emit('kettle_automatic_on', kid, namespace ='/brew') ## Current Temp is equal or higher than Target Temp ... switch Heater off if(currentTemp >= targetTemp and app.brewapp_pid_state.get(kid, False) == True): app.brewapp_pid_state[kid] = False switchHeaterOFF(kid) socketio.emit('kettle_automatic_off', kid, namespace ='/brew') time.sleep(1) app.brewapp_pid_state[kid] = False switchOFF(kid) socketio.emit('kettle_automatic_off', kid, namespace ='/brew') app.logger.info("Stop PID - Kettle Id: "+ str(kid))
def ws_switch(data): s = int(data["switch"]) if (app.brewapp_switch_state.get(s, None) == None): socketio.emit('message', { "headline": "HARDWARE_ERROR", "message": "PLEASE_CHECK_YOUR_HARDWARE_CONFIG" }, namespace='/brew') return if (app.brewapp_hardware_config[s]["config"].get("switch", None) is None): socketio.emit('message', { "headline": "HARDWARE_ERROR", "message": "PLEASE_CHECK_YOUR_HARDWARE_CONFIG" }, namespace='/brew') return if (app.brewapp_switch_state[s] == True): app.logger.info("Switch off: " + str(s)) app.brewapp_hardware.switchOFF(str(s)) app.brewapp_switch_state[s] = False else: app.logger.info("Switch on: " + str(s)) app.brewapp_hardware.switchON(str(s)) app.brewapp_switch_state[s] = True socketio.emit('switch_state_update', app.brewapp_switch_state, namespace='/brew')
def run(self): try: on = float(self.config["ON"]) except Exception as e: on = 0 app.logger.error( "Wrong ON parameter for hysteresis! Set ON parameter to 0") socketio.emit('message', { "headline": "WRONG_HYSTERESIS_PARAMETER", "message": "WRONG_ON_PARAMETER" }, namespace='/brew') try: off = float(self.config["OFF"]) except Exception as e: off = 0 app.logger.error("Wrong max parameter!") socketio.emit('message', { "headline": "WRONG_HYSTERESIS_PARAMETER", "message": "WRONG_OFF_PARAMETER" }, namespace='/brew') while self.isRunning(): currentTemp = self.getCurrentTemp() ## Current temperature targetTemp = self.getTargetTemp() ## Target Temperature if currentTemp + on < targetTemp: self.switchHeaterON() if currentTemp + off > targetTemp: self.switchHeaterOFF() socketio.sleep(1) self.switchHeaterOFF()
def ws_switch(data): s = int(data["switch"]) if(app.brewapp_switch_state.get(s, None) == None): socketio.emit('message', {"headline": "HARDWARE_ERROR", "message": "PLEASE_CHECK_YOUR_HARDWARE_CONFIG"}, namespace='/brew') return if(app.brewapp_hardware_config[s]["config"].get("switch", None) is None): socketio.emit('message', {"headline": "HARDWARE_ERROR", "message": "PLEASE_CHECK_YOUR_HARDWARE_CONFIG"}, namespace='/brew') return if(app.brewapp_switch_state[s] == True): app.logger.info("Switch off: " + str(s)) app.brewapp_hardware.switchOFF(str(s)); app.brewapp_switch_state[s] = False else: app.logger.info("Switch on: " + str(s)) app.brewapp_hardware.switchON(str(s)); app.brewapp_switch_state[s] = True socketio.emit('switch_state_update', app.brewapp_switch_state, namespace ='/brew')
def switchOff(s): app.brewapp_hardware.switchOFF(s); app.brewapp_switch_state[s] = False socketio.emit('switch_state_update', app.brewapp_switch_state, namespace ='/brew')
def reload_fermenter(id): f = Fermenter.query.get(id) d = to_dict(f, deep={'steps': []}) app.cbp['FERMENTERS'][f.id] = d socketio.emit('fermenter_update', d, namespace='/brew')
def resetSteps(): resetBeep() db.session.query(Step).update({'state': 'I', 'start': None, 'end': None, 'timer_start': None}, synchronize_session='evaluate') db.session.commit() socketio.emit('step_update', getAsArray(Step, order = "order"), namespace ='/brew')
def switchOn(s): app.brewapp_hardware.switchON(s); app.brewapp_switch_state[s] = True socketio.emit('switch_state_update', app.brewapp_switch_state, namespace ='/brew')
def post_post(result, **kw): if result["type"] is "json": result["value"] = json.loads(result["value"]) readConfig() socketio.emit('config', app.brewapp_config, namespace='/brew')