Created
July 3, 2020 14:38
-
-
Save huggre/5815111ed70f5b0ed456ff5c979e3d4a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# import the necessary packages | |
from __future__ import print_function | |
from PIL import Image | |
from PIL import ImageTk | |
import tkinter as tki | |
from tkinter import scrolledtext | |
from pyzbar import pyzbar | |
import threading | |
import imutils | |
import cv2 | |
import os | |
import csv | |
import json | |
# Import the PyOTA library | |
import iota | |
from iota import Address | |
class ReverseVendingMachine: | |
def __init__(self, vs): | |
# IOTA seed used for payment transaction | |
# Replace with your own devnet seed | |
seed = b"YOUR9SEED9GOES9HERE" | |
# URL to IOTA fullnode used when interacting with the Tangle | |
iotaNode = "https://nodes.devnet.iota.org:443" | |
# Define api object | |
self.api = iota.Iota(iotaNode, seed=seed) | |
# Define Total reward variable | |
self.total_reward = 0 | |
# Define some objects | |
self.vs = vs | |
self.frame = None | |
self.thread = None | |
self.stopEvent = None | |
# Initialize the root window and VideoStream panel | |
self.root = tki.Tk() | |
self.panel = None | |
# Define window header label | |
self.header_lbl = tki.Label(self.root, text='Recycle with IOTA') | |
self.header_lbl.config(font=("Courier", 30)) | |
self.header_lbl.grid(row=0, column=0, columnspan=2, sticky=(tki.N, tki.S, tki.E, tki.W)) | |
# Define barcode text box | |
self.barcode_txt = tki.Text(self.root, height=1, width=30) | |
self.barcode_txt.grid(column=0, row=1, sticky=(tki.S, tki.E, tki.W)) | |
# Define Item list | |
self.item_list=scrolledtext.ScrolledText(self.root, width=30, height=10, wrap=tki.WORD) | |
self.item_list.grid(column=0, row=2, sticky=(tki.N, tki.S, tki.E, tki.W)) | |
# Define barcode "Scan Item" button | |
scan_item_btn = tki.Button(self.root, width=30, text = 'Scan Item...', command=self.scanItem) | |
scan_item_btn.grid(column=1, row=1, sticky=(tki.N, tki.S, tki.E, tki.W)) | |
# Define Total Reward text box | |
self.total_txt = tki.Text(self.root, height=1, width=30) | |
self.total_txt.grid(column=0, row=3, sticky=(tki.S, tki.E, tki.W)) | |
# Define "Clame Reward" button | |
get_reward_btn = tki.Button(self.root, text = 'Get Reward', command=self.initiateGetReward) | |
get_reward_btn.grid(column=0, row=4, sticky=(tki.N, tki.S, tki.E, tki.W)) | |
# Define Message box | |
self.msg_box=scrolledtext.ScrolledText(self.root, width=30, height=10, wrap=tki.WORD) | |
self.msg_box.grid(column=0, row=5, columnspan=2, sticky=(tki.N, tki.S, tki.E, tki.W)) | |
# ... | |
self.root.bind('<Return>', (lambda event: self.scanItem())) | |
# Set a callback to handle when the window is closed | |
self.root.wm_title("The Reverse Vending Machine") | |
self.root.wm_protocol("WM_DELETE_WINDOW", self.onClose) | |
def getReward(self): | |
# Try/except statement to get around a RunTime | |
# error that Tkinter throws due to threading | |
try: | |
# Loop the vieoStream until we get a QR code | |
while not self.stopEvent.is_set(): | |
# Grab the frame from the video stream and resize it to | |
# have a maximum width of 300 pixels | |
self.frame = self.vs.read() | |
self.frame = imutils.resize(self.frame, width=300) | |
# Get QR codes from camera using pyzbar | |
qrcodes = pyzbar.decode(self.frame) | |
# Loop over the detected qrcodes | |
for qrcode in qrcodes: | |
# Extract the bounding box location of the barcode and draw | |
# the bounding box surrounding the barcode on the image | |
(x, y, w, h) = qrcode.rect | |
cv2.rectangle(self.frame, (x, y), (x + w, y + h), (0, 0, 255), 2) | |
# The barcode data is a bytes object so if we want to draw it | |
# on our output image we need to convert it to a string first | |
qrcodeData = qrcode.data.decode("utf-8") | |
qrcodeType = qrcode.type | |
# Draw the barcode data and barcode type on the image | |
text = "{} ({})".format(qrcodeData, qrcodeType) | |
cv2.putText(self.frame, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) | |
# QR codes generated by the IOTA wallet or thetangle.org | |
# is actually a dict object so we use json to convert the | |
# qrcodeData string to a dict. | |
jsondata = json.loads(qrcodeData) | |
# Get address from dict | |
addr = jsondata.get('address') | |
# Now that we have the IOTA address we can exit the while loop and initiate the payment process | |
self.stopEvent.set() | |
# OpenCV represents images in BGR order; however PIL | |
# represents images in RGB order, so we need to swap | |
# the channels, then convert to PIL and ImageTk format | |
image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) | |
image = Image.fromarray(image) | |
image = ImageTk.PhotoImage(image) | |
# If the videoStream panel is not None, we need to initialize it | |
if self.panel is None: | |
self.panel = tki.Label(image=image) | |
self.panel.image = image | |
self.panel.grid(row=2, column=1, rowspan=3) | |
# Otherwise, simply update the panel | |
else: | |
self.panel.configure(image=image) | |
self.panel.image = image | |
# Now that we have the IOTA address, lets send the reward to the cusomer | |
# Clear the VideoStream panel | |
self.panel.config(image='') | |
# Display sending reward message | |
self.msg_box.insert(tki.INSERT, 'Sending reward of ' + str(self.total_reward) + ' IOTA to address: ' + addr + '\n') | |
# Create transaction object | |
tx1 = iota.ProposedTransaction( address = iota.Address(addr), message = None, tag = iota.Tag(iota.TryteString.from_unicode('HOTELIOTA')), value = self.total_reward) | |
# Send transaction to tangle | |
self.msg_box.insert(tki.INSERT, 'Sending transaction..., please wait\n') | |
SentBundle = self.api.send_transfer(depth=3,transfers=[tx1], inputs=None, change_address=None, min_weight_magnitude=9) | |
# Display transaction sent confirmation message | |
self.msg_box.insert(tki.INSERT, 'Transaction sendt..., thanks for recycling with IOTA\n') | |
# Cleanup and prepare for next customer... | |
# Clear Item list | |
self.item_list.delete(1.0, 'end') | |
# Clear total reward text box | |
self.total_txt.delete(1.0, 'end') | |
# Reset Total award variable | |
self.total_reward = 0 | |
# Display system is ready message | |
self.msg_box.insert(tki.INSERT, 'System is ready...\n') | |
except RuntimeError: | |
print("[INFO] caught a RuntimeError") | |
def initiateGetReward(self): | |
# Show "get QR code" message | |
self.msg_box.insert(tki.INSERT, 'Please hold a valid IOTA address QR code in front of the camera..\n') | |
# Start new get reward thread | |
self.stopEvent = threading.Event() | |
self.thread = threading.Thread(target=self.getReward, args=()) | |
self.thread.start() | |
def scanItem(self): | |
barcode = self.barcode_txt.get("1.0",'end-1c') | |
barcode = barcode.rstrip("\n") #, Strip any trailing returns from the string | |
barcode_found = False | |
with open('barcodesdb.csv') as csv_file: | |
csv_reader = csv.reader(csv_file, delimiter=',') | |
for row in csv_reader: | |
if row[0] == barcode: | |
item_reward=row[1] | |
self.total_reward = self.total_reward + int(item_reward) | |
barcode_found = True | |
if barcode_found == True: | |
# If a barcode match was found in the barcode database, add Item to list | |
# and update the total reward texbox. | |
# Else, diplay barcode not message | |
self.item_list.insert(tki.INSERT, barcode + ': Reward=' + item_reward + ' IOTA\n') | |
self.msg_box.insert(tki.INSERT, 'Item approved\n') | |
self.total_txt.delete(1.0, 'end') | |
self.barcode_txt.delete(1.0, 'end') | |
self.total_txt.insert(tki.INSERT, 'Total Reward: ' + str(self.total_reward)) | |
else: | |
self.msg_box.insert(tki.INSERT, 'Barcode not found in database\n') | |
def onClose(self): | |
# Set the stop event, cleanup the camera, and allow the rest of | |
# the quit process to continue | |
print("[INFO] closing...") | |
self.stopEvent.set() | |
self.vs.stop() | |
self.root.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment