예제 #1
0
    def __init__(self, settings, lcd):
        self.settings = settings
        self.lcd = lcd
        self.sel = NumberSelector(self.lcd)
        self.sel.callback = self.select_packer_callback
        self.menu = Menu(self.lcd)
        self.menu.callback = self.menu_callback
        self.scanner = BarcodeScanner.get_scanner()
        self.mode = self.MODE_SELECT_PACKER

        self.terminal_id = self.settings.get("terminal")

        self.ws = Webservice(self.settings.get("url"))
        self.ws.token = self.settings.get("token")
        self.ws.username = self.settings.get("username")
        self.ws.password = self.settings.get("password")

        self.scanner_thread = Thread(target=self.scanner_thread, name="scanner_thread")
        self.buttons_thread = Thread(target=self.buttons_thread, name="buttons_thread")
        self.timer_thread = Thread(target=self.timer_thread, name="timer_thread")
        self.scanner_thread.daemon = True
        self.buttons_thread.daemon = True
        self.timer_thread.daemon = True

        self.lock = Lock()
        self.semaphore = Semaphore()
        self.timer_event = Event()
        self.quit_event = Event()

        self.event_stack = list()

        # Tracking status variables
        self.packer_id = None
        self.invoice = None
        self.start_time = None
        self.order_info = None

        # Saved previous modes for special cases
        self.previous_mode_menu = None
