#!/usr/bin/python
# coding: utf8
__author__ = 'laird'
#
# OSCommerceClient.py
#
# Polls an OSCommerce site and pulls down a list of pending orders, prints them, and sets their status to 'process$
#
# uses requests from http://docs.python-requests.org/en/latest/user/install/#distribute-pip
#
# Todo:
# - remove extended character substitution
import logging
import requests
import Queue
from threading import Thread
import time
import argparse
from escpos import *
try:
import RPi.GPIO as GPIO
except ImportError:
print "error importing GPIO. No access to printer for you!"
havePrinter = False;
# configuration
server = "test.com" #set to your own server
securityCode = "********"
pollPage = "/arduino2.php" # poll for orders
detailPage = "/arduino3.php" # get text of receipt to print
setPage = "/arduino5.php" # set status of an order
copies = 2 # set to no of copies... usefull to check if driver hands over the correct amount of cash
testMode = 0 # set to 1 to suppress setting order status (so can retest the same order)
# Set to the serial port for your printer
havePrinter = False
Epson = printer.Serial("/dev/ttyAMA0")
Epson._raw('\x1b\x52\x04') # Set to Danish 1 character set
# Buzzer on GPIO 22 = pin 15
buzzer = 15
GPIO.setmode(GPIO.BOARD)
GPIO.setup(buzzer, GPIO.OUT, initial=GPIO.HIGH)
# Standard
waitPollForOrders = 30 # wait 30 seconds between polls
printCopies = 1 # number of copies of receipt to print
maxNumToPrint = 5
buzzerTime = 1 # buzz for one second
# parse command line arguments
parser = argparse.ArgumentParser(description='This is the OSCommerce client by laird.', epilog="set either poll or reset, not both.")
# group = parser.add_mutually_exclusive_group()
parser.add_argument('-p','--poll', metavar='seconds', type=int, default=30, help='poll for new orders')
parser.add_argument('-f','--force', type=int, default=0, help='force orders to a given status code')
parser.add_argument('-c','--printCopies', type=int, default=1, help='print this many copies of each receipt')
parser.add_argument('-t','--testMode', type=int, default=0, help='set test mode to 1 to leave orders in unchanged state')
parser.add_argument('-i','--havePrinter', type=int, default=1, help='set to 1 if you have a printer, 0 if not')
parser.add_argument('-s','--server', default="87.51.52.114", help='address of server')
parser.add_argument('-e','--securityCode', default="1234", help='security code for server')
parser.add_argument('-q','--pollPage', default="/arduino1.php", help='page to poll for orders')
parser.add_argument('-d','--detailPage', default="/arduino3.php", help='page to retrieve order details')
parser.add_argument('-a','--setPage', default="/arduino4.php", help='page to set status')
parser.add_argument('-n','--serialPort', default="/dev/ttyAMA0", help='serial port for printer')
# note: Running with -h or --help prints the above info
args = parser.parse_args()
if args.poll: waitPollForOrders=args.poll
if args.copies: printCopies = args.copies
# setup
#order = ""
#orders = []
# queue of orders received in polling that need to be printed
ordersToPrint = Queue.Queue()
# queue of orders that were printed that need to be set to status 'processing'
ordersToConfirm = Queue.Queue();
# poll for orders, add any pending to queue for processing
def pollForUpdates(ordersToPrint, ordersToConfirm):
"Poll for pending orders, add them to queue to print"
print "starting poll worker"
while True:
print "poll for orders"
url = "http://"+server+pollPage;
payload = {'sc': securityCode};
pollResult = requests.get(url, params=payload);
textResult = pollResult.text;
if (len(textResult) > 0):
orders=textResult.split(',');
for order in orders:
# strip out formatting
order = order.replace("[",""); # ignore starting [
order = order.replace("
",""); # ignore break between lines
order = order.replace("OK]",""); # ignore end OK]
logging.debug("processing order "+order);
vals = order.split();
if (len(vals) == 2):
orderNum = int(vals[0]);
status = int(vals[1]);
logging.debug("found order "+str(orderNum)+" status "+str(status)+",")
if (status == 2):
print "queue order %i to print." % orderNum
ordersToPrint.put(orderNum)
else:
logging.debug("skip order "+str(orderNum));
else:
if order=="OK]":
logging.debug("OK at end of list");
#else:
#logging.warn("Found bad order "+order);
time.sleep(waitPollForOrders)
def printOrders(ordersToPrint, ordersToConfirm):
"worker thread to print a queued order, then queue it to confirm"
print "starting print worker"
while True:
order = ordersToPrint.get()
print "printing order %i ." % +order
url = "http://"+server+detailPage;
payload = {'sc': securityCode, "o": order};
printResult = requests.get(url, params=payload);
printResult.encoding = 'ISO-8859-1'
for copy in range(copies):
textResult = printResult.text
# replace non-ASCII characters
# textResult = textResult.replace(u"Å","AA")
# textResult = textResult.replace(u"Æ","AE")
# textResult = textResult.replace(u"Ø","OE")
# textResult = textResult.replace(u"å","aa")
# textResult = textResult.replace(u"æ","ae")
# textResult = textResult.replace(u"ø","oe")
#print textResult
if (len(textResult) > 0):
textBlocks = printResult.text.split("[")
first=True
for textBlock in textBlocks:
#print "block "+textBlock
if first: # don't try to parse control code from first text block because it doesn't have one
print textBlock
if len(textBlock)>1: Epson._raw(textBlock.encode('utf-8')) # printer hates null strings
first = False
else:
c = textBlock[0] # first character is formatting command
text = textBlock[1:]
#print "control "+c+" text "+text
if (c == 'B'):
if havePrinter: Epson.set(type="B")
#print ""
elif (c == 'b'):
if havePrinter: Epson.set(type="normal")
#print ""
elif (c == 'U'):
if havePrinter: Epson.set(type="U")
#print ""
elif (c == 'u'):
if havePrinter: Epson.set(type="normal")
#print ""
elif (c == 'D'):
if havePrinter: Epson.set(width=2, height=2)
#print ""
elif (c == 'd'):
if havePrinter: Epson.set(width=1, height=1)
#print ""
elif (c == 'F'):
if havePrinter: Epson._raw('\x0a')
#print "Feed"
elif (c == 'E'):
if havePrinter: Epson._raw('\x5B')
elif (c == 'e'):
if havePrinter: Epson._raw('\x7B')
elif (c == 'O'):
if havePrinter: Epson._raw('\x5C')
elif (c == 'o'):
if havePrinter: Epson._raw('\x7C')
elif (c == 'A'):
if havePrinter: Epson._raw('\x5D')
elif (c == 'a'):
if havePrinter: Epson._raw('\x7D')
else:
print ""
if len(text)>0:
if havePrinter: Epson._raw(text) # print out the text
if havePrinter: Epson.cut()
# repeat above for each copy
# and sound buzzer
GPIO.output(buzzer, GPIO.LOW)
time.sleep(buzzerTime)
GPIO.output(buzzer, GPIO.HIGH)
ordersToConfirm.put(order) # if successful. if failed, add back to queue to print
ordersToPrint.task_done()
def confirmOrders(ordersToPrint, ordersToConfirm):
"worker thread to send confirmation message"
if (testMode):
print "starting confirm worker in test mode"
else:
print "starting confirm worker"
while True:
order = ordersToConfirm.get()
if (not testMode):
print "confirming order "+str(order)+"."
url = "http://"+server+setPage;
payload = {'sc': securityCode, "o": order, "s":"finished"};
printResult = requests.get(url, params=payload);
ordersToConfirm.task_done()
if args.reset:
print "Sorry, I don't know how to reset orders yet."
else:
if args.poll:
print "Starting polling"
pollWorker = Thread(target=pollForUpdates, args=(ordersToPrint, ordersToConfirm))
pollWorker.setDaemon(True)
pollWorker.start()
printWorker = Thread(target=printOrders, args=(ordersToPrint, ordersToConfirm))
printWorker.setDaemon(True)
printWorker.start()
confirmWorker = Thread(target=confirmOrders, args=(ordersToPrint, ordersToConfirm))
confirmWorker.setDaemon(True)
confirmWorker.start();
while True:
time.sleep(60)
#print "bored"
# sit back and relax while the workers work