def __checkForExpired(self): """ Private slot to check entries for expiration. """ if self.__daysToExpire < 0 or len(self.__history) == 0: return now = QDateTime.currentDateTime() nextTimeout = 0 while self.__history: checkForExpired = QDateTime(self.__history[-1].dateTime) checkForExpired.setDate(checkForExpired.date().addDays(self.__daysToExpire)) if now.daysTo(checkForExpired) > 7: nextTimeout = 7 * 86400 else: nextTimeout = now.secsTo(checkForExpired) if nextTimeout > 0: break itm = self.__history.pop(-1) self.__lastSavedUrl = "" self.entryRemoved.emit(itm) self.__saveTimer.saveIfNeccessary() if nextTimeout > 0: self.__expiredTimer.start(nextTimeout * 1000)
def __checkForExpired(self): """ Private slot to check entries for expiration. """ if self.__daysToExpire < 0 or len(self.__history) == 0: return now = QDateTime.currentDateTime() nextTimeout = 0 while self.__history: checkForExpired = QDateTime(self.__history[-1].dateTime) checkForExpired.setDate(checkForExpired.date().addDays( self.__daysToExpire)) if now.daysTo(checkForExpired) > 7: nextTimeout = 7 * 86400 else: nextTimeout = now.secsTo(checkForExpired) if nextTimeout > 0: break itm = self.__history.pop(-1) self.__lastSavedUrl = "" self.entryRemoved.emit(itm) self.__saveTimer.saveIfNeccessary() if nextTimeout > 0: self.__expiredTimer.start(nextTimeout * 1000)
def add_racer_to_modeldb(modeldb, racer, field_name, field_start): #pylint: disable=too-many-branches """Adds a racer to the model, or updates an existing racer.""" # Racers without a tt_finish_time_url are placeholder entries and should not show # up in our racer list. if not 'tt_finish_time_url' in racer: return metadata = { 'ontheday': { 'id': racer['id'], 'tt_finish_time_url': racer['tt_finish_time_url'], 'checksum': racer['checksum'] } } ontheday_watch_finish_time = racer['watch_finish_time'] ontheday_tt_dnf = racer['tt_dnf'] if ontheday_tt_dnf: finish = MSECS_DNP elif ontheday_watch_finish_time == '00:00:00': finish = MSECS_UNINITIALIZED else: reference_datetime = QDateTime(QDate.currentDate()) date = reference_datetime.date() time = QTime.fromString(ontheday_watch_finish_time, Qt.ISODateWithMs) if time.isValid(): datetime = QDateTime(date, time) finish = reference_datetime.msecsTo(datetime) else: finish = MSECS_UNINITIALIZED if finish == MSECS_UNINITIALIZED: status = '' else: status = 'remote' if field_start: start = field_start else: start_clock = QDateTime( QDate.currentDate(), QTime.fromString(racer['watch_start_time'], Qt.ISODateWithMs)) start = QDateTime(QDate.currentDate()).msecsTo(start_clock) if modeldb.racer_table_model.racer_exists(str(racer['race_number'])): modeldb.racer_table_model.update_racer( racer['race_number'], racer['firstname'], racer['lastname'], field_name, racer['category'], racer['team'], racer['racing_age'], start, finish, status, json.dumps(metadata)) else: modeldb.racer_table_model.add_racer(racer['race_number'], racer['firstname'], racer['lastname'], field_name, racer['category'], racer['team'], racer['racing_age'], start, finish, status, json.dumps(metadata))
def load_history_data(pair, start_date, finish_date): try: start_date = QDateTime(start_date) finish_date = QDateTime(finish_date) date = start_date.date() year_month_load = [] while not (date.month() == finish_date.date().month() and date.year() == finish_date.date().year()): year_month_load.append(str(date.year()) + "_" + str(date.month())) date = date.addMonths(1) year_month_load.append(str(date.year()) + "_" + str(date.month())) trades = [] for year_month in year_month_load: trades_load = [] if os.path.isfile(SAVE_PATH + '/' + pair + '_' + year_month + '.hst'): while True: try: with open( SAVE_PATH + '/' + pair + '_' + year_month + '.hst', 'rb') as f: trades_load = pickle.loads( zlib.decompress(f.read())) break except: time.sleep(1) trades += trades_load finish_date = finish_date.addDays(1) if len(trades) != 0: trades = trades[find_pos_to_date(trades, start_date): find_pos_to_date(trades, finish_date)] return trades except: print('load_history_data', pair) sys.exit()
def inRepetitiveScheduleRange(self, rule): start = QDateTime.fromString(rule.start, "MMddyyyyhh:mm:ss") end = QDateTime.fromString(rule.end, "MMddyyyyhh:mm:ss") now = QDateTime().currentDateTime() startTime = start.time() endTime = end.time() currTime = now.time() startDayOfWeek = start.date().dayOfWeek() endDayOfWeek = end.date().dayOfWeek() currDayOfWeek = now.date().dayOfWeek() duration = ((endDayOfWeek - startDayOfWeek) + 7) % 7 curDuration = ((currDayOfWeek - startDayOfWeek) + 7) % 7 # True if in valid range else False return not((curDuration > duration) or (curDuration == duration and (currTime < startTime or currTime >= endTime)))
def setData(self, index, value, role=Qt.EditRole): #pylint: disable=invalid-name """Convert the friendly representation back to msecs.""" if role in (Qt.DisplayRole, Qt.EditRole): if index.column( ) in self.msecs_from_reference_columns + self.msecs_delta_columns: if not value: msecs = MSECS_UNINITIALIZED elif value.upper() == 'DNS': msecs = MSECS_DNS elif value.upper() == 'DNF': msecs = MSECS_DNF elif value.upper() == 'DNP': msecs = MSECS_DNP else: race_table_model = self.modeldb.race_table_model if index.column( ) in self.msecs_from_reference_columns and self.wall_times: reference_datetime = race_table_model.get_reference_clock_datetime( ) else: reference_datetime = QDateTime(QDate.currentDate()) date = reference_datetime.date() time = QTime.fromString(value, defaults.DATETIME_FORMAT) if time.isValid(): datetime = QDateTime(date, time) msecs = reference_datetime.msecsTo(datetime) else: msecs = MSECS_UNINITIALIZED return self.sourceModel().setData(self.mapToSource(index), msecs, role) return super().setData(index, value, role)
def extractProfileCropsterXLS(file): res = {} # the interpreted data set book = xlrd.open_workbook(file) sheet_names = book.sheet_names() # extract general profile information general_sh = book.sheet_by_index(0) if general_sh.nrows >= 1: general_data = dict( zip([x.value for x in general_sh.row(0)], general_sh.row(1))) if 'Id-Tag' in general_data: try: id_tag = general_data['Id-Tag'].value batch_prefix = id_tag.rstrip('0123456789') batch_number = int(id_tag[len(batch_prefix):]) res["roastbatchprefix"] = batch_prefix res["roastbatchnr"] = batch_number except: pass for tag, label in zip([ 'Profile', 'Lot name', 'Machine', 'Roast technician', 'Sensorial notes', 'Roasting notes' ], [ 'title', 'beans', 'roastertype', 'operator', 'cuppingnotes', 'roastingnotes' ]): if tag in general_data: try: value = str(general_data[tag].value) res[label] = value except: pass if 'Date' in general_data: try: raw_date = general_data['Date'].value date_tuple = xlrd.xldate_as_tuple(raw_date, book.datemode) date = QDateTime(*date_tuple) res["roastdate"] = encodeLocal(date.date().toString()) res["roastisodate"] = encodeLocal(date.date().toString( Qt.ISODate)) res["roasttime"] = encodeLocal(date.time().toString()) res["roastepoch"] = int(date.toTime_t()) res["roasttzoffset"] = libtime.timezone except: pass if 'Ambient temp.' in general_data: try: value = general_data['Ambient temp.'].value res['ambientTemp'] = float(value) except: pass if 'Start weight' in general_data or 'End weight' in general_data: cropster_weight_units = ["G", "KG", "LBS", "OZ"] artisan_weight_units = ["g", "Kg", "lb", "oz"] weight = [0, 0, artisan_weight_units[0]] try: value = general_data['End weight unit'].value idx = cropster_weight_units.index(value) weight[2] = artisan_weight_units[idx] except: pass try: value = general_data['Start weight unit'].value idx = cropster_weight_units.index(value) weight[2] = artisan_weight_units[idx] except: pass try: value = general_data['Start weight'].value weight[0] = value except: pass try: value = general_data['End weight'].value weight[1] = value except: pass res["weight"] = weight # BT: try: BT_idx = sheet_names.index("Curve - Bean temp.") BT_sh = book.sheet_by_index(BT_idx) if BT_sh.ncols >= 1: time = BT_sh.col(0) temp = BT_sh.col(1) if len(time) > 0 and len(temp) > 0 and len(time) == len(temp): if "FAHRENHEIT" in str(temp[0].value): res["mode"] = 'F' else: res["mode"] = 'C' res["timex"] = [t.value for t in time[1:]] res["temp2"] = [t.value for t in temp[1:]] res["temp1"] = [-1] * len(res["timex"]) res["timeindex"] = [0, 0, 0, 0, 0, 0, len(res["timex"]) - 1, 0] except: pass # ET try: ET_idx = sheet_names.index("Curve - Env. temp.") ET_sh = book.sheet_by_index(ET_idx) if ET_sh.ncols >= 1: time = ET_sh.col(0) temp = ET_sh.col(1) if len(time) > 0 and len(temp) > 0 and len(time) == len(temp): if "FAHRENHEIT" in str(temp[0].value): res["mode"] = 'F' else: res["mode"] = 'C' res["temp1"] = [t.value for t in temp[1:]] if len(res["timex"]) != len(res["temp1"]): res["timex"] = [t.value for t in time[1:]] if "temp2" not in res or len(res["temp2"]) != len( res["timex"]): res["temp2"] = [-1] * len(res["timex"]) res["timeindex"] = [0, 0, 0, 0, 0, 0, len(res["timex"]) - 1, 0] except: pass # extra temperature curves channel = 1 # toggle between channel 1 and 2 to be filled with extra temperature curve data for sn in sheet_names: if sn.startswith( "Curve" ) and "temp." in sn and sn != "Curve - Bean temp." and sn != "Curve - Env. temp.": try: extra_curve_name = sn.split("Curve - ") if len(extra_curve_name) > 1: extra_curve_name = extra_curve_name[1].split("temp.") extra_curve_name = extra_curve_name[0] else: extra_curve_name = extra_curve_name[0] CT_idx = sheet_names.index(sn) CT_sh = book.sheet_by_index(CT_idx) if CT_sh.ncols >= 1: time = CT_sh.col(0) temp = CT_sh.col(1) if len(time) > 0 and len(temp) > 0 and len(time) == len( temp): if "extradevices" not in res: res["extradevices"] = [] if "extraname1" not in res: res["extraname1"] = [] if "extraname2" not in res: res["extraname2"] = [] if "extratimex" not in res: res["extratimex"] = [] if "extratemp1" not in res: res["extratemp1"] = [] if "extratemp2" not in res: res["extratemp2"] = [] if "extramathexpression1" not in res: res["extramathexpression1"] = [] if "extramathexpression2" not in res: res["extramathexpression2"] = [] if channel == 1: channel = 2 res["extradevices"].append(25) res["extraname1"].append(extra_curve_name) res["extratimex"].append( [t.value for t in time[1:]]) res["extratemp1"].append( [t.value for t in temp[1:]]) res["extramathexpression1"].append("") elif (len(time) - 1) == len( res["extratimex"][-1] ): # only if time lengths is same as of channel 1 channel = 1 res["extraname2"].append(extra_curve_name) res["extratemp2"].append( [t.value for t in temp[1:]]) res["extramathexpression2"].append("") except: pass if "extraname1" in res and "extraname2" in res and len( res["extraname1"]) != len(res["extraname2"]): # we add an empty second extra channel if needed res["extraname2"].append("Extra 2") res["extratemp2"].append([-1] * len(res["extratemp1"][-1])) res["extramathexpression2"].append("") # add events try: COMMENTS_idx = sheet_names.index("Comments") COMMENTS_sh = book.sheet_by_index(COMMENTS_idx) gas_event = False # set to True if a Gas event exists airflow_event = False # set to True if an Airflow event exists specialevents = [] specialeventstype = [] specialeventsvalue = [] specialeventsStrings = [] if COMMENTS_sh.ncols >= 4: takeClosest = lambda num, collection: min( collection, key=lambda x: abs(x - num)) for r in range(COMMENTS_sh.nrows): if r > 0: try: time = COMMENTS_sh.cell(r, 0).value comment_type = COMMENTS_sh.cell(r, 2).value if comment_type not in [ "Turning point" ]: # TP is ignored as it is automatically assigned comment_value = COMMENTS_sh.cell(r, 3).value c = takeClosest(time, res["timex"]) timex_idx = res["timex"].index(c) if comment_type == "Color change": res["timeindex"][1] = timex_idx elif comment_type == "First crack": res["timeindex"][2] = timex_idx elif comment_type == "Second crack": res["timeindex"][4] = timex_idx else: specialevents.append(timex_idx) if comment_type == "Airflow": airflow_event = True specialeventstype.append(0) elif comment_type == "Gas": gas_event = True specialeventstype.append(3) else: specialeventstype.append(4) try: v = float(comment_value) v = v / 10. + 1 specialeventsvalue.append(v) except: specialeventsvalue.append(0) if comment_type not in [ "Airflow", "Gas", "Comment" ]: specialeventsStrings.append(comment_type) else: specialeventsStrings.append(comment_value) except: pass if len(specialevents) > 0: res["specialevents"] = specialevents res["specialeventstype"] = specialeventstype res["specialeventsvalue"] = specialeventsvalue res["specialeventsStrings"] = specialeventsStrings if gas_event or airflow_event: # first set etypes to defaults res["etypes"] = [ QApplication.translate("ComboBox", "Air", None), QApplication.translate("ComboBox", "Drum", None), QApplication.translate("ComboBox", "Damper", None), QApplication.translate("ComboBox", "Burner", None), "--" ] # update if airflow_event: res["etypes"][0] = "Airflow" if gas_event: res["etypes"][3] = "Gas" except: pass return res
class SunMoonWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setupGraphicsScene() self.configuration = tombo.configfile.ConfigFile('sunmoon.conf') self.getConfiguration() self.minimum_interval = self.miscellaneous['minimum_interval'] self.setLocation() self.timer = QTimer() self.setupMethods() self.setCurrentDate() self.setConfigurationText() self.displayedDate = QDateTime(self.ui.deDate.date()) self.show() def setLocation(self): self.location = Location((self.astral['name'], self.astral['region'], float(self.astral['latitude']), float(self.astral['longitude']), self.astral['timezone'], self.astral['elevation'])) def getConfiguration(self): self.astral = self.configuration.getItems('ASTRAL') self.miscellaneous = self.configuration.getItems('MISCELLANEOUS') def setConfigurationText(self): config_label_text_color = "#" + self.miscellaneous['config_text_color'] self.ui.leLatitude.setText(self.astral['latitude']) self.ui.lblLatitude.setText("<font color='" + config_label_text_color + "'>" + self.astral['latitude'] + "</font>") self.ui.leLongitude.setText(self.astral['longitude']) self.ui.lblLongitude.setText("<font color='" + config_label_text_color + "'>" + self.astral['longitude'] + "</font>") self.ui.leElevation.setText(self.astral['elevation']) self.ui.lblElevation.setText("<font color='" + config_label_text_color + "'>" + self.astral['elevation'] + "</font>") self.ui.leLocation.setText(self.astral['name']) self.ui.lblLocation.setText("<font color='" + config_label_text_color + "'>" + self.astral['name'] + "</font>") self.ui.leCountry.setText(self.astral['region']) self.ui.lblRegion.setText("<font color='" + config_label_text_color + "'>" + self.astral['region'] + "</font>") self.ui.leTimeZone.setText(self.astral['timezone']) self.ui.lblTimeZone.setText("<font color='" + config_label_text_color + "'>" + self.astral['timezone'] + "</font>") self.ui.leMinimumInterval.setText(self.miscellaneous['minimum_interval']) self.ui.leTextColor.setText(self.miscellaneous['config_text_color']) def setCurrentDate(self): self.ui.deDate.setDate(QDate.currentDate()) self.displayedDate = QDateTime(self.ui.deDate.date()) def setupGraphicsScene(self): self.scene = QGraphicsScene() self.scene.setBackgroundBrush(Qt.black) self.scene.setSceneRect(0, 0, 209, 169) self.ui.gvMoon.setScene(self.scene) self.brushWhite = QBrush(QColor(Qt.white)) self.brushBlack = QBrush(QColor(Qt.black)) self.pen = QPen(Qt.NoPen) self.ellipseWhite = self.scene.addEllipse(50, 30, 100, 100, self.pen, self.brushWhite) self.ellipseBlack = self.scene.addEllipse(50, 30, 100, 100, self.pen, self.brushBlack) def setupMethods(self): self.ui.deDate.dateChanged.connect(self.setTimes) self.ui.pbStart.clicked.connect(lambda: self.autoStartStop("start")) self.ui.pbStop.clicked.connect(lambda: self.autoStartStop("stop")) self.ui.pbSave.clicked.connect(lambda: self.configActions("save")) self.ui.pbDiscard.clicked.connect(lambda: self.configActions("discard")) self.ui.pbClear.clicked.connect(lambda: self.configActions("clear")) self.timer.timeout.connect(self.advanceDate) self.ui.pbSetCurrentDate.clicked.connect(self.setCurrentDate) #---------------------------------------------------------------------- def configActions(self, action): """Some pushbutton actions route here.""" #print(action) if action == 'clear': self.clearConfigFields() elif action == 'discard': self.clearConfigFields() self.setConfigurationText() elif action == 'save': self.saveConfiguration() #---------------------------------------------------------------------- def saveConfiguration(self): """Save info from config fields.""" self.configuration.setValue('MISCELLANEOUS', 'minimum_interval', self.ui.leMinimumInterval.text()) self.configuration.setValue('MISCELLANEOUS', 'config_text_color', self.ui.leTextColor.text()) self.configuration.setValue('ASTRAL', 'latitude', self.ui.leLatitude.text()) self.configuration.setValue('ASTRAL', 'longitude', self.ui.leLongitude.text()) self.configuration.setValue('ASTRAL', 'elevation', self.ui.leElevation.text()) self.configuration.setValue('ASTRAL', 'timezone', self.ui.leTimeZone.text()) self.configuration.setValue('ASTRAL', 'name', self.ui.leLocation.text()) self.configuration.setValue('ASTRAL', 'region', self.ui.leCountry.text()) self.getConfiguration() self.setConfigurationText() #---------------------------------------------------------------------- def clearConfigFields(self): """Clear text from all config tab fields.""" self.ui.leLatitude.setText('') self.ui.leLongitude.setText('') self.ui.leElevation.setText('') self.ui.leLocation.setText('') self.ui.leCountry.setText('') self.ui.leTimeZone.setText('') self.ui.leMinimumInterval.setText('') self.ui.leTextColor.setText('') #---------------------------------------------------------------------- def discardConfigFields(self): """Clear all config fields and repopulate with original text.""" self.clearConfigFields() self.setConfigurationText() def autoStartStop(self, action): if action == 'start': if self.ui.sbInterval.value() == 0: self.timer.setInterval(int(self.miscellaneous['minimum_interval'])) else: self.timer.setInterval(self.ui.sbInterval.value() * 1000) self.timer.start() elif action == 'stop': self.timer.stop() def advanceDate(self): self.displayedDate = self.displayedDate.addDays(1) self.ui.deDate.setDate(self.displayedDate.date()) def setTimes(self): date_displayed = self.ui.deDate.date().toPyDate() astral_info = self.location.sun(date_displayed) self.ui.leSunrise.setText(astral_info['sunrise'].strftime('%I:%M %p')) self.ui.leSunset.setText(astral_info['sunset'].strftime('%I:%M %p')) self.ui.leDaylight.setText(self.calcDaylight(astral_info['sunset'] - astral_info['sunrise'])) self.ui.leMoonPhase.setText('Day ' + str(self.location.moon_phase(date_displayed, type(float)))) self.setMoonPhase(self.location.moon_phase(date_displayed, type(float))) #print(self.location.moon_phase(date=None, rtype=type(float))) def calcDaylight(self, timedelta): return '{} hours, {} minutes'.format(timedelta.seconds // 3600, (timedelta.seconds // 60) % 60) def setMoonPhase(self, moon_phase): #print(moon_phase) increment = 100 / 14 self.scene.removeItem(self.ellipseBlack) if moon_phase < 15: self.ellipseBlack = self.scene.addEllipse((moon_phase * -increment) + 50, 30, 100, 100, self.pen, self.brushBlack) else: self.ellipseBlack = self.scene.addEllipse(((moon_phase - 28) * -increment) + 50, 30, 100, 100, self.pen, self.brushBlack)
class DT(object): ''' Date and Time Object ''' def __init__(self, stamp=None): loct = int(time.time()) self.tz = (time.mktime(time.gmtime(loct)) - loct) / 3600 self.dst = time.localtime()[8] self.__call__(stamp) def __call__(self, stamp=None): if stamp == None: self.epoch = int(time.time()) elif isinstance(stamp, int) or isinstance(stamp, float): self.epoch = int(stamp) elif isinstance(stamp, str): if is_datecode(stamp): # YYWWD # set epoch to the beginning of the datecode # http://stackoverflow.com/questions/5882405/get-date-from-iso-week-number-in-python iso_year = int(stamp[:2]) if iso_year > 70: # epoch = 1 Jan 1970 ;-) iso_year += 1900 else: iso_year += 2000 iso_week = int(stamp[2:4]) iso_day = int(stamp[4]) temp = iso_to_gregorian(iso_year, iso_week, iso_day) self.epoch = int( (datetime.datetime(temp.year, temp.month, temp.day) - datetime.datetime(1970, 1, 1)).total_seconds()) elif is_date(stamp): # DDMMYYYY DD = int(stamp[:2]) MM = int(stamp[2:4]) YYYY = int(stamp[4:]) self.epoch = int( (datetime.datetime(YYYY, MM, DD) - datetime.datetime(1970, 1, 1)).total_seconds()) elif os.path.exists(stamp): # file path self.epoch = os.stat(stamp)[6] else: raise Exception( "can not interprete the string '%s' as an initializer " % stamp) elif isinstance(stamp, QDateTime): self.epoch = stamp.currentSecsSinceEpoch() elif isinstance(stamp, QDate): DD = stamp.dayOfWeek() MM = stamp.month() YYYY = stamp.year() self.epoch = int((datetime.datetime(YYYY, MM, DD) - datetime.datetime(1970, 1, 1)).total_seconds()) else: raise Exception("Don't now how to handle type(%s)=%s" % (stamp, type(stamp))) self._populate() def _populate(self): t = time.gmtime(self.epoch) d = datetime.date(t.tm_year, t.tm_mon, t.tm_mday) self.datecode = "%4d%02d%1d" % (d.isocalendar()[0], d.isocalendar()[1], d.isocalendar()[2]) # YYYYWWD self.datecode = self.datecode[2:] # YYWWD self.min = t.tm_min # minute of the hour [0 .. 59] if self.min < 15: self.qhour = 1 elif self.min < 30: self.qhour = 2 elif self.min < 45: self.qhour = 3 else: self.qhour = 4 self.hour = t.tm_hour # hour of the day [0 .. 23] self.sec = t.tm_sec # seconds of the min [0..59] self.wday = d.isocalendar()[2] if self.wday == 1: self.wday_name = 'Monday' elif self.wday == 2: self.wday_name = 'Tuesday' elif self.wday == 3: self.wday_name = 'Wednesday' elif self.wday == 4: self.wday_name = 'Thursday' elif self.wday == 5: self.wday_name = 'Friday' elif self.wday == 6: self.wday_name = 'Saturday' elif self.wday == 7: self.wday_name = 'Sunday' else: # should never reach this point raise DTOerror self.mday = t.tm_mday # day of the month [1 .. 31] self.yday = t.tm_yday # day of the year [1 .. 365/366] depending on leap year self.week = d.isocalendar()[ 1] # week of the year [1 .. 52/53] aka 'Work Week' self.month = t.tm_mon # month of the year [1 .. 12] if self.month == 1: self.month_name = 'January' elif self.month == 2: self.month_name = 'February' elif self.month == 3: self.month_name = 'March' elif self.month == 4: self.month_name = 'April' elif self.month == 5: self.month_name = 'May' elif self.month == 6: self.month_name = 'June' elif self.month == 7: self.month_name = 'July' elif self.month == 8: self.month_name = 'August' elif self.month == 9: self.month_name = 'September' elif self.month == 10: self.month_name = 'October' elif self.month == 11: self.month_name = 'November' elif self.month == 12: self.month_name = 'December' else: # should never reach this point raise DTOerror if self.month in [1, 2, 3]: self.quarter = 1 elif self.month in [4, 5, 6]: self.quarter = 2 elif self.month in [7, 8, 9]: self.quarter = 3 else: self.quarter = 4 self.year = t.tm_year # year self.datetime = datetime.datetime(self.year, self.month, self.mday, self.hour, self.min, self.sec) self.date = datetime.date(self.year, self.month, self.mday) self.time = datetime.time(self.hour, self.min, self.sec) utc_offset = (-self.tz * 3600) + (self.dst * 3600) self.QDateTime = QDateTime() self.QDateTime.setOffsetFromUtc( int(utc_offset)) # timezone + day light saving self.QDateTime.setSecsSinceEpoch(self.epoch) self.QDate = self.QDateTime.date() self.QTime = self.QDateTime.time() def boh(self): ''' Returns the epoch (is thus gmt based) for the Begin Of the Hour from the underlaying epoch. The epoch of the object remains unchanged. ''' return int( (datetime.datetime(self.year, self.month, self.mday, self.hour) - datetime.datetime(1970, 1, 1)).total_seconds()) def eoh(self): ''' Returns the epoch (is thus gmt based) for the End Of the Hour from the underlaying epoch. The underlaying epoch of the object remains unchanged. ''' return self.boh() + 3600 - 1 def bod(self): ''' Returns the epoch (is thus gmt based) for the Begin Of the Day from the underlaying epoch. The epoch of the object remains unchanged. ''' return int((datetime.datetime(self.year, self.month, self.mday) - datetime.datetime(1970, 1, 1)).total_seconds()) def eod(self): ''' Returns the epoch (is thus gmt based) for the End Of the Day from the underlaying epoch. The underlaying epoch of the object remains unchanged. ''' return self.bod() + (24 * 60 * 60) def bow(self): ''' Returns the epoch (is thus gmt based) for the Begin Of the Week from the underlaying epoch. The underlaying epoch of the object remains unchanged. ''' temp = iso_to_gregorian(self.year, self.week, 1) return int((datetime.datetime(temp.year, temp.month, temp.day) - datetime.datetime(1970, 1, 1)).total_seconds()) def eow(self): ''' Returns the epoch (is thus gmt based) for the End Of the Week from the underlaying epoch. The underlaying epoch of the object remains unchanged. ''' return self.bow() + (7 * 24 * 60 * 60) def bom(self): ''' Returns the epoch (is thus gmt based) of the Begin Of the Month from the undelaying epoch. The underlying epoch of the object remains unchanged. ''' return DT("01%2s%4s" % (self.month, self.year)) def eom(self): ''' Returns the epoch (is thus gmt based) of the End Of the Month from the undelaying epoch. The underlying epoch of the object remains unchanged. ''' if self.month == 12: return DT("0101%4s" % (self.year + 1)).epoch - 1 else: return DT("01%2s%4s" % (self.month + 1, self.year)).epoch - 1 def boy(self): ''' Returns the epoch (is thus gmt based) of the Begin Of the Year from the underlaying epoch. The underlying epoch of the object remains unchanged. ''' return DT("0101%4s" % self.year).epoch def eoy(self): ''' Returns the epoch (is thus gmt based) of the End Of the Year from the undelaying epoch. The undelaying epoch of the object remains unchanged. ''' return DT("0101%4s" % (self.year + 1)).epoch - 1 def local(self): ''' Returns the epoch (is thus gmt based) for the LOCAL time. The underlaying epoch remains unchanged. ''' return self.epoch - (self.tz * 3600) + (abs(self.dst) * 3600) def __sub__(self, other): if self.__class__.__name__ == other.__class__.__name__: return TD(self.epoch - other.epoch) return NotImplemented def __lt__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch < other.epoch: return True else: return False def __le__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch <= other.epoch: return True else: return False def __eq__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch == other.epoch: return True else: return False def __ne__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch != other.epoch: return True else: return False def __gt__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch > other.epoch: return True else: return False def __ge__(self, other): if self.__class__.__name__ != other.__class__.__name__: return False if self.epoch >= other.epoch: return True else: return False def __repr__(self): #Monday, January 6 2014 @ 13:22:11 (Q1 2014) return "%s, %s %s %s @ %02d:%02d:%02d (Q%s %s)" % ( self.wday_name, self.month_name, self.mday, self.year, self.hour, self.min, self.sec, self.quarter, self.datecode)
def run(self): ActServo = QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0)) ActC7 = QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0)) while True: try: self.updHora.emit() self.Ht.setDates() datetime = QDateTime.currentDateTime() #HoraVideo=self.setting.readFile() #print(duration) condicionC1= (datetime.date()==self.Ht.ui.dateTimeC1.date()and\ datetime.time().hour()==self.Ht.ui.dateTimeC1.time().hour()and\ datetime.time().minute()==self.Ht.ui.dateTimeC1.time().minute()and\ datetime.time().second()==self.Ht.ui.dateTimeC1.time().second()) condicionC2=(datetime.date()==self.Ht.ui.dateTimeC2.date()and\ datetime.time().hour()==self.Ht.ui.dateTimeC2.time().hour()and\ datetime.time().minute()==self.Ht.ui.dateTimeC2.time().minute()and\ datetime.time().second()==self.Ht.ui.dateTimeC2.time().second()) condicionC3=(datetime.date()==self.Ht.ui.dateTimeC3.date()and\ datetime.time().hour()==self.Ht.ui.dateTimeC3.time().hour()and\ datetime.time().minute()==self.Ht.ui.dateTimeC3.time().minute()and\ datetime.time().second()==self.Ht.ui.dateTimeC3.time().second()) condicionC4=(datetime.date()==self.Ht.ui.dateTimeC4.date()and\ datetime.time().hour()==self.Ht.ui.dateTimeC4.time().hour()and\ datetime.time().minute()==self.Ht.ui.dateTimeC4.time().minute()and\ datetime.time().second()==self.Ht.ui.dateTimeC4.time().second()) condicionC5=(datetime.date()==self.Ht.ui.dateTimeC5.date()and\ datetime.time().hour()==self.Ht.ui.dateTimeC5.time().hour()and\ datetime.time().minute()==self.Ht.ui.dateTimeC5.time().minute()and\ datetime.time().second()==self.Ht.ui.dateTimeC5.time().second()) if (condicionC1 or condicionC2 or condicionC3 or condicionC4 or condicionC5): ActServo = self.ActDispense(datetime) if (datetime.date() == self.Ht.ui.dateTimeC6.date() and datetime.time().hour() == self.Ht.ui.dateTimeC6.time().hour() and datetime.time().minute() == self.Ht.ui.dateTimeC6.time().minute() and #):#and datetime.time().second() == self.Ht.ui.dateTimeC6.time().second()): ActServo = self.ActDispense(datetime) ActC7 = datetime.addSecs(120) #3600 print(ActC7) if (datetime.date() == ActServo.date() and datetime.time().hour() == ActServo.time().hour() and datetime.time().minute() == ActServo.time().minute() and datetime.time().second() == ActServo.time().second()): print('yes claro') #servito.run() #time.sleep(10) if (datetime.date() == ActC7.date() and datetime.time().hour() == ActC7.time().hour() and datetime.time().minute() == ActC7.time().minute() and datetime.time().second() == ActC7.time().second()): print('Compartimento7') #movMotor.run() self.RechargeReminder.show() # Mostrar pantalla de cargar #time.sleep(10) #GPIO.cleanup() except Exception as e: print(e)
class Task(TaskBase): taskData = DAMGDICT() def __init__(self, taskID=None, taskName=None, taskMode=None, taskType=None, project=None, organisation=None, duetime={}, duedate={}, details={}): super(Task, self).__init__() self.taskID = taskID self.taskName = taskName self.taskMode = taskMode self.taskType = taskType self.project = project self.details = details self.organisation = organisation self.duetime = QTime(duetime['hour'], duetime['minute'], duetime['second']) self.duedate = QDate(duedate['year'], duedate['month'], duedate['day']) self.endDate = QDateTime(self.duedate, self.duetime) self.update() format = self.countter_format() self.timer.timeout.connect(self.update) self.timer.start(format) def update(self): self.startDate = QDateTime(self.date.currentDate(), self.time.currentTime()) self.days = self.startDate.daysTo(self.endDate) self.hours = self.endDate.time().hour() - self.startDate.time().hour() if self.hours <= 0: if self.days > 0: self.days = self.days - 1 self.hours = self.hours + 24 self.minutes = self.endDate.time().minute() - self.startDate.time().minute() if self.minutes <= 0: if self.hours > 0: self.hours = self.hours - 1 self.minutes = self.minutes + 60 self.seconds = self.endDate.time().second() - self.startDate.time().second() if self.seconds <= 0: if self.minutes > 0: self.minutes = self.minutes - 1 self.seconds = self.seconds + 60 self._status = self.get_status() if self.days == 0: if self.hours == 0: if self.minutes == 0: if self.seconds <= 30: pth = os.path.join(SOUND_DIR, 'bell.wav') if not self.play_alarm: playsound(pth) self.play_alarm = True if self.days != 0: hrs = self.hours + self.days*24 else: hrs = self.hours countdown = '{0}:{1}:{2}'.format(hrs, self.minutes, self.seconds) self.countdown.emit(countdown) self._dateline = self.endDate.toString('dd/MM/yy - hh:mm:ss') self._enddate = self.endDate.date().toString('dd/MM/yy') self._endtime = self.endDate.time().toString('hh:mm:ss') self.updateData() def updateData(self): self.taskData.add('name', self.taskName) self.taskData.add('id', self.taskID) self.taskData.add('mode', self.taskMode) self.taskData.add('type', self.taskType) self.taskData.add('project', self.project) self.taskData.add('organisation', self.organisation) self.taskData.add('dateline', self._dateline) self.taskData.add('enddate', self._enddate) self.taskData.add('endtime', self._endtime) self.taskData.add('details', self.details) with open(os.path.join(TASK_DIR, '{0}.task'.format(self.taskID)), 'w') as f: json.dump(self.taskData, f, indent=4) return self.taskData def get_status(self): if self.days < 0: self._status = 'Overdued' elif self.days == 0: if self.hours < 0: self._status = 'Overdued' elif self.hours == 0: if self.minutes <= 0: self._status = 'Overdued' else: self._status = 'Urgent' else: self._status = 'Urgent' elif self.days <= 2: self._status = 'Tomorrow' elif self.days > 2 and self.days < 7: self._status = '{0} days'.format(self.days) elif self.days == 7: self._status = '1 Week' else: self._status = '{0} days'.format(self.days) return self._status def dateline(self): return self._dateline def enddate(self): return self._enddate def endtime(self): return self._endtime # ------------------------------------------------------------------------------------------------------------- # Created by panda on 16/11/2019 - 7:00 PM # © 2017 - 2018 DAMGteam. All rights reserved
def extractProfileCropsterXLS(file, _): res = {} # the interpreted data set book = xlrd.open_workbook(file) sheet_names = book.sheet_names() id_tag_trans = [ "Id-Tag", # EN "ID-Tag", # DE "Etiqueta de identificaci\u00f3n", # ES "N\u00b0 d'identification", # FR "Codice ID", # IT "ID-Tag", # PT "ID-\u0442ег", # RU "ID-Tag", # KO "ID-\u30bf\u30b0", # JP "ID\uff0d\u6807\u7b7e", # CN simplified "\u7de8\u865f\u0020\u002d\u0020\u6a19\u7c64" ] # CN traditional date_trans = [ "Date", # EN "Datum", # DE "Fecha", # ES "Date", # FR "Data", # IT, PT "\u0414\u0430\u0442\u0430", # RU "\ub0a0\uc9dc", # KO "\u65e5\u4ed8", # JP "\u65e5\u671f", # CN simplified "\u65e5\u671f", # CN traditional ] # list of Artisan tags for strings associated to tuple of (fixed) column nr (or Null) and list of tag translations string_tag_labels_trans = [ ( 'beans', 1, [ "Lot name", # EN "Chargenname", # DE "Nombre del lote", # ES "Nom du lot", # FR "Nome lotto", # IT "Nome do lote", # PT "\u0418\u043c\u044f\u0020\u043b\u043e\u0442\u0430", # RU "Lot \uc774\ub984", # KO "\u30ed\u30c3\u30c8\u540d", # JP "\u6279\u6b21\u540d\u79f0", # CN Simplified "\u6279\u6b21\u540d\u7a31", # CN Traditional ]), ( 'title', 2, [ "Profile", # EN "Profil", # DE, FR "Perfil", # ES, pT "Profilo", # IT "\u041f\u0440\u043e\u0444\u0438\u043b\u044c", # RU "\ud504\ub85c\ud30c\uc77c", # KO "\u30d7\u30ed\u30d5\u30a1\u30a4\u30eb", # JP "\u66f2\u7ebf\u6863\u6848", # CN Simplified "\u66f2\u7dda\u6a94\u6848", # CN Traditional ]), ( 'roastertype', 3, [ "Machine", # EN, FR "Maschine", # DE "Tostador", # ES "Macchina", # IT "M\u00e1quina", # PT "\u041c\u0430\u0448\u0438\u043d\u0430", # RU "\uba38\uc2e0", # KO "\u6a5f\u68b0", # JP "\u70d8\u7119\u673a", # CN Simplified "\u70d8\u7119\u6a5f", # CN Traditional ]), ( 'operator', 4, [ "Roast technician", # EN "R\u00f6sttechniker", # DE "T\u00e9cnico de tueste", # ES "Torr\u00e9facteur", # FR "Addetto alla tostatura", # IT "Mestre de torra", # PT "\u041e\u0431\u0436\u0430\u0440\u0449\u0438\u043a", # RU "\ub85c\uc2a4\ud130", # KO "\u30ed\u30fc\u30b9\u30c8\u30c6\u30af\u30cb\u30b7\u30e3\u30f3", # JP "\u70d8\u7119\u5e08", # CN Simplified "\u70d8\u7119\u5e2b", # CN Traditional ]), ( 'cuppingnotes', None, [ "Sensorial notes", # EN "Sensorische Notizen", # DE "Anotaciones sobre el an\u00e1lisis sensorial", # ES "Commentaires sensoriels", # FR "Note sensoriali", # IT "Observa\u00e7\u00f5es sensoriais", # PT "\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f\u0020\u043a\u0020\u0430\u043d\u0430\u043b\u0438\u0437\u0443\u0020\u0432\u043a\u0443\u0441\u043e\u0432\u044b\u0445\u0020\u0445\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a", # RU "\uc13c\uc11c\ub9ac\u0020\uba54\ubaa8", # KO "\u77e5\u899a\u30e1\u30e2", # JP "\u611f\u5b98\u7279\u5f81\u9644\u6ce8", # CN Simplified "\u611f\u5b98\u7279\u5fb5\u9644\u8a3b", # CN Traditional ]), ( 'roastingnotes', None, [ "Roasting notes", # EN "R\u00f6st-Notizen", # DE "Anotaciones sobre el tostado", # ES "Commentaires de torr\u00e9faction", # FR "Note sulla tostatura", # IT "Observa\u00e7\u00f5es da torrefa\u00e7\u00e3o", # PT "\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f\u0020\u043a\u0020\u043e\u0431\u0436\u0430\u0440\u043a\u0435", # RU "\ub85c\uc2a4\ud305\u0020\uba54\ubaa8", # KO "\u30ed\u30fc\u30b9\u30c6\u30a3\u30f3\u30b0\u30ce\u30fc\u30c8", # JP "\u70d8\u7119\u7b14\u8bb0", # CN Simplified "\u70d8\u7119\u7b46\u8a18", # CN Traditional ]) ] ambient_temp_trans = [ "Ambient temp.", # EN "Raumtemp.", # DE "Temperatura ambiente", # ES "Temp. ambiante", # FR, IT, PT "\u0422\u0435\u043c\u043f\u002e\u0020\u043e\u043a\u0440\u0443\u0436\u0430\u044e\u0449\u0435\u0433\u043e\u0020\u0432\u043e\u0437\u0434\u0443\u0445\u0430", # RU "\uc8fc\ubcc0\u0020\uc628\ub3c4", # KO "\u30a2\u30f3\u30d3\u30a8\u30f3\u30c8\u6e29\u5ea6", # JP "\u5ba4\u5185\u6e29\u5ea6", # CN Simplified "\u5ba4\u5167\u6eab\u5ea6", # CN Traditional ] start_weight_trans = [ "Start weight", # EN "Startgewicht", # DE "Peso inicial", # ES, PT "Poids initial", # FR "Peso iniziale", # IT "\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439\u0020\u0432\u0435\u0441", # RU "\uc2dc\uc791\u0020\ubb34\uac8c", # KO "\u958b\u59cb\u91cd\u91cf", # JP "\u5f00\u59cb\u91cd\u91cf", # CN Simplified "\u958b\u59cb\u91cd\u91cf", # CN Traditional ] start_weight_unit_trans = [ "Start weight unit", # EN "Einheit Startgewicht", # DE "Unidad de peso inicial", # ES "Unit\u00e9 poids initial", # FR "Unit\u00e0 peso iniziale", # IT "Unidade do peso inicial", # PT "\u0415\u0434\u0438\u043d\u0438\u0446\u0430\u0020\u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f\u0020\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e\u0020\u0432\u0435\u0441\u0430", # RU "\uc2dc\uc791\u0020\ubb34\uac8c\u0020\ub2e8\uc704", # KO "\u958b\u59cb\u91cd\u91cf\u30e6\u30cb\u30c3\u30c8", # JP "\u5f00\u59cb\u91cd\u91cf\u5355\u4f4d", # CN Simplified "\u958b\u59cb\u91cd\u91cf\u55ae\u4f4d", # CN Traditional ] end_weight_trans = [ "End weight", # EN "Endgewicht", # DE "Peso final", # ES, PT "Poids final", # FR "Peso finale", # IT "\u041a\u043e\u043d\u0435\u0447\u043d\u044b\u0439\u0020\u0432\u0435\u0441", # RU "\uc885\ub8cc\u0020\ubb34\uac8c", # KO "\u958b\u59cb\u91cd\u91cf", # JP "\u7ed3\u675f\u91cd\u91cf", # CN Simplified "\u7d50\u675f\u91cd\u91cf", # CN Traditional ] end_weight_unit_trans = [ "End weight unit", # EN "Einheit Endgewicht", # DE "Unidad de peso final", # ES "Unit\u00e9 poids final", # FR "Unit\u00e0 peso finale", # IT "Unidade de peso final", # PT "\u0415\u0434\u0438\u043d\u0438\u0446\u0430\u0020\u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f\u0020\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e\u0020\u0432\u0435\u0441\u0430", # RU "\uc885\ub8cc\u0020\ubb34\uac8c\u0020\ub2e8\uc704", # KO "\u958b\u59cb\u91cd\u91cf\u30e6\u30cb\u30c3\u30c8", # JP "\u7ed3\u675f\u91cd\u91cf\u5355\u4f4d", # CN Simplified "\u7d50\u675f\u91cd\u91cf\u55ae\u4f4d", # CN Traditional ] turning_point_trans = [ "Turning point", # EN "Wendepunkt", # DE "Temperatura de fondo", # ES "Point de balance", # FR "Punto di flesso", # IT "Temperatura de fundo", # PT "\u041f\u043e\u0432\u043e\u0440\u043e\u0442\u043d\u0430\u044f\u0020\u0442\u043e\u0447\u043a\u0430", # RU "\ud130\ub2dd\u0020\ud3ec\uc778\ud2b8", # KO "\u30bf\u30fc\u30cb\u30f3\u30b0\u30dd\u30a4\u30f3\u30c8", # JP "\u56de\u6e29\u70b9", # CN Simplified "\u56de\u6e29\u9ede", # CN Trraditional ] color_change_trans = [ "Color change", # EN "Farb\u00e4nderung", # DE "Cambio de color", # ES "Changement de couleur", # FR "Cambiamento di colore", # IT "Mudan\u00e7a de cor", # PT "\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u0020\u0446\u0432\u0435\u0442\u0430", # RU "\uc0c9\u0020\ubcc0\ud654", # KO "\u8272\u306e\u5909\u5316", # JP "\u989c\u8272\u53d8\u5316", # CN Simplified "\u984f\u8272\u8b8a\u5316", # CN Traditional ] first_crack_trans = [ "First crack", # EN "1. Crack", # DE "Primer crac", # ES "Premier crack", # FR "Primo Crack", # IT "Primeiro crack", # PT "\u041f\u0435\u0440\u0432\u044b\u0439\u0020\u0442\u0440\u0435\u0441\u043a", # RU "\u0031\ucc28\u0020\ud06c\ub799", # KO "\uff11\u30cf\u30bc", # JP "\u4e00\u7206", # CN Simplified, Traditional ] second_crack_trans = [ "Second crack", # EN, FR "2. Crack", # DE "Segundo crac", # ES "Secondo Crack", # IT "Segundo crack", # PT "\u0412\u0442\u043e\u0440\u043e\u0439\u0020\u0442\u0440\u0435\u0441\u043a", # RU "\u0032\ucc28\u0020\ud06c\ub799", # KO "\uff12\u30cf\u30bc", # JP "\u4e8c\u7206", # CN Simplified, Traditional ] gas_trans = [ "Gas", # EN, DE, ES, IT "Gaz", # FR "G\u00e1s", # PT "\u0413\u0430\u0437", # RU "\uac00\uc2a4", # KO "\u30ac\u30b9", # JP "\u706b\u529b", # CN Timplified, Traditional ] airflow_trans = [ "Airflow", # EN, DE "Flujo de aire", # ES "Arriv\u00e9e d'air", # FR "Flusso d'aria", # IT "Fluxo de ar", # PT "\u0412\u043e\u0437\u0434\u0443\u0448\u043d\u044b\u0439\u0020\u043f\u043e\u0442\u043e\u043a", # RU "\uacf5\uae30\u0020\ud750\ub984", # KO "\u7a7a\u6c17\u306e\u6d41\u308c", # JP "\u98ce\u95e8", # CN Simplified "\u98a8\u9580", # CN Traditional ] comment_trans = [ "Comment", # EN "Kommentar", # DE "Comentar", # ES "Commentaire", # FR "Commento", # IT "Coment\u00e1rio", # PT "\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439", # RU "\ucf54\uba58\ud2b8", # KO "\u30b3\u30e1\u30f3\u30c8", # JP "\u5907\u6ce8", # CN Simplified "\u5099\u8a3b", # CN Traditional ] # standard curves curve_bt_trans = [ "Curve - Bean temp.", # EN "Kurve - Bohnentemp.", # DE "Curva - Temp. del grano", # ES (potentially wrong) "Courbe Temp. grain", # FR "Curva - Temp. chicco", # IT "Curva - Temp. do gr\u00e3o", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0437\u0435\u0440\u0435\u043d", # RU "\ucee4\ube0c\u0020\u002d\u0020\ube48\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u8c46\u306e\u6e29\u5ea6\u3002", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u8c46\u6e29", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u8c46\u6eab", # CH Traditional ] curve_et_trans = [ # not that we map Exhaust to ET and not Env. Temp. as it is available more often; Env. Temp. is mapped to an extra device curve if available "Curve - Exhaust temp.", # EN "Kurve - Ablufttemp.", # DE "Curva - Temp. de salida", # ES (potentially wrong) "Courbe Temp. \u00e9chappement", # FR "Curva - Temp. fumi", # IT "Curva - Temp. de exaust\u00e3o", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u043d\u0430\u0020\u0432\u044b\u0445\u043e\u0434\u0435", # RU "\ucee4\ube0c\u0020\u002d\u0020\ubc30\uae30\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u6392\u6c17\u6e29\u5ea6\u3002", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u6392\u98ce\u6e29", # CN Simplified, Traditional ] # extra temperature curves (C-F conversion applicable) curve_env_temp_trans = [ "Curve - Env. temp.", # EN "Kurve - Umgebungstemp.", # DE "Curva - Temp. ambiente", # ES "Courbe Temp. env.", # FR "Curva - Temp. aria in tamburo", # IT "Curva - Temp. ambiente", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f", # RU "\ucee4\ube0c\u0020\u002d\u0020\uc8fc\ubcc0\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u5468\u56f2\u6e29\u5ea6", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u7089\u6e29", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u7210\u6eab", # CN Traditional ] curve_burner_temp_trans = [ "Curve - Burner temp.", # EN "Kurve - Brennertemp.", # DE "Curva - Temp. del quemador", # ES "Courbe Temp. br\u00fbleur", # FR "Curva - Temp. bruciatore", # IT "Curva - Temp. do queimador", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0433\u043e\u0440\u0435\u043b\u043a\u0438", # RU "\ucee4\ube0c\u0020\u002d\u0020\ubc84\ub108\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30d0\u30fc\u30ca\u30fc\u6e29\u5ea6", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u71c3\u70df\u5668\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u71c3\u7159\u5668\u6eab\u5ea6", # CN Traditional ] curve_other_temp_trans = [ "Curve - Other temp.", # EN "Kurve - Andere Temp.", # DE "Curva - Otras temperaturas", # ES "Courbe Temp. autre", # FR "Curva - Altra temp.", # IT "Curva - Outra temp.", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0414\u0440\u0443\u0433\u0430\u044f\u0020\u0442\u0435\u043c\u043f.", # RU "\ucee4\ube0c\u0020\u002d\u0020\uae30\ud0c0\u0020\uc628\ub3c4\u002e", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u4ed6\u306e\u6e29\u5ea6", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u5176\u5b83\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u5176\u5b83\u6eab\u5ea6", # CN Traditional ] curve_stack_temp_trans = [ "Curve - Stack temp.", # EN "Kurve - Schornsteintemp.", # DE "Curva - Temp. del tiro", # ES "Courbe Temp. broche", # FR "Curva - Temp. camino", # IT "Curva - Temp. do escoamento de", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0432\u0020\u0434\u044b\u043c\u043e\u0432\u043e\u0439\u0020\u0442\u0440\u0443\u0431\u0435", # RU "\ucee4\ube0c\u0020\u002d\u0020\uc2a4\ud0dd\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30b9\u30bf\u30c3\u30af\u6e29\u5ea6", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u70df\u56f1\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u7159\u56ea\u6eab\u5ea6", # CN Traditional ] curve_return_temp_trans = [ "Curve - Return temp.", # EN "Kurve - R\u00fccklauftemp.", # DE "Curva - Temp. de retorno", # ES "Courbe Temp. retour", # FR "Curva - Temp. di ritorno", # IT "Curva - Temperatura de Retorno", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430", # RU "\ucee4\ube0c\u0020\u002d\u0020\ubc30\uae30\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u623b\u308a\u6e29\u5ea6\u3002", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u7a7a\u6c14\u56de\u7089\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u7a7a\u6c23\u56de\u7210\u6eab\u5ea6", # CN Traditional ] curve_inlet_temp_trans = [ "Curve - Inlet temp.", # EN "Kurve - Einlasstemp.", # DE "Curva - Temp. de entrada", # ES "Courbe Temp. entr\u00e9e", # FR "Curva - Temp. in ingresso", # IT "Curva - Temp. do ar de entrada", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u043d\u0430\u0020\u0432\u0445\u043e\u0434\u0435", # RU "\ucee4\ube0c\u0020\u002d\u0020\ud761\uae30\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u5438\u6c17\u53e3\u6e29\u5ea6", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u8fdb\u98ce\u6e29", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u9032\u98a8\u6eab", # CN Traditional ] curve_afterburner_temp_trans = [ "Curve - Afterburner temp.", # EN "Kurve - Nachbrennertemp.", # DE "Curva - Temp. del posquemador", # ES "Courbe Temp. post-combustion", # FR "Curva - Temp. bruciafumi", # IT "Curva - Temp. p\u00f3s-combust\u00e3o", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0432\u0020\u0444\u043e\u0440\u0441\u0430\u0436\u043d\u043e\u0439\u0020\u043a\u0430\u043c\u0435", # RU "\ucee4\ube0c\u0020\u002d\u0020\uc560\ud504\ud130\ubc84\ub108\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30a2\u30d5\u30bf\u30fc\u30d0\u30fc\u30ca\u30fc\u6e29\u5ea6\u3002", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u540e\u7f6e\u71c3\u70df\u5668\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u5f8c\u7f6e\u71c3\u7159\u5668\u6eab\u5ea6", # CN Traditional ] curve_drum_temp_trans = [ "Curve - Drum temp.", # EN "Kurve - Trommeltemp.", # DE "Curva - Temp. del Tambor", # EE "Courbe Temp. tambour", # FR "Curva - Temp. tamburo", # IT "Curva - Temperatura do Tambor", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020\u0431\u0430\u0440\u0430\u0431\u0430\u043d\u0430", # RU "\ucee4\ube0c\u0020\u002d\u0020\ub4dc\ub7fc\u0020\uc628\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30c9\u30e9\u30e0\u6e29\u5ea6\u3002", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u9505\u7089\u6e29\u5ea6", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u934b\u7210\u6eab\u5ea6", # CN Traditional ] # extra non-temperature curves (no temperature conversion) curve_gas_control_trans = [ "Curve - Gas control", # EN "Kurve - Gas-Kontrolle", # DE "Curva - Control del gas", # ES "Courbe R\u00e9gulation du d\u00e9bit de g", # FR "Curva - Controllo gas", # IT "Curva - Controle de g\u00e1s", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u0020\u0433\u0430\u0437\u043e\u043c", # RU "\ucee4\ube0c\u0020\u002d\u0020\uac00\uc2a4\u0020\uc81c\uc5b4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30ac\u30b9\u30b3\u30f3\u30c8\u30ed\u30fc\u30eb", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u706b\u529b\u63a7\u5236", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u706b\u529b\u63a7\u5236", # CN Traditional ] curve_drum_speed_trans = [ "Curve - Drum speed", # EN "Kurve - Trommelgeschw.", # DE "Curva - Velocidad del tambor", # ES "Courbe Vitesse du tambour", # FR "Curva - Velocit\u00e0 tamburo", # IT "Curva - Velocidade do tambor", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u0020\u0431\u0430\u0440\u0430\u0431\u0430\u043d\u0430", # RU "\ucee4\ube0c\u0020\u002d\u0020\ub4dc\ub7fc\u0020\uc18d\ub3c4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30c9\u30e9\u30e0\u30b9\u30d4\u30fc\u30c9", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u8f6c\u901f", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u8f49\u901f", # CN Traditional ] curve_airflow_trans = [ "Curve - Airflow", # EN "Kurve - Airflow", # DE "Curva - Flujo de aire", # ES "Courbe Arriv\u00e9e d'air", # FR "Curva - Flusso d'aria", # IT "Curva - Fluxo de ar", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0412\u043e\u0437\u0434\u0443\u0448\u043d\u044b\u0439\u0020\u043f\u043e\u0442\u043e\u043a", # RU "\ucee4\ube0c\u0020\u002d\u0020\uacf5\uae30\u0020\ud750\ub984", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u7a7a\u6c17\u306e\u6d41\u308c", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u98ce\u95e8", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u98a8\u9580", # CN Traditional ] curve_gas_trans = [ "Curve - Gas", # EN "Kurve - Gas", # DE "Curva - Gas", # ES "Courbe Gaz", # FR "Curva - Gas", # IT "Curva - G\u00e1s", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0413\u0430\u0437", # RU "\ucee4\ube0c\u0020\u002d\u0020\uac00\uc2a4", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30ac\u30b9", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u706b\u529b", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u706b\u529b", # CN Traditional ] # curve_gas_comments_trans = [ # "Curve - Gas comments", # EN # "Kurve - Kommentare Gas", # DE # "Curva - Comentarios sobre el gas", # ES # "Courbe Commentaires de type Gaz", # FR # "Curva - Commenti sul Gas", # IT # "Curva - Coment\u00e1rios do g\u00e1s", # PT # "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u041a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438\u0020\u043f\u043e\u0020\u043f\u043e\u0432\u043e\u0434\u0443", # RU # "\ucee4\ube0c\u0020\u002d\u0020\uac00\uc2a4\u0020\ucf54\uba58\ud2b8", # KO # "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30ac\u30b9\u306b\u3064\u3044\u3066\u306e\u30b3\u30e1\u30f3\u30c8", # JP # "\u66f2\u7ebf\u0020\u002d\u0020\u706b\u529b\u5907\u6ce8", # CN Simplified # "\u66f2\u7dda\u0020\u002d\u0020\u706b\u529b\u5099\u8a3b", # CN Traditional # ] curve_drum_pressure_trans = [ "Curve - Drum pressure", # EN "Kurve - Trommeldruck", # DE "Curva - Presi\u00f3n del tambor", # ES "Courbe Pression du tambour", # FR "Curva - Pressione tamburo", # IT "Curva - Press\u00e3o do tambor", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0414\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u0020\u0432\u0020\u0431\u0430\u0440\u0430\u0431\u0430\u043d\u0435", # RU "\ucee4\ube0c\u0020\u002d\u0020\ub4dc\ub7fc\u0020\uc555\ub825", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u30c9\u30e9\u30e0\u5727\u529b", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u7089\u538b", # CN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u7210\u58d3", # CN Traditional ] curve_airflow_control_trans = [ "Curve - Airflow control", # EN "Kurve - Airflow-Steuerung", # DE "Curva - Regulaci\u00f3n del caudal de aire", # ES "Courbe Contr\u00f4le de la ventilati", # FR "Curva - Controllo del flusso d'", # IT: "Curva - Controllo del flusso d'aria" "Curva - Controle de fluxo de ar", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u041a\u043e\u043d\u0442\u0440\u043e\u043b\u044c\u0020\u0432\u043e\u0437\u0434\u0443\u0448\u043d\u043e\u0433\u043e\u0020\u043f\u043e", # RU "\ucee4\ube0c\u0020\u002d\u0020\u0041\u0069\u0072\u0066\u006c\u006f\u0077\u0020\u0063\u006f\u006e\u0074\u0072\u006f\u006c", # KO "\u30ab\u30fc\u30d6\u0020\u002d\u0020\u7a7a\u6c17\u306e\u6d41\u308c\u306e\u7ba1\u7406", # JP "\u66f2\u7ebf\u0020\u002d\u0020\u98ce\u95e8\u63a7\u5236", # SN Simplified "\u66f2\u7dda\u0020\u002d\u0020\u0041\u0069\u0072\u0066\u006c\u006f\u0077\u0020\u0063\u006f\u006e\u0074\u0072\u006f\u006c", # SN Traditional ] curve_fan_speed_trans = [ "Curve - fanSpeed", # EN "Kurve - fanSpeed", # DE #"Curva - Velocidad del ventilador", # ES "Courbe fanSpeed", # FR "Curva - fanSpeed", # IT, ES "Curva - fanSpeed", # PT "\u041a\u0440\u0438\u0432\u0430\u044f - fanSpeed", # RU "\ucee4\ube0c - fanSpeed", # KO "\u30ab\u30fc\u30d6 - fanSpeed", # JP "\u66f2\u7ebf - fanSpeed", # CN Simplified "\u66f2\u7dda - fanSpeed", # CN Traditional ] #### extra_temp_curve_trans = \ curve_env_temp_trans + \ curve_burner_temp_trans + \ curve_other_temp_trans + \ curve_stack_temp_trans + \ curve_return_temp_trans + \ curve_inlet_temp_trans + \ curve_afterburner_temp_trans + \ curve_drum_temp_trans extra_nontemp_curve_trans = \ curve_gas_control_trans + \ curve_drum_speed_trans + \ curve_airflow_trans + \ curve_gas_trans + \ curve_drum_pressure_trans + \ curve_airflow_control_trans + \ curve_fan_speed_trans #curve_gas_comments_trans curve_prefixa = [ # Curve + Temp "Curva - Temp.", # ES (potentially wrong) "Courbe Temp.", # FR "Curva - Temp.", # IT "Curva - Temp.", # PT "\u041a\u0440\u0438\u0432\u0430\u044f\u0020\u002d\u0020\u0422\u0435\u043c\u043f\u002e\u0020", # RU # just Curve "Curve -", # EN "Kurve -", # DE "Curva -", # ES, IT, PT "Courbe", # FR "\u041a\u0440\u0438\u0432\u0430\u044f -", # RU "\ucee4\ube0c -", # KO "\u30ab\u30fc\u30d6 -", # JP "\u66f2\u7ebf -", # CN Simplified "\u66f2\u7dda -", # CN Traditional ] curve_postfixa = [ "temp.", # EN "temp.", # DE "\u0020\uc628\ub3c4", # KO "\u6e29\u5ea6\u3002", # JP "\u6e29\u5ea6", # CN Simplified & Tranitional ] ########## # extract general profile information general_sh = book.sheet_by_index(0) if general_sh.nrows >= 1: row1 = general_sh.row(1) general_data = dict(zip([x.value for x in general_sh.row(0)], row1)) res["samplinginterval"] = 1.0 try: id_tag_value = None # try to find the "Id-Tag" value # 1. test the column name in all known translations for tag in id_tag_trans: if tag in general_data: id_tag_value = general_data[tag].value break # 2. take the first value of row1 if id_tag_value is None and len(row1) > 0: id_tag_value = row1[0].value if id_tag_value is not None: batch_prefix = id_tag_value.rstrip('0123456789') batch_number = int(id_tag_value[len(batch_prefix):]) res["roastbatchprefix"] = batch_prefix res["roastbatchnr"] = batch_number except: pass for (tag, pos, trans) in string_tag_labels_trans: value = None try: # 1. test the column name in all known translations for tr in trans: if tr in general_data: value = general_data[tr].value break # 2. take the pos column value of row1 if value is None and pos is not None and len(row1) > pos: value = row1[pos].value if value is not None: res[tag] = encodeLocal(value) except: pass try: date_tag_value = None # try to find the "Date" value # 1. test the column name in all known translations for tag in date_trans: if tag in general_data: date_tag_value = general_data[tag].value break # 2. take the first value of row1 if date_tag_value is None: date_tag_value = row1[6].value if date_tag_value is not None: date_tuple = xlrd.xldate_as_tuple(date_tag_value, book.datemode) date = QDateTime(*date_tuple) if date.isValid(): res["roastdate"] = encodeLocal(date.date().toString()) res["roastisodate"] = encodeLocal(date.date().toString( Qt.ISODate)) res["roasttime"] = encodeLocal(date.time().toString()) res["roastepoch"] = int(date.toTime_t()) res["roasttzoffset"] = libtime.timezone except: pass try: ambient_tag_value = None # try to find the "Date" value # test the column name in all known translations for tag in ambient_temp_trans: if tag in general_data: ambient_tag_value = general_data[tag].value break if ambient_tag_value is None and len(row1) > 27: ambient_tag_value = row1[27] if ambient_tag_value is not None: res['ambientTemp'] = float(ambient_tag_value) except: pass try: start_weight_tag_value = None start_weight_unit_tag_value = None end_weight_tag_value = None end_weight_unit_tag_value = None # try to find the "Start weight" value # test the column name in all known translations for tag in start_weight_trans: if tag in general_data: start_weight_tag_value = general_data[tag].value break if start_weight_tag_value is None and len(row1) > 9: start_weight_tag_value = row1[9] # try to find the "Start weight unit" value # test the column name in all known translations for tag in start_weight_unit_trans: if tag in general_data: start_weight_unit_tag_value = general_data[tag].value break if start_weight_unit_tag_value is None and len(row1) > 10: start_weight_unit_tag_value = row1[10] # try to find the "End weight" value # test the column name in all known translations for tag in end_weight_trans: if tag in general_data: end_weight_tag_value = general_data[tag].value break if end_weight_tag_value is None and len(row1) > 11: end_weight_tag_value = row1[11] # try to find the "End weight unit" value # test the column name in all known translations for tag in end_weight_unit_trans: if tag in general_data: end_weight_unit_tag_value = general_data[tag].value break if end_weight_unit_tag_value is None and len(row1) > 12: end_weight_unit_tag_value = row1[12] if start_weight_tag_value is not None and end_weight_tag_value is not None: cropster_weight_units = ["G", "KG", "LBS", "OZ"] artisan_weight_units = ["g", "Kg", "lb", "oz"] weight = [0, 0, artisan_weight_units[0]] try: if end_weight_unit_tag_value is not None: idx = cropster_weight_units.index( end_weight_unit_tag_value) weight[2] = artisan_weight_units[idx] except: pass try: if start_weight_unit_tag_value: idx = cropster_weight_units.index( start_weight_unit_tag_value) weight[2] = artisan_weight_units[idx] except: pass try: if start_weight_tag_value is not None: weight[0] = start_weight_tag_value except: pass try: if end_weight_tag_value is not None: weight[1] = end_weight_tag_value except: pass res["weight"] = weight except: pass res["timex"] = [] res["temp1"] = [] res["temp2"] = [] # BT: BT_idx = None ET_idx = None try: for i, sn in enumerate(sheet_names): if sn in curve_bt_trans: BT_idx = i BT_sh = book.sheet_by_index(BT_idx) if BT_sh.ncols >= 1: time = BT_sh.col(0) temp = BT_sh.col(1) if len(time) > 0 and len(temp) > 0 and len(time) == len( temp): if "FAHRENHEIT" in str(temp[0].value): res["mode"] = 'F' else: res["mode"] = 'C' res["timex"] = [t.value for t in time[1:]] res["temp2"] = [t.value for t in temp[1:]] res["temp1"] = [-1] * len(res["timex"]) res["timeindex"] = [ 0, 0, 0, 0, 0, 0, len(res["timex"]) - 1, 0 ] break except: pass # ET try: for et_trans in [ curve_env_temp_trans, curve_et_trans, curve_return_temp_trans, curve_burner_temp_trans ]: for i, sn in enumerate(sheet_names): if sn in et_trans: ET_idx = i ET_sh = book.sheet_by_index(ET_idx) if ET_sh.ncols >= 1: time = ET_sh.col(0) temp = ET_sh.col(1) if len(time) > 0 and len(temp) > 0 and len( time) == len(temp): if "FAHRENHEIT" in str(temp[0].value): res["mode"] = 'F' else: res["mode"] = 'C' res["temp1"] = [t.value for t in temp[1:]] if len(res["timex"]) != len(res["temp1"]): res["timex"] = [t.value for t in time[1:]] if "temp2" not in res or len(res["temp2"]) != len( res["timex"]): res["temp2"] = [-1] * len(res["timex"]) res["timeindex"] = [ 0, 0, 0, 0, 0, 0, len(res["timex"]) - 1, 0 ] break if ET_idx is not None: break except: pass # extra temperature curves (only if ET or BT and its corresponding timex was already parsed successfully) if len(res["timex"]) > 0: channel = 1 # toggle between channel 1 and 2 to be filled with extra temperature curve data for CT_idx, sn in enumerate(sheet_names): sn = sn.strip() if CT_idx != BT_idx and CT_idx != ET_idx: # all but temp and non-temp curves but for the already processed ET and BT curves if sn in extra_temp_curve_trans: temp_curve = True elif sn in extra_nontemp_curve_trans: temp_curve = False else: continue try: extra_curve_name = sn # we split of the "Curve -" prefix for px in curve_prefixa: if extra_curve_name.startswith(px): sp = extra_curve_name.split(px) if len(sp) > 1: extra_curve_name = sp[1] else: extra_curve_name = sp[0] extra_curve_name = extra_curve_name.strip() break # we split of also the "temp." postfix for px in curve_postfixa: if extra_curve_name.endswith(px): extra_curve_name = extra_curve_name.split( px)[0].strip() break CT_sh = book.sheet_by_index(CT_idx) if CT_sh.ncols >= 1: time = CT_sh.col(0) temp = CT_sh.col(1) if len(time) > 0 and len(temp) > 0 and len( time) == len(temp): if "extradevices" not in res: res["extradevices"] = [] if "extraname1" not in res: res["extraname1"] = [] if "extraname2" not in res: res["extraname2"] = [] if "extratimex" not in res: res["extratimex"] = [] if "extratemp1" not in res: res["extratemp1"] = [] if "extratemp2" not in res: res["extratemp2"] = [] if "extramathexpression1" not in res: res["extramathexpression1"] = [] if "extramathexpression2" not in res: res["extramathexpression2"] = [] if "extraNoneTempHint1" not in res: res["extraNoneTempHint1"] = [] if "extraNoneTempHint2" not in res: res["extraNoneTempHint2"] = [] if channel == 1: channel = 2 if temp_curve: # apply temp conversion res["extraNoneTempHint1"].append(False) else: # no temp conversion res["extraNoneTempHint1"].append(True) res["extradevices"].append( 25) # Virtual Device res["extraname1"].append( encodeLocal(extra_curve_name)) res["extratimex"].append( [t.value for t in time[1:]]) res["extratemp1"].append( [t.value for t in temp[1:]]) res["extramathexpression1"].append("") elif (len(time) - 1) == len( res["extratimex"][-1] ): # only if time lengths is same as of channel 1 channel = 1 if temp_curve: # apply temp conversion res["extraNoneTempHint2"].append(False) else: # no temp conversion res["extraNoneTempHint2"].append(True) res["extraname2"].append( encodeLocal(extra_curve_name)) res["extratemp2"].append( [t.value for t in temp[1:]]) res["extramathexpression2"].append("") except: pass if "extraname1" in res and "extraname2" in res and len( res["extraname1"]) != len(res["extraname2"]): # we add an empty second extra channel if needed res["extraname2"].append("Extra 2") res["extratemp2"].append([-1] * len(res["extratemp1"][-1])) res["extraNoneTempHint2"].append(True) res["extramathexpression2"].append("") # add events try: COMMENTS_idx = 1 try: sheet_names.index("Comments") except: pass COMMENTS_sh = book.sheet_by_index(COMMENTS_idx) gas_event = False # set to True if a Gas event exists airflow_event = False # set to True if an Airflow event exists specialevents = [] specialeventstype = [] specialeventsvalue = [] specialeventsStrings = [] if COMMENTS_sh.ncols >= 4: takeClosest = lambda num, collection: min( collection, key=lambda x: abs(x - num)) for r in range(COMMENTS_sh.nrows): if r > 0: try: time = COMMENTS_sh.cell(r, 0).value comment_type = COMMENTS_sh.cell(r, 2).value.strip() if comment_type not in turning_point_trans: # TP is ignored as it is automatically assigned comment_value = COMMENTS_sh.cell(r, 3).value c = takeClosest(time, res["timex"]) timex_idx = res["timex"].index(c) if comment_type in color_change_trans: res["timeindex"][1] = timex_idx elif comment_type in first_crack_trans: res["timeindex"][2] = timex_idx elif comment_type == "First crack end": res["timeindex"][3] = timex_idx elif comment_type in second_crack_trans: res["timeindex"][4] = timex_idx elif comment_type == "Second crack end": res["timeindex"][5] = timex_idx elif comment_type == "Duration": res["timeindex"][6] = timex_idx else: specialevents.append(timex_idx) ae = False ge = False if comment_type in airflow_trans: ae = True airflow_event = True specialeventstype.append(0) elif comment_type in gas_trans: ge = True gas_event = True specialeventstype.append(3) else: specialeventstype.append(4) try: v = float(comment_value) v = v / 10. + 1 specialeventsvalue.append(v) except: specialeventsvalue.append(0) if not ae and not ge and comment_type not in comment_trans: specialeventsStrings.append( encodeLocal(comment_type)) else: specialeventsStrings.append( encodeLocal(comment_value)) except: pass if len(specialevents) > 0: res["specialevents"] = specialevents res["specialeventstype"] = specialeventstype res["specialeventsvalue"] = specialeventsvalue res["specialeventsStrings"] = specialeventsStrings if gas_event or airflow_event: # first set etypes to defaults res["etypes"] = [ QApplication.translate("ComboBox", "Air", None), QApplication.translate("ComboBox", "Drum", None), QApplication.translate("ComboBox", "Damper", None), QApplication.translate("ComboBox", "Burner", None), "--" ] # update if airflow_event: res["etypes"][0] = "Airflow" if gas_event: res["etypes"][3] = "Gas" except: # import traceback # import sys # traceback.print_exc(file=sys.stdout) pass return res
def extractProfilePetronciniCSV(file, _): res = {} # the interpreted data set res["samplinginterval"] = 1.0 csvFile = io.open(file, 'r', newline="", encoding='utf-8') data = csv.reader(csvFile, delimiter=';') #read file header next(data) # skip "Export path" next(data) # skip path header = [i.strip() for i in next(data)] roast_date = None power = None # holds last processed heater event value power_last = None # holds the heater event value before the last one power_event = False # set to True if a heater event exists specialevents = [] specialeventstype = [] specialeventsvalue = [] specialeventsStrings = [] timex = [] temp1 = [] # outlet temperature as ET temp2 = [] # bean temperature extra1 = [] # inlet temperature extra2 = [] # burner percentage timeindex = [ -1, 0, 0, 0, 0, 0, 0, 0 ] #CHARGE index init set to -1 as 0 could be an actal index used i = 0 for row in data: if row == []: continue i = i + 1 items = list(zip(header, row)) item = {} for (name, value) in items: item[name] = value.strip() # take i as time in seconds timex.append(i) # extract roast_date if roast_date is None and 'Year' in item and 'Month' in item and 'Day' in item and 'Hour' in item and 'Minute' in item and 'Second' in item: try: date = QDate(int(item['Year']), int(item['Month']), int(item['Day'])) time = QTime(int(item['Hour']), int(item['Minute']), int(item['Second'])) roast_date = QDateTime(date, time) except: passs # if 'Outlet Temperature' in item: temp1.append(float(item['Outlet Temperature'])) else: temp1.append(-1) if 'Beans Temperature' in item: temp2.append(float(item['Beans Temperature'].replace(",", "."))) else: temp2.append(-1) # mark CHARGE if not timeindex[0] > -1: timeindex[0] = i # mark DROP if timeindex[0] > -1 and i > 0: timeindex[6] = i - 1 # add ror, power, speed and pressure if 'Inlet Temperature' in item: extra1.append(float(item['Inlet Temperature'])) else: extra1.append(-1) if 'Burner Percentage' in item: extra2.append(float(item['Burner Percentage'])) else: extra2.append(-1) if "Burner Percentage" in item: try: v = float(item["Burner Percentage"]) if v != power: # power value changed if v == power_last: # just a fluctuation, we remove the last added power value again power_last_idx = next( i for i in reversed(range(len(specialeventstype))) if specialeventstype[i] == 3) del specialeventsvalue[power_last_idx] del specialevents[power_last_idx] del specialeventstype[power_last_idx] del specialeventsStrings[power_last_idx] power = power_last power_last = None else: power_last = power power = v power_event = True v = v / 10. + 1 specialeventsvalue.append(v) specialevents.append(i) specialeventstype.append(3) specialeventsStrings.append(item["power"] + "%") else: power_last = None except Exception: pass csvFile.close() res["timex"] = timex res["temp1"] = replace_duplicates(temp1) res["temp2"] = replace_duplicates(temp2) res["timeindex"] = timeindex res["extradevices"] = [25] res["extratimex"] = [timex[:]] res["extraname1"] = ["IT"] res["extratemp1"] = [extra1] res["extramathexpression1"] = [""] res["extraname2"] = ["burner"] res["extratemp2"] = [replace_duplicates(extra2)] res["extramathexpression2"] = [""] # set date if roast_date is not None and roast_date.isValid(): res["roastdate"] = encodeLocal(roast_date.date().toString()) res["roastisodate"] = encodeLocal(roast_date.date().toString( Qt.ISODate)) res["roasttime"] = encodeLocal(roast_date.time().toString()) res["roastepoch"] = int(roast_date.toTime_t()) res["roasttzoffset"] = libtime.timezone if len(specialevents) > 0: res["specialevents"] = specialevents res["specialeventstype"] = specialeventstype res["specialeventsvalue"] = specialeventsvalue res["specialeventsStrings"] = specialeventsStrings if power_event or speed_event: # first set etypes to defaults res["etypes"] = [ QApplication.translate("ComboBox", "Air", None), QApplication.translate("ComboBox", "Drum", None), QApplication.translate("ComboBox", "Damper", None), QApplication.translate("ComboBox", "Burner", None), "--" ] return res
def format_date(date: QDateTime): if date.date() == QDate.currentDate(): return date.time().toString("hh:mm") else: return date.toString("ddd, MMMM d hh:mm ap")
def extremum(pair, profit_buy_to_sell, profit_sell_to_buy): date = QDateTime(2000, 1, 1, 0, 0, 0) list_extremum = load_from_file(SAVE_PATH_EXTREMUM + '/' + pair + '_' + str(profit_buy_to_sell) + '_' + str(profit_sell_to_buy) + '.data') old_list_extremum = [] while True: if len(list_extremum) % 2 == 1: list_extremum = list_extremum[:-1] list_extremum = list_extremum[:-2] old_buy, old_sell = [], [] if list_extremum: date = unixdate_to_qdate(list_extremum[-1]['date']) while date.date() <= QDate.currentDate(): all_trades = load_history_data(pair, date, date) if all_trades: last_trade = all_trades[-1] if date.date() == QDate.currentDate(): all_trades += DownLoadTrades().load_data_in_Exmo( pair, [last_trade]) for item in all_trades: if list_extremum: if item['trade_id'] > list_extremum[-1]['trade_id']: if item['type'] == "buy": # buy if len(list_extremum) % 2 == 1: if float(list_extremum[-1]['price']) > float( item['price']): list_extremum[-1] = item.copy() # print('B_ED', float(item['price'])) else: if (1 - float(item['price']) / float(list_extremum[-1]['price']) ) * 100 >= profit_sell_to_buy: if (old_buy and float(old_buy['price']) > float( item['price'])) or not old_buy: # print('B_AD', float(item['price'])) list_extremum.append(item) old_buy, old_sell = [], [] else: # sell if len(list_extremum) % 2 == 1: if (float(item['price']) / float(list_extremum[-1]['price']) - 1) * 100 >= profit_buy_to_sell: # print('S_AD', float(item['price'])) list_extremum.append(item) elif len(list_extremum) > 2 and float( item['price']) > float( list_extremum[-2]['price']): # print('S_Del_B', float(item['price'])) old_buy = list_extremum[-1].copy() old_sell = list_extremum[-2].copy() list_extremum[-2] = item.copy() list_extremum = list_extremum[:-1] else: if old_buy and (float(item['price']) / float(old_buy['price']) - 1) * 100 >= profit_buy_to_sell: # print('S_Add_B', float(item['price'])) list_extremum[-1] = old_sell.copy() list_extremum.append(old_buy) list_extremum.append(item) old_buy, old_sell = [], [] elif float(list_extremum[-1]['price']) < float( item['price']): # print('S_ED', float(item['price'])) list_extremum[-1] = item.copy() else: if item['type'] == "buy": list_extremum.append(item) date = date.addDays(1) try: result = old_list_extremum[-1] == list_extremum[-1] except: result = False if not result: if not os.path.exists(SAVE_PATH_EXTREMUM): os.makedirs(SAVE_PATH_EXTREMUM) save_to_file( SAVE_PATH_EXTREMUM + '/' + pair + '_' + str(profit_buy_to_sell) + '_' + str(profit_sell_to_buy) + '.data', list_extremum) return {'change_data': not result, 'data': list_extremum}