Example #1
0
def addRoast(roast_record=None):
    global queue
    try:
        config.logger.info("queue:addRoast()")
        if roast_record == None:
            r = roast.getRoast()
        else:
            r = roast_record
        # if modification date is not set yet, we add the current time as modified_at timestamp as float EPOCH with millisecond
        if not "modified_at" in r:
            r["modified_at"] = util.epoch2ISO8601(time.time())
        config.logger.debug("queue: -> roast: %s", r)
        # check if all required data is available before queueing this up
        if "roast_id" in r and r["roast_id"] and \
           (roast_record is not None or ("date" in r and r["date"] and "amount" in r)): # amount can be 0 but has to be present
            # put in upload queue
            config.logger.debug("queue: -> put in queue")
            config.app_window.sendmessage(
                QApplication.translate(
                    "Plus", "Queuing roast for upload to artisan.plus",
                    None))  # @UndefinedVariable
            queue.put({"url": config.roast_url, "data": r, "verb": "POST"})
            config.logger.debug("queue: -> roast queued up")
            config.logger.debug("queue: -> qsize: %s", queue.qsize())
            sync.setSyncRecordHash(r)
        else:
            config.logger.debug(
                "queue: -> roast not queued as mandatory info missing")
    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error("queue: Exception in addRoast() in line %s: %s",
                            exc_tb.tb_lineno, e)
Example #2
0
def getRoast():
    d = {}
    try:
        config.logger.debug("roast:getRoast()")
        aw = config.app_window
        p = aw.getProfile()

        d = getTemplate(p)

        # id => roast_id
        if "id" in d:
            d["roast_id"] = d["id"]
            del d["id"]

        # start_weight => amount
        if "start_weight" in d:
            d["amount"] = d["start_weight"]
            del d["start_weight"]
        else:
            d["amount"] = 0

        if "computed" in p:
            cp = p["computed"]
            util.addNum2dict(cp, "det", d, "CM_ETD", 0, 100, 1)
            util.addNum2dict(cp, "dbt", d, "CM_BTD", 0, 100, 1)

        if aw.qmc.plus_store:
            d["location"] = aw.qmc.plus_store
        if aw.qmc.plus_coffee:
            d["coffee"] = aw.qmc.plus_coffee
        else:
            d["coffee"] = None
        if aw.qmc.plus_blend_spec:
            d["blend"] = aw.qmc.plus_blend_spec
        else:
            d["blend"] = None

        util.addTemp2dict(p, "ambientTemp", d, "temperature")
        util.addNum2dict(p, "ambient_pressure", d, "pressure", 800, 1200, 1)
        util.addNum2dict(p, "ambient_humidity", d, "humidity", 0, 100, 1)

        util.addString2dict(p, "roastingnotes", d, "notes", 1023)

        if aw.qmc.background and aw.qmc.backgroundprofile:
            bp = aw.qmc.backgroundprofile
            template = getTemplate(bp)
            d["template"] = template

        # if profile is already saved, that modification date is send along to the server instead the timestamp
        # of the moment the record is queued
        if not aw.curFile is None:
            d["modified_at"] = util.epoch2ISO8601(
                util.getModificationDate(aw.curFile))

    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error("roast: Exception in getRoast() line %s: %s",
                            exc_tb.tb_lineno, e)
    return d
