示例#1
0
    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)
示例#2
0
    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)
示例#3
0
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))
示例#4
0
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()
示例#5
0
    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)))
示例#6
0
    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)
示例#7
0
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
示例#8
0
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)
示例#9
0
文件: DT.py 项目: nerohmot/Semi-ATE
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)
示例#10
0
    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)
示例#11
0
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
示例#12
0
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
示例#13
0
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
示例#14
0
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")
示例#15
0
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}