Loading .gitignore +2 −0 Original line number Diff line number Diff line Loading @@ -4,3 +4,5 @@ */Hardware/History */Hardware/__Previews */Hardware/Project\ Logs* */__pycache__ Software-hub/NeoKomp.py +22 −4 Original line number Diff line number Diff line Loading @@ -10,8 +10,8 @@ from frames.Balance import Balance import api_communication as API import ble_driver as NeoBLE import rfid import ble_driver as ble import rfid_driver as rfid class NeoKomp(QtWidgets.QMainWindow): """ Loading @@ -31,10 +31,16 @@ class NeoKomp(QtWidgets.QMainWindow): self.central_widget = QtWidgets.QStackedWidget() self.setCentralWidget(self.central_widget) # Timeout indicator always runs. Frames will connect to this timer if # they need to repeatedly run a routine to update a label, like a timer # countdown. self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) # Make frames self.frames = {} for F in (Guide, Search, Cart, Receipt, Balance): frame = F(self) frame = F(parent=self) self.frames[frame.__class__.__name__] = frame self.central_widget.addWidget(frame) Loading @@ -51,9 +57,10 @@ class NeoKomp(QtWidgets.QMainWindow): self.rfid_manager.start() # Make BLE manager self.ble_manager = NeoBLE.BLEThread(self, self.device_mapping) self.ble_manager = ble.BLEThread(self, self.device_mapping) self.ble_manager.start() def enter_event(self, event): """Send enter event to the relevant frame""" frame = self.frames[self.state] Loading @@ -63,6 +70,17 @@ class NeoKomp(QtWidgets.QMainWindow): self.central_widget.setCurrentWidget(self.frames[frame]) self.frames[frame].focus() def show_balance(self, rfid): self.show_frame('Balance') self.frames['Balance'].show_balance(rfid) def attempt_to_buy(self, rfid, items): self.show_frame('Receipt') self.frames['Receipt'].attempt_to_buy(rfid, items) def cart_has_items(self): return self.frames['Cart'].has_items() @QtCore.pyqtSlot("PyQt_PyObject") def ble_button_pressed(self, location): self.frames['Cart'].add_item_from_location(location) Loading Software-hub/ble_driver.py +4 −5 Original line number Diff line number Diff line Loading @@ -18,10 +18,9 @@ class BLEThread(QtCore.QThread): self.parent = parent self.device_mapping = device_mapping # Find primary bluetooth controller. TODO: find a better way of getting # the adapter name # Find primary Bluetooth controller. ctrl_info = subprocess.check_output(['btmgmt', 'info']).decode('utf-8') pattern = r"([a-zA-Z]*[0-9]*):\tPrimary controller" pattern = r"([a-zA-Z]+[0-9]+):\tPrimary controller" primary_ctrl = re.search(pattern, ctrl_info).group(1) # Make sure ble is on and not currently connected Loading @@ -29,7 +28,7 @@ class BLEThread(QtCore.QThread): os.system("bluetoothctl power on") # Create BLE Manager self.manager = BLEKomp(parent=self, adapter_name=primary_ctrl) self.manager = BLEManager(parent=self, adapter_name=primary_ctrl) # Connect signal self.button_pressed.connect(parent.ble_button_pressed) Loading @@ -45,7 +44,7 @@ class BLEThread(QtCore.QThread): print("Button order: %s" % position) self.button_pressed.emit(position) class BLEKomp(gatt.DeviceManager): class BLEManager(gatt.DeviceManager): def __init__(self, *args, **kwargs): self.parent = kwargs.pop('parent') super().__init__(*args, **kwargs) Loading Software-hub/frames/Balance.py +6 −35 Original line number Diff line number Diff line Loading @@ -2,32 +2,23 @@ import sys import traceback import math from PyQt5 import QtCore, QtGui, QtWidgets from frames.FrameBase import GenericFrame, TimedFrame import api_communication as API BALANCE_TIMEOUT_MS = 300000 BALANCE_TIMEOUT_MS = 10000 DEBUG = True def debug(string): if DEBUG: print(string) class Balance(QtWidgets.QWidget): def __init__(self, parent): super().__init__(parent) self.parent = parent class Balance(GenericFrame, TimedFrame): def __init__(self, **kwargs): super(Balance, self).__init__(**dict(kwargs, timeout=BALANCE_TIMEOUT_MS)) self.parent = kwargs['parent'] self.init_layout() self.timer_init() ## Install/Enable custom eventFilter() self.installEventFilter(self) def init_layout(self): # General vertical layout self.layout = QtWidgets.QVBoxLayout(self) title_font = QtGui.QFont() title_font.setPointSize(20) self.title = QtWidgets.QLabel("Balance") Loading Loading @@ -104,26 +95,6 @@ Start typing to search for a component.""" # Pass event to QWidget return super(Balance, self).eventFilter(obj, event) def timer_init(self): # Timeout is SingleShot timer self.timeout_timer = QtCore.QTimer() self.timeout_timer.setSingleShot(True) self.timeout_timer.timeout.connect(self.timeout) # Timeout indicator always runs self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) self.indicator_timer.timeout.connect(self.update_timeout_indicator) def restart_timer(self): if self.timeout_timer.isActive(): self.timeout_timer.stop() self.timeout_timer.start(BALANCE_TIMEOUT_MS) def stop_timer(self): self.timeout_timer.stop() @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide Loading Software-hub/frames/Cart.py +75 −79 Original line number Diff line number Diff line import sys import math from PyQt5 import QtCore, QtGui, QtWidgets from frames.FrameBase import GenericFrame, TimedFrame import api_communication as API Loading @@ -9,22 +10,15 @@ CART_TIMEOUT_MS = 300000 CART_TABLE_HEIGHT = 500 CART_TABLE_WIDTH = 800 DEBUG = True def debug(string): if DEBUG: print(string) class Cart(QtWidgets.QWidget): def __init__(self, parent): super().__init__(parent) self.parent = parent class Cart(GenericFrame, TimedFrame): def __init__(self, **kwargs): super(Cart, self).__init__(**dict(kwargs, timeout=CART_TIMEOUT_MS)) self.parent = kwargs['parent'] self.headers = ['id', 'navn', 'beskrivelse', 'antall', 'pris'] self.layout_init() self.timer_init() self.add_total() # Connect cell double click to add to cart Loading @@ -34,9 +28,6 @@ class Cart(QtWidgets.QWidget): self.installEventFilter(self) def layout_init(self): ## General vertical layout self.layout = QtWidgets.QVBoxLayout(self) ## Title title_font = QtGui.QFont() title_font.setPointSize(20) Loading @@ -58,10 +49,10 @@ class Cart(QtWidgets.QWidget): self.layout.addStretch() ## Help text self.help_text = "\ Press <Return> to remove selected item.\n\ Double click item to remove item.\n\ TODO: Scan RFID card to buy Cart." self.help_text = """Press <Return> to remove selected item. Double click item to remove item. TODO: Scan RFID card to buy Cart. """ self.help_label = QtWidgets.QLabel(self.help_text) self.layout.addWidget(self.help_label) Loading Loading @@ -102,21 +93,38 @@ TODO: Scan RFID card to buy Cart." self.layout.addLayout(self.navigation_buttons) @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide self.clear_cart('Guide') @QtCore.pyqtSlot() def update_timeout_indicator(self): if self.timeout_timer.isActive(): time = self.timeout_timer.remainingTime() time = math.ceil(time / 1000) # ms to s self.timeout_indicator.setText("Timeout in " + str(time) + "s") else: self.timeout_indicator.setText("") # Install a custom eventFilter to capture enterPressed anywhere def eventFilter(self, obj, event): if event.type() == QtCore.QEvent.ShortcutOverride: self.restart_timer() if event.text().isalnum(): self.parent.show_frame('Search') return False # ? if event.type() == QtCore.QEvent.KeyPress: elif event.type() == QtCore.QEvent.KeyPress: if event.key() == QtCore.Qt.Key_Return: self.return_pressed() return True if event.key() == QtCore.Qt.Key_Escape: elif event.key() == QtCore.Qt.Key_Escape: # Emulate timeout self.clear_cart('Guide') return True else: self.restart_timer() # Pass event to QWidget return super(Cart, self).eventFilter(obj, event) Loading @@ -138,42 +146,6 @@ TODO: Scan RFID card to buy Cart." if (row < self.cart.rowCount() - 1): self.remove_row(row) def timer_init(self): # Timeout is SingleShot timer self.timeout_timer = QtCore.QTimer() self.timeout_timer.setSingleShot(True) self.timeout_timer.timeout.connect(self.timeout) # Timeout indicator always runs self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) self.indicator_timer.timeout.connect(self.update_timeout_indicator) def restart_timer(self): if self.timeout_timer.isActive(): self.timeout_timer.stop() self.timeout_timer.start(CART_TIMEOUT_MS) def stop_timer(self): self.timeout_timer.stop() @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide self.clear_cart() @QtCore.pyqtSlot() def update_timeout_indicator(self): if self.timeout_timer.isActive(): time = self.timeout_timer.remainingTime() time = math.ceil(time / 1000) # ms to s self.timeout_indicator.setText("Timeout in " + str(time) + "s") else: self.timeout_indicator.setText("") def focus(self): return def add_item_from_location(self, loc): item = API.AJAX_search_component_pos(loc['rom'], loc['seksjon'], loc['hylle'], loc['rad'], loc['kolonne'], loc['dybde']) print(item) Loading @@ -193,8 +165,37 @@ TODO: Scan RFID card to buy Cart." def has_items(self): return self.cart.rowCount() >= 2 def add_to_row_amount(self, row, num): # Get old amount # Row 5 has amount amount = self.cart.item(row, 3).text() try: amount = int(amount) + 1 except: print("EXCET") amount = 0 self.cart.item(row, 3).setText(str(amount)) def increment_row_amount(self, row): self.add_to_row_amount(row, 1) def decrement_row_amount(self, row): self.add_to_row_amount(row, -1) def add_item(self, item): row_positions = self.cart.rowCount() # Check if the item is already in the cart row_of_existing_item = None for row in range(row_positions-1): item_id = self.cart.item(row, 0).data(QtCore.Qt.UserRole)['id'] if (item_id == item['id']): row_of_existing_item = row if (row_of_existing_item != None): self.increment_row_amount(row_of_existing_item) else: # New item goes one above the bottom (which is the Total/Sum) row = row_positions - 1 self.cart.insertRow(row) Loading Loading @@ -242,7 +243,6 @@ TODO: Scan RFID card to buy Cart." title_table_item.setFont(font) total_table_item.setFont(font) def update_total(self): total = 0 row_count = self.cart.rowCount() Loading Loading @@ -310,15 +310,11 @@ TODO: Scan RFID card to buy Cart." items.append(self.cart.item(row, 0).data(QtCore.Qt.UserRole)) if len(items) == 0: self.parent.show_frame('Balance') self.parent.frames['Balance'].show_balance(rfid) self.parent.show_balance(rfid) return # Switch to receipt self.parent.show_frame('Receipt') # Issue the buy self.parent.frames['Receipt'].attempt_to_buy(rfid, items) # Clear the cart self.clear_cart('Receipt') # Issue the buy self.parent.attempt_to_buy(rfid, items) Loading
.gitignore +2 −0 Original line number Diff line number Diff line Loading @@ -4,3 +4,5 @@ */Hardware/History */Hardware/__Previews */Hardware/Project\ Logs* */__pycache__
Software-hub/NeoKomp.py +22 −4 Original line number Diff line number Diff line Loading @@ -10,8 +10,8 @@ from frames.Balance import Balance import api_communication as API import ble_driver as NeoBLE import rfid import ble_driver as ble import rfid_driver as rfid class NeoKomp(QtWidgets.QMainWindow): """ Loading @@ -31,10 +31,16 @@ class NeoKomp(QtWidgets.QMainWindow): self.central_widget = QtWidgets.QStackedWidget() self.setCentralWidget(self.central_widget) # Timeout indicator always runs. Frames will connect to this timer if # they need to repeatedly run a routine to update a label, like a timer # countdown. self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) # Make frames self.frames = {} for F in (Guide, Search, Cart, Receipt, Balance): frame = F(self) frame = F(parent=self) self.frames[frame.__class__.__name__] = frame self.central_widget.addWidget(frame) Loading @@ -51,9 +57,10 @@ class NeoKomp(QtWidgets.QMainWindow): self.rfid_manager.start() # Make BLE manager self.ble_manager = NeoBLE.BLEThread(self, self.device_mapping) self.ble_manager = ble.BLEThread(self, self.device_mapping) self.ble_manager.start() def enter_event(self, event): """Send enter event to the relevant frame""" frame = self.frames[self.state] Loading @@ -63,6 +70,17 @@ class NeoKomp(QtWidgets.QMainWindow): self.central_widget.setCurrentWidget(self.frames[frame]) self.frames[frame].focus() def show_balance(self, rfid): self.show_frame('Balance') self.frames['Balance'].show_balance(rfid) def attempt_to_buy(self, rfid, items): self.show_frame('Receipt') self.frames['Receipt'].attempt_to_buy(rfid, items) def cart_has_items(self): return self.frames['Cart'].has_items() @QtCore.pyqtSlot("PyQt_PyObject") def ble_button_pressed(self, location): self.frames['Cart'].add_item_from_location(location) Loading
Software-hub/ble_driver.py +4 −5 Original line number Diff line number Diff line Loading @@ -18,10 +18,9 @@ class BLEThread(QtCore.QThread): self.parent = parent self.device_mapping = device_mapping # Find primary bluetooth controller. TODO: find a better way of getting # the adapter name # Find primary Bluetooth controller. ctrl_info = subprocess.check_output(['btmgmt', 'info']).decode('utf-8') pattern = r"([a-zA-Z]*[0-9]*):\tPrimary controller" pattern = r"([a-zA-Z]+[0-9]+):\tPrimary controller" primary_ctrl = re.search(pattern, ctrl_info).group(1) # Make sure ble is on and not currently connected Loading @@ -29,7 +28,7 @@ class BLEThread(QtCore.QThread): os.system("bluetoothctl power on") # Create BLE Manager self.manager = BLEKomp(parent=self, adapter_name=primary_ctrl) self.manager = BLEManager(parent=self, adapter_name=primary_ctrl) # Connect signal self.button_pressed.connect(parent.ble_button_pressed) Loading @@ -45,7 +44,7 @@ class BLEThread(QtCore.QThread): print("Button order: %s" % position) self.button_pressed.emit(position) class BLEKomp(gatt.DeviceManager): class BLEManager(gatt.DeviceManager): def __init__(self, *args, **kwargs): self.parent = kwargs.pop('parent') super().__init__(*args, **kwargs) Loading
Software-hub/frames/Balance.py +6 −35 Original line number Diff line number Diff line Loading @@ -2,32 +2,23 @@ import sys import traceback import math from PyQt5 import QtCore, QtGui, QtWidgets from frames.FrameBase import GenericFrame, TimedFrame import api_communication as API BALANCE_TIMEOUT_MS = 300000 BALANCE_TIMEOUT_MS = 10000 DEBUG = True def debug(string): if DEBUG: print(string) class Balance(QtWidgets.QWidget): def __init__(self, parent): super().__init__(parent) self.parent = parent class Balance(GenericFrame, TimedFrame): def __init__(self, **kwargs): super(Balance, self).__init__(**dict(kwargs, timeout=BALANCE_TIMEOUT_MS)) self.parent = kwargs['parent'] self.init_layout() self.timer_init() ## Install/Enable custom eventFilter() self.installEventFilter(self) def init_layout(self): # General vertical layout self.layout = QtWidgets.QVBoxLayout(self) title_font = QtGui.QFont() title_font.setPointSize(20) self.title = QtWidgets.QLabel("Balance") Loading Loading @@ -104,26 +95,6 @@ Start typing to search for a component.""" # Pass event to QWidget return super(Balance, self).eventFilter(obj, event) def timer_init(self): # Timeout is SingleShot timer self.timeout_timer = QtCore.QTimer() self.timeout_timer.setSingleShot(True) self.timeout_timer.timeout.connect(self.timeout) # Timeout indicator always runs self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) self.indicator_timer.timeout.connect(self.update_timeout_indicator) def restart_timer(self): if self.timeout_timer.isActive(): self.timeout_timer.stop() self.timeout_timer.start(BALANCE_TIMEOUT_MS) def stop_timer(self): self.timeout_timer.stop() @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide Loading
Software-hub/frames/Cart.py +75 −79 Original line number Diff line number Diff line import sys import math from PyQt5 import QtCore, QtGui, QtWidgets from frames.FrameBase import GenericFrame, TimedFrame import api_communication as API Loading @@ -9,22 +10,15 @@ CART_TIMEOUT_MS = 300000 CART_TABLE_HEIGHT = 500 CART_TABLE_WIDTH = 800 DEBUG = True def debug(string): if DEBUG: print(string) class Cart(QtWidgets.QWidget): def __init__(self, parent): super().__init__(parent) self.parent = parent class Cart(GenericFrame, TimedFrame): def __init__(self, **kwargs): super(Cart, self).__init__(**dict(kwargs, timeout=CART_TIMEOUT_MS)) self.parent = kwargs['parent'] self.headers = ['id', 'navn', 'beskrivelse', 'antall', 'pris'] self.layout_init() self.timer_init() self.add_total() # Connect cell double click to add to cart Loading @@ -34,9 +28,6 @@ class Cart(QtWidgets.QWidget): self.installEventFilter(self) def layout_init(self): ## General vertical layout self.layout = QtWidgets.QVBoxLayout(self) ## Title title_font = QtGui.QFont() title_font.setPointSize(20) Loading @@ -58,10 +49,10 @@ class Cart(QtWidgets.QWidget): self.layout.addStretch() ## Help text self.help_text = "\ Press <Return> to remove selected item.\n\ Double click item to remove item.\n\ TODO: Scan RFID card to buy Cart." self.help_text = """Press <Return> to remove selected item. Double click item to remove item. TODO: Scan RFID card to buy Cart. """ self.help_label = QtWidgets.QLabel(self.help_text) self.layout.addWidget(self.help_label) Loading Loading @@ -102,21 +93,38 @@ TODO: Scan RFID card to buy Cart." self.layout.addLayout(self.navigation_buttons) @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide self.clear_cart('Guide') @QtCore.pyqtSlot() def update_timeout_indicator(self): if self.timeout_timer.isActive(): time = self.timeout_timer.remainingTime() time = math.ceil(time / 1000) # ms to s self.timeout_indicator.setText("Timeout in " + str(time) + "s") else: self.timeout_indicator.setText("") # Install a custom eventFilter to capture enterPressed anywhere def eventFilter(self, obj, event): if event.type() == QtCore.QEvent.ShortcutOverride: self.restart_timer() if event.text().isalnum(): self.parent.show_frame('Search') return False # ? if event.type() == QtCore.QEvent.KeyPress: elif event.type() == QtCore.QEvent.KeyPress: if event.key() == QtCore.Qt.Key_Return: self.return_pressed() return True if event.key() == QtCore.Qt.Key_Escape: elif event.key() == QtCore.Qt.Key_Escape: # Emulate timeout self.clear_cart('Guide') return True else: self.restart_timer() # Pass event to QWidget return super(Cart, self).eventFilter(obj, event) Loading @@ -138,42 +146,6 @@ TODO: Scan RFID card to buy Cart." if (row < self.cart.rowCount() - 1): self.remove_row(row) def timer_init(self): # Timeout is SingleShot timer self.timeout_timer = QtCore.QTimer() self.timeout_timer.setSingleShot(True) self.timeout_timer.timeout.connect(self.timeout) # Timeout indicator always runs self.indicator_timer = QtCore.QTimer() self.indicator_timer.start(100) self.indicator_timer.timeout.connect(self.update_timeout_indicator) def restart_timer(self): if self.timeout_timer.isActive(): self.timeout_timer.stop() self.timeout_timer.start(CART_TIMEOUT_MS) def stop_timer(self): self.timeout_timer.stop() @QtCore.pyqtSlot() def timeout(self): #Clear it and go to guide self.clear_cart() @QtCore.pyqtSlot() def update_timeout_indicator(self): if self.timeout_timer.isActive(): time = self.timeout_timer.remainingTime() time = math.ceil(time / 1000) # ms to s self.timeout_indicator.setText("Timeout in " + str(time) + "s") else: self.timeout_indicator.setText("") def focus(self): return def add_item_from_location(self, loc): item = API.AJAX_search_component_pos(loc['rom'], loc['seksjon'], loc['hylle'], loc['rad'], loc['kolonne'], loc['dybde']) print(item) Loading @@ -193,8 +165,37 @@ TODO: Scan RFID card to buy Cart." def has_items(self): return self.cart.rowCount() >= 2 def add_to_row_amount(self, row, num): # Get old amount # Row 5 has amount amount = self.cart.item(row, 3).text() try: amount = int(amount) + 1 except: print("EXCET") amount = 0 self.cart.item(row, 3).setText(str(amount)) def increment_row_amount(self, row): self.add_to_row_amount(row, 1) def decrement_row_amount(self, row): self.add_to_row_amount(row, -1) def add_item(self, item): row_positions = self.cart.rowCount() # Check if the item is already in the cart row_of_existing_item = None for row in range(row_positions-1): item_id = self.cart.item(row, 0).data(QtCore.Qt.UserRole)['id'] if (item_id == item['id']): row_of_existing_item = row if (row_of_existing_item != None): self.increment_row_amount(row_of_existing_item) else: # New item goes one above the bottom (which is the Total/Sum) row = row_positions - 1 self.cart.insertRow(row) Loading Loading @@ -242,7 +243,6 @@ TODO: Scan RFID card to buy Cart." title_table_item.setFont(font) total_table_item.setFont(font) def update_total(self): total = 0 row_count = self.cart.rowCount() Loading Loading @@ -310,15 +310,11 @@ TODO: Scan RFID card to buy Cart." items.append(self.cart.item(row, 0).data(QtCore.Qt.UserRole)) if len(items) == 0: self.parent.show_frame('Balance') self.parent.frames['Balance'].show_balance(rfid) self.parent.show_balance(rfid) return # Switch to receipt self.parent.show_frame('Receipt') # Issue the buy self.parent.frames['Receipt'].attempt_to_buy(rfid, items) # Clear the cart self.clear_cart('Receipt') # Issue the buy self.parent.attempt_to_buy(rfid, items)