Example #3
0
def getTemplate(bp):
    config.logger.debug("roast:getTemplate()")
    d = {}
    try:
        aw = config.app_window

        util.addNum2dict(bp, "roastbatchnr", d, "batch_number", 0, 65534, 0)
        if "batch_number" in d and d["batch_number"]:
            util.addString2dict(bp, "roastbatchprefix", d, "batch_prefix", 50)
            util.addNum2dict(bp, "roastbatchpos", d, "batch_pos", 0, 255, 0)

        if "roastepoch" in bp:
            d["date"] = util.epoch2ISO8601(bp["roastepoch"])
            try:
                gmt_offset = util.limitnum(-60000, 60000, util.getGMToffset())
                if gmt_offset is not None:
                    d["GMT_offset"] = gmt_offset
            except:
                pass

        if "weight" in bp:
            if bp["weight"][0]:
                try:
                    w = util.limitnum(
                        0, 65534,
                        aw.convertWeight(
                            bp["weight"][0],
                            aw.qmc.weight_units.index(bp["weight"][2]),
                            aw.qmc.weight_units.index("Kg")))
                    if w is not None:
                        d["start_weight"] = util.float2floatMin(w, 3)  # in kg
                except:
                    pass
            if bp["weight"][1]:
                try:
                    w = util.limitnum(
                        0, 65534,
                        aw.convertWeight(
                            bp["weight"][1],
                            aw.qmc.weight_units.index(bp["weight"][2]),
                            aw.qmc.weight_units.index("Kg")))
                    if w is not None:
                        d["end_weight"] = util.float2floatMin(w, 3)  # in kg
                except:
                    pass

        if "density_roasted" in bp:
            if bp["density_roasted"][0]:
                try:
                    n = util.limitnum(0, 1000, bp["density_roasted"][0])
                    if n is not None:
                        d["density_roasted"] = util.float2floatMin(n, 1)
                except:
                    pass

        util.add2dict(bp, config.uuid_tag, d, "id")
        util.addNum2dict(bp, "moisture_roasted", d, "moisture", 0, 100, 1)
        util.addString2dict(bp, "title", d, "label", 255)
        util.addString2dict(bp, "roastertype", d, "machine", 50)
        util.addString2dict(bp, "machinesetup", d, "setup", 50)
        util.addNum2dict(bp, "whole_color", d, "whole_color", 0, 255, 0)
        util.addNum2dict(bp, "ground_color", d, "ground_color", 0, 255, 0)

        if ("whole_color" in d or "ground_color" in d):
            util.addString2dict(bp, "color_system", d, "color_system", 25)

        if "computed" in bp:
            cp = bp["computed"]

            util.addAllTemp2dict(cp, d, [("CHARGE_ET", "charge_temp_ET"),
                                         ("CHARGE_BT", "charge_temp"),
                                         ("TP_BT", "TP_temp"),
                                         ("DRY_BT", "DRY_temp"),
                                         ("FCs_BT", "FCs_temp"),
                                         ("FCe_BT", "FCe_temp"),
                                         ("DROP_BT", "drop_temp"),
                                         ("DROP_ET", "drop_temp_ET")])
            util.addAllTime2dict(cp, d, [
                "TP_time", "DRY_time", "FCs_time", "FCe_time",
                ("DROP_time", "drop_time")
            ])

            if "finishphasetime" in cp:
                util.addTime2dict(cp, "finishphasetime", d, "DEV_time")
                if "totaltime" in cp:
                    v = util.limitnum(
                        0, 100,
                        util.float2floatMin(
                            cp["finishphasetime"] / cp["totaltime"] * 100, 1))
                    if v is not None:
                        d["DEV_ratio"] = v

            util.addNum2dict(cp, "AUC", d, "AUC", 0, 10000, 0)
            util.addTemp2dict(cp, "AUCbase", d, "AUC_base")

    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error("roast: Exception in getTemplate() line %s: %s",
                            exc_tb.tb_lineno, e)
    return d
Example #4
0
def fetchServerUpdate(uuid, file=None):
    aw = config.app_window
    try:
        config.logger.debug(
            "sync:fetchServerUpdate() -> requesting update from server (file: %s)",
            file)
        last_modified = ""
        if file is not None:
            file_last_modified = util.getModificationDate(file)
            # if file modification data is newer than what we have in our sync cache (as the file was externally modified),
            # we update our sync cache