예제 #2
0
class PackingTimeTracker(object):
    MODE_SELECT_PACKER = "select_packer"
    MODE_WAIT_INVOICE = "wait_invoice"
    MODE_TRACKING = "resume_tracking"
    MODE_MENU = "show_menu"

    ERROR_MESSAGES = {
        "Order not found.": "Bestellung\nnicht gefunden",
        "Failed to get order.": "Abruf\nfehlgeschlagen",
    }

    EVENT_BARCODE = 1
    EVENT_BUTTON = 2
    EVENT_DEVICE = 3
    EVENT_QUIT = 4

    def __init__(self, settings, lcd):
        self.settings = settings
        self.lcd = lcd
        self.sel = NumberSelector(self.lcd)
        self.sel.callback = self.select_packer_callback
        self.menu = Menu(self.lcd)
        self.menu.callback = self.menu_callback
        self.scanner = BarcodeScanner.get_scanner()
        self.mode = self.MODE_SELECT_PACKER

        self.terminal_id = self.settings.get("terminal")

        self.ws = Webservice(self.settings.get("url"))
        self.ws.token = self.settings.get("token")
        self.ws.username = self.settings.get("username")
        self.ws.password = self.settings.get("password")

        self.scanner_thread = Thread(target=self.scanner_thread, name="scanner_thread")
        self.buttons_thread = Thread(target=self.buttons_thread, name="buttons_thread")
        self.timer_thread = Thread(target=self.timer_thread, name="timer_thread")
        self.scanner_thread.daemon = True
        self.buttons_thread.daemon = True
        self.timer_thread.daemon = True

        self.lock = Lock()
        self.semaphore = Semaphore()
        self.timer_event = Event()
        self.quit_event = Event()

        self.event_stack = list()

        # Tracking status variables
        self.packer_id = None
        self.invoice = None
        self.start_time = None
        self.order_info = None

        # Saved previous modes for special cases
        self.previous_mode_menu = None

    def scanner_thread(self):
        while not self.quit_event.isSet():
            try:
                barcode = self.scanner.read()

                self.add_event((self.EVENT_BARCODE, barcode))

            except (NoDeviceFoundError, AttributeError):
                self.scanner = None

                # Inform the main thread that the barcode scanner was unplugged
                self.add_event((self.EVENT_DEVICE, "plugged_out"))

                # Let this thread search for a barcode scanner
                self.search_scanner()

        print("Quitting scanner thread")

    def add_event(self, event):
        self.lock.acquire()
        self.event_stack.append(event)
        self.semaphore.release()
        self.lock.release()

    def search_scanner(self):
        """ Called from the scanner thread, this will keep searching for a barcode scanner until it is found. """
        self.scanner = None

        while self.scanner is None:
            sleep(1)
            self.scanner = BarcodeScanner.get_scanner()

            if self.quit_event.isSet():
                return

        self.add_event((self.EVENT_DEVICE, "plugged_in"))

    def buttons_thread(self):
        while not self.quit_event.isSet():
            button = self.lcd.read_buttons()

            if button is not None:
                self.add_event((self.EVENT_BUTTON, button))

            sleep(0.1)

        print("Quitting buttons thread")

    def timer_thread(self):
        while self.timer_event.wait() and not self.quit_event.isSet():
            while self.mode == self.MODE_TRACKING and self.start_time is not None:
                if self.scanner is None:
                    self.lcd.message("Kein Barcode-\nscanner gefunden")
                else:
                    string = self.format_time(time() - self.start_time)

                    string = string + (" " * (16 - len(string) - len(self.invoice))) + self.invoice
                    string += "\n" + self.order_info

                    self.lcd.message(string)

                self.timer_event.clear()
                sleep(1)
        print("Quitting timer thread")

    def start(self):
        self.scanner_thread.start()
        self.buttons_thread.start()
        self.timer_thread.start()

        print("Entering main loop")
        while True:
            has_events = self.semaphore.acquire(blocking=0)

            if not has_events:
                sleep(0.1)

            else:
                self.lock.acquire()
                for event in self.event_stack:
                    group, value = event

                    print("Event %02d: %s" % (group, value))

                    if group == self.EVENT_BARCODE:
                        self.barcode_entered(value)
                    elif group == self.EVENT_BUTTON:
                        self.button_pressed(value)
                    elif group == self.EVENT_DEVICE:
                        self.barcode_scanner_plugged()
                    elif group == self.EVENT_QUIT:
                        self.quit()

                    self.event_stack.remove(event)
                self.lock.release()

    def barcode_scanner_plugged(self):
        if self.mode not in (self.MODE_MENU, self.MODE_SELECT_PACKER):
            self.resume()

    def barcode_entered(self, barcode):
        if self.mode == self.MODE_SELECT_PACKER:
            self.select_packer_callback(barcode)

        elif self.mode == self.MODE_WAIT_INVOICE:
            self.invoice = self.parse_invoice_barcode(barcode)
            self.start_tracking()

        elif self.mode == self.MODE_TRACKING:
            self.end_tracking()

    def button_pressed(self, button):
        if self.mode == self.MODE_SELECT_PACKER:
            self.sel.on_button_press(button)

        elif self.mode == self.MODE_MENU:
            self.menu.button_pressed(button)

        else:
            self.show_menu()

    def show_menu(self):
        self.previous_mode_menu = self.mode
        self.mode = self.MODE_MENU

        self.menu.show([
            ("logout", "Abmelden"),
            ("abort", "Paket\nabbrechen"),
            ("quit", "Beenden"),
            ("restart", "Programm\nneustarten"),
            ("shutdown", "Herunterfahren"),
            ("show_ip", "IP-Adresse\nanzeigen"),
        ])

    def menu_callback(self, option):
        if option == "logout":
            self.logout_packer()
        elif option == "abort":
            self.wait_invoice()
        elif option == "quit":
            self.quit()
        elif option == "restart":
            self.quit(restart=True)
        elif option == "shutdown":
            self.shutdown()
        elif option == "show_ip":
            ip = get_ip_addr("wlan0")
            self.lcd.message("IP-Adresse:\n%s" % ip)
        elif option is None:
            self.mode = self.previous_mode_menu
            self.previous_mode_menu = None
            self.resume()

    def resume(self):
        print("Resume mode %s" % self.mode)
        getattr(self, self.mode)()

    def logout_packer(self):
        print("Logged out packer")

        self.lcd.message("Verbinde...")
        self.ws.call("Packaging", "logoutPacker", {"packer": self.packer_id, "terminal": self.terminal_id})

        self.select_packer()

    def select_packer(self):
        self.mode = self.MODE_SELECT_PACKER
        self.packer_id = None
        self.sel.show("Packernummer:")

    def wait_invoice(self):
        self.mode = self.MODE_WAIT_INVOICE
        self.invoice = None

        if self.scanner is None:
            self.lcd.message("Kein Barcode-\nscanner gefunden")
        else:
            self.lcd.message("Lieferschein\nscannen")

    def start_tracking(self):
        self.lcd.message("Verbinde...")

        result = self.ws.call("Packaging", "getOrderInfo", {"orderId": self.invoice})

        if result["_success"]:
            self.start_time = time()
            self.mode = self.MODE_TRACKING

            self.order_info = "%s %s" % (result["first_name"], result["last_name"])
            self.resume_tracking()
        else:
            self.lcd.message(result["_status"])
            sleep(1)
            self.wait_invoice()

    def resume_tracking(self):
        self.timer_event.set()

    def end_tracking(self):
        pack_time = int(time() - self.start_time)

        self.lcd.message("Verbinde...")
        self.start_time = None

        result = self.ws.call("Packaging", "finishParcel", {
            "orderId": self.invoice,
            "packTime": pack_time,
            "packerId": self.packer_id,
        })

        if result["_success"]:
            self.lcd.message("Gepackte Zeit:\n%s Minuten" % self.format_time(pack_time))
        else:
            self.lcd.message("Fehlgeschlagen")

        sleep(2)
        self.wait_invoice()

    def select_packer_callback(self, number):
        self.lcd.message("Verbinde...")
        result = self.ws.call("Packaging", "loginPacker", {"packerId": number})

        if result["_success"]:
            self.packer_id = result["packer_id"]
            self.lcd.message("Hallo,\n%s!" % result["name"].encode("ascii", "replace"))

            sleep(1)

            self.mode = self.MODE_WAIT_INVOICE
            self.resume()
        else:
            self.lcd.message("Unbekannte\nNummer")
            sleep(1)
            self.sel.show(self.sel.prompt)

    def quit(self, restart=False):
        print("Quitting %s" % current_thread().name)
        self.quit_event.set()
        self.timer_event.set()
        self.buttons_thread.join()
        self.scanner_thread.join()
        self.timer_thread.join()

        if restart:
            exit(200)
        else:
            self.lcd.clear()
            self.lcd.backlight(lcd.OFF)
            exit()

    def shutdown(self):
        print("Shutting down...")
        self.lcd.message("Fahre\nherunter")
        system("/sbin/shutdown -h now")

    def __setattr__(self, key, value):
        def color(col, text):
            return "\033[%dm%s\033[0m" % (col, text)

        if (key == "mode" or key.startswith("previous_mode")) and hasattr(self, key):
            if getattr(self, key) != value:
                print("Switching %s from %s to %s." % (color(31, key), color(32, getattr(self, key)), color(33, value)))

        object.__setattr__(self, key, value)

    @staticmethod
    def format_time(seconds):
        return "%d:%02d" % (floor(seconds / 60), seconds % 60)

    @staticmethod
    def parse_invoice_barcode(barcode):
        if len(barcode) != 13:
            return barcode

        invoice = barcode[1:-1]
        return invoice.strip("0")