class Brewer: """ A brewer uses the thermometers and heaters in order to follow the receipe. Each brewer has a single tank who knows its own composition in order to perform kick-ass calculations' """ def __init__(self): """ Constructor """ self.__name = None self.__outside_thermometer = None self.__tank = None self.__receipe = None self.__brewing_started = False def config_from_file(self, a_path): """ Configure the Brewer instantiates elements and populates the Tank as described by the selected config file :param a_path: path and name of the config file :type a_path: String """ print "using path:"+a_path with open(a_path) as f: content = f.read() f.close() print "content"+content y = BeautifulSoup(content,"xml") self.__name = y.brewer['name'] self.__receipe=Receipe("Fill me !") self.__receipe.config_from_file(y.brewer.receipe.contents[0]) thermo_tank=Thermometer(y.brewer.tank.equipments.thermometer['name'], y.brewer.tank.equipments.thermometer.path.contents[0]) if(y.brewer.tank['drivetype']=="BOOLEAN"): self.__tank=Tank(y.brewer.tank['name'],int(y.brewer.tank['diameter']),thermo_tank, BOOLEAN) elif(y.brewer.tank['drivetype']=="PID"): self.__tank=Tank(y.brewer.tank['name'],int(y.brewer.tank['diameter']),thermo_tank, PID) elif(y.brewer.tank['drivetype']=="PREDICTIVE"): self.__tank=Tank(y.brewer.tank['name'],int(y.brewer.tank['diameter']),thermo_tank, PREDICTIVE) elif(y.brewer.tank['drivetype']=="STEP_INERTIA"): self.__tank=Tank(y.brewer.tank['name'],int(y.brewer.tank['diameter']),thermo_tank, STEP_INERTIA) for a_heater in y.find_all('heater'): self.__tank.add_heater(Heater(a_heater.get('name'),int(a_heater.get('power')),int(a_heater.get('GPIOpin')))) for an_ingredient in y.find_all('ingredient'): if(an_ingredient.get('type')=="Grain"): self.__tank.add_ingredient(Ingredient(an_ingredient.get('name'),GRAIN,float(an_ingredient.get('quantity')))) elif(an_ingredient.get('type')=="Water"): self.__tank.add_ingredient(Ingredient(an_ingredient.get('name'),WATER,float(an_ingredient.get('quantity')))) self.__outside_thermometer = Thermometer(y.brewer.outsidethermometer['name'],y.brewer.outsidethermometer.path.contents[0]) return self.__name def get_name(self): """ Returns the name of the Brewer :return: Name of the Brewer :rtype: Sting """ return self.__name def print_self(self): """ Returns the Brewer as a human readable String ended with a new line :return: A String detailling the caracteristics of the Brewer :rtype: String """ to_print="Name : "+self.__name to_print+="Outside thermometer : "+self.__outside_thermometer.print_self() to_print+="Tank : "+self.__tank.print_self() to_print+="Receipe : "+self.__receipe.print_self()+"\n" return to_print def init_brewing(self): """ Checks that everything is ready for brewing and starts the receipe :return: A Boolean True = started OK, False for any anomaly :rtype: Boolean """ if(self.__name == None or self.__tank == None or self.__receipe == None or self.__brewing_started == True):return False self.__brewing_started = True self.__receipe.start(self.__tank.get_current_temperature()) print "***************************************************" print "Updated receipe "+self.__receipe.print_self() return True def log_temperatures(self,a_file): """ This function logs in the desired output file the temperature state of the system. :param a_file: path and name of the file where all temperature will be reccorded :type a_file: String """ f=open(a_file, "a") try: f.write(str(datetime.datetime.now().strftime('%H:%M:%S'))+"\t"+unicodedata.normalize('NFKD',self.__receipe.get_current_step().get_name()).encode('ascii','ignore')+"\t"+str(self.__receipe.get_current_temperature_instruction())+"\t"+str(self.__tank.get_current_temperature())+"\t"+str(self.__tank.get_heating_status())+"\n") except: print "Unexpected log write error" f.close() def brew(self,a_outputfile): """ This function is the main brewing function : ajusting the temperature according to the receipe. Function to be called regularily (every 5 seconds for instance). :param a_outputfile: path and name of the file where all temperature will be reccorded :type a_outputfile: String """ while 1==1 : self.__receipe.update_step() if(self.__receipe.get_current_step().get_type()==TRANSITION): if(self.__tank.get_current_temperature()>=self.__receipe.get_next_temperature_instruction()): #Only works as long as transitions go from lower to higher temperatures... self.__receipe.transition_complete() if(self.__receipe.get_current_step()==None): print "Receipe completed" return True #self.__tank.temperature_hysteresis_drive(self.__receipe.get_current_temperature_instruction()) #self.__tank.temperature_inertia_drive(self.__receipe.get_current_temperature_instruction(), self.__receipe.get_next_temperature_instruction()) #self.__tank.temperature_model_drive(self.__receipe.get_current_temperature_instruction(), self.__receipe.get_next_temperature_instruction(),self.__outside_thermometer.read_temperature()) self.__tank.temperature_step_inertia_drive(self.__receipe.get_current_temperature_instruction(), self.__receipe.get_next_temperature_instruction(),self.__receipe.get_current_step().get_inertia()) print "Current step : "+self.__receipe.get_current_step().print_self() print "Temperature instuction : "+str(self.__receipe.get_current_temperature_instruction()) print "Next Temperature instuction : "+str(self.__receipe.get_next_temperature_instruction()) print "Current temperature : "+str(self.__tank.get_current_temperature()) self.log_temperatures(a_outputfile) print 'Type "N" if you want to skip the current step', rlist, _, _ = select([sys.stdin], [], [], UPDATE_PERIOD) if rlist: s = sys.stdin.readline() if(s == "N\n"): print "Skip order received" self.__receipe.user_force_next_step() else: print "No input. Moving on..."