#            addSync(uuid,file_last_modified)
#   don't update the sync cache timestamp here as the changes might not have been submitted to the server yet
        else:
            file_last_modified = None

        if file_last_modified is not None:
            last_modified = "?modified_at=" + str(
                int(round(file_last_modified * 1000)))
        res = connection.getData(config.roast_url + "/" + uuid + last_modified)
        status = res.status_code

        if status == 204:  # NO CONTENT: data on server is older then ours
            config.logger.debug(
                "sync:fetchServerUpdate() -> 204 data on server is older")
            #no newer data found on server, do nothing; controller.is_synced() might report an unsynced status
            # if file modification date is newer than what is known on the version from the server via the sync cache

            if file is not None and getSync(uuid) is None:
                config.logger.debug(
                    "sync: -> file not in sync cache yet, we recuires to fetch the servers modification date and add the profile to the sync cache"
                )
                # we recurse to get a 200 with the last_modification date from the server for this record to add it to the sync cache automatically
                fetchServerUpdate(uuid)
            pass
        elif status == 404:
            try:
                data = res.json()
                if "success" in data and not data["success"]:
                    config.logger.debug(
                        "sync:fetchServerUpdate() -> 404 roast record deleted on server"
                    )
                    # data not found on server, remove UUID from sync cache
                    delSync(uuid)
                # else there must be another cause of the 404
                else:
                    config.logger.debug(
                        "sync:fetchServerUpdate() -> 404 server error")
            except:
                pass
        elif status == 200:  # data on server is newer than ours => update with data from server
            config.logger.debug(
                "sync:fetchServerUpdate() -> 200 data on server is newer")
            data = res.json()
            if "result" in data:
                r = data["result"]
                config.logger.debug("sync: -> fetch: %s", r)

                if getSync(uuid) is None and "modified_at" in r:
                    addSync(uuid, util.ISO86012epoch(r["modified_at"]))
                    config.logger.debug(
                        "sync: -> added profile automatically to sync cache")

                if file_last_modified is not None:
                    config.logger.debug("sync: -> file last_modified date: %s",
                                        util.epoch2ISO8601(file_last_modified))
                if "modified_at" in r and file_last_modified is not None and util.ISO86012epoch(
                        r["modified_at"]) > file_last_modified:
                    applyServerUpdates(r)
                else:
                    config.logger.debug(
                        "sync: -> data received from server was older!?")
                    config.logger.debug(
                        "sync: -> file last_modified epoch: %s",
                        file_last_modified)
                    config.logger.debug(
                        "sync: -> server last_modified epoch: %s",
                        util.ISO86012epoch(r["modified_at"]))
                    config.logger.debug(
                        "sync: -> server last_modified date: %s",
                        r["modified_at"])
    except requests.exceptions.ConnectionError as e:  # more general: requests.exceptions.RequestException
        config.logger.debug(
            "sync: -> connection error in fetchServerUpdate(), disconnecting: %s",
            e)
        # we disconnect, but keep the queue running to let it automatically reconnect if possible
        controller.disconnect(remove_credentials=False, stop_queue=False)
    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error(
            "sync: Exception in fetchServerUpdate() in line %s: %s",
            exc_tb.tb_lineno, e)
    finally:
        aw.editgraphdialog = None  # stop block opening the Roast Properties dialog while syncing from the server
        config.app_window.updatePlusStatusSignal.emit()  # @UndefinedVariable
Example #5
0
def fetchServerUpdate(uuid, file=None):
    aw = config.app_window
    try:
        config.logger.debug(
            "sync:fetchServerUpdate() -> requesting update from server (file: %s)",
            file)
        last_modified = ""
        if file is not None:
            file_last_modified = util.getModificationDate(file)
            # if file modification data is newer than what we have in our sync cache (as the file was externally modified),
            # we update our sync cache
#            addSync(uuid,file_last_modified)
#   don't update the sync cache timestamp here as the changes might not have been submitted to the server yet
        else:
            file_last_modified = None
        if file_last_modified is not None:
            last_modified = "?modified_at=" + str(
                int(round(file_last_modified * 1000)))
        res = connection.getData(config.roast_url + "/" + uuid + last_modified)
        status = res.status_code
        if status == 204:  # NO CONTENT: data on server is older then ours
            config.logger.debug(
                "sync:fetchServerUpdate() -> 204 data on server is older")
            pass  # we do nothing
        elif status == 404:
            try:
                data = res.json()
                if "success" in data and not data["success"]:
                    config.logger.debug(
                        "sync:fetchServerUpdate() -> 404 roast record deleted on server"
                    )
                    # data not found on server, remove UUID from sync cache
                    delSync(uuid)
                # else there must be another cause of the 404
                else:
                    config.logger.debug(
                        "sync:fetchServerUpdate() -> 404 server error")
            except:
                pass
        elif status == 200:  # data on server is newer than ours => update with data from server
            config.logger.debug(
                "sync:fetchServerUpdate() -> 200 data on server is newer")
            data = res.json()
            if "result" in data:
                r = data["result"]
                config.logger.debug("sync: -> fetch: %s", r)
                if file_last_modified is not None:
                    config.logger.debug("sync: -> file last_modified date: %s",
                                        util.epoch2ISO8601(file_last_modified))
                if "modified_at" in r and file_last_modified is not None and util.ISO86012epoch(
                        r["modified_at"]) > file_last_modified:
                    applyServerUpdates(r)
                else:
                    config.logger.debug(
                        "sync: -> data received from server was older!?")
                    config.logger.debug(
                        "sync: -> file last_modified epoch: %s",
                        file_last_modified)
                    config.logger.debug(
                        "sync: -> server last_modified epoch: %s",
                        util.ISO86012epoch(r["modified_at"]))
                    config.logger.debug(
                        "sync: -> server last_modified date: %s",
                        r["modified_at"])
    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error(
            "sync: Exception in fetchServerUpdate() in line %s: %s",
            exc_tb.tb_lineno, e)
    finally:
        aw.editgraphdialog = None  # stop block opening the Roast Properties dialog while syncing from the server
        config.app_window.updatePlusStatusSignal.emit()  # @UndefinedVariable
Example #6
0
def getRoast():
    d = {}
    try:
        config.logger.debug("roast:getRoast()")
        aw = config.app_window
        p = aw.getProfile()

        d = getTemplate(p)

        # id => roast_id
        if "id" in d:
            d["roast_id"] = d["id"]
            del d["id"]

        # start_weight => amount
        if "start_weight" in d:
            d["amount"] = d["start_weight"]
            del d["start_weight"]
        else:
            d["amount"] = 0

        # computed values added just for the profile, but not for the profiles template
        try:
            if "computed" in p:
                cp = p["computed"]
                if "det" in cp:
                    util.addTemp2dict(cp, "det", d, "CM_ETD")
                if "dbt" in cp:
                    util.addTemp2dict(cp, "dbt", d, "CM_BTD")
                #### Energy Consumption data only added if not zero
                util.addAllNum2dict(
                    cp,
                    d,
                    [
                        # energy consumption by source type in BTU
                        "BTU_ELEC",
                        "BTU_LPG",
                        "BTU_NG",
                        # energy consumption by process in BTU
                        "BTU_roast",
                        "BTU_preheat",
                        "BTU_bbp",
                        "BTU_cooling",
                        # total energy conumption per batch
                        "BTU_batch"
                    ],
                    None,  # no min limit
                    None,  # no max limit
                    1,  # 1 decimal places
                )

                util.addAllNum2dict(
                    cp,
                    d,
                    [
                        # CO2 production by process in g
                        "CO2_roast",
                        "CO2_preheat",
                        "CO2_bbp",
                        "CO2_cooling",
                        # total CO2 production per batch
                        "CO2_batch"
                    ],
                    None,  # no min limit
                    None,  # no max limit
                    3,  # 3 decimal places
                    factor=1 /
                    1000,  # CO2 data is forwarded in kg (instead of the Artisan internal g)
                )
        except Exception as e:
            config.logger.info("roast: Exception in getRoast() %s", e)

        if aw.qmc.plus_store:
            d["location"] = aw.qmc.plus_store
        else:
            d["location"] = None
        if aw.qmc.plus_coffee:
            d["coffee"] = aw.qmc.plus_coffee
        else:
            d["coffee"] = None  # we neeed to explicitly add empty selections otherwise the coffee cannot be deleted from the online record
        if aw.qmc.plus_blend_spec and aw.qmc.plus_coffee is None:
            d["blend"] = trimBlendSpec(aw.qmc.plus_blend_spec)
        else:
            d["blend"] = None  # we neeed to explicitly add empty selections otherwise the coffee cannot be deleted from the online record

        # ensure that location is None if neither coffee nor blend is set
        if d["coffee"] is None and d["blend"] is None and d[
                "location"] is not None:
            d["location"] = None

        try:
            util.addTemp2dict(p, "ambientTemp", d, "temperature")
            util.addNum2dict(p, "ambient_pressure", d, "pressure", 800, 1200,
                             1)
            util.addNum2dict(p, "ambient_humidity", d, "humidity", 0, 100, 1)
        except Exception as e:
            config.logger.info("roast: Exception in getRoast() %s", e)

        try:
            util.addString2dict(p, "roastingnotes", d, "notes", 1023)
        except Exception as e:
            config.logger.info("roast: Exception in getRoast() %s", e)

        if aw.qmc.background and aw.qmc.backgroundprofile:
            bp = aw.qmc.backgroundprofile
            template = getTemplate(bp)
            d["template"] = template

        # if profile is already saved, that modification date is send along to the server instead the timestamp
        # of the moment the record is queued
        if aw.curFile is not None:
            d["modified_at"] = util.epoch2ISO8601(
                util.getModificationDate(aw.curFile))

    except Exception as e:
        import sys
        _, _, exc_tb = sys.exc_info()
        config.logger.error("roast: Exception in getRoast() line %s: %s",
                            exc_tb.tb_lineno, e)
        return {}
    return d