diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a51474e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +src/__pycache__ +spool/ +try.sh \ No newline at end of file diff --git a/README.md b/README.md index 16a3b8f..38cbbb2 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,10 @@ Run stampalafanza.py ![Console](/console.png) + + +# Pantalla oled +- Install adafruit library +# https://github.com/adafruit/Adafruit_CircuitPython_Bundle +# https://github.com/adafruit/Adafruit_CircuitPython_SSD1306 +- I would recomend to install it in a Python venv not in the native python \ No newline at end of file diff --git a/spoolraw.py b/spoolraw.py index adec6a9..9bd1377 100755 --- a/spoolraw.py +++ b/spoolraw.py @@ -28,7 +28,6 @@ def main(): files = [x for x in sorted(glob.glob(os.path.dirname(os.path.realpath(__file__)) + '/spool/**/*-*', recursive=True)) if not x.endswith('.info') and not x.endswith('.keep') and not x.endswith('.raw')] for fname in files: - #print(fname) rawname = fname + "." + ppdstd + ".raw" if not os.path.isfile(rawname): print ("Converto " + os.path.basename(rawname)) @@ -67,7 +66,7 @@ def main(): cmd = CONV_CMD.split(' ') cmd = [x % {'in': fname, 'out': rawname, 'ppd': ppd, 'copies': copies, 'sides': sides, 'media': media} for x in cmd] cmd = " ".join(cmd) - #print (cmd) + print (cmd) os.system(cmd) else: print ("Salto " + os.path.basename(rawname)) diff --git a/src/cups.py b/src/cups.py new file mode 100644 index 0000000..bf490fa --- /dev/null +++ b/src/cups.py @@ -0,0 +1,9 @@ +import configparser + +class CupsManager(): + def __init__(self,fname,DEFAULT_COPIES,DEFAULT_SIDES,DEFAULT_MEDIA): + self.config = configparser.ConfigParser() + self.name = "-".join(os.path.basename(fname).split("-")[1:]) + self.copies = DEFAULT_COPIES + self.sides = DEFAULT_SIDES + self.media = DEFAULT_MEDIA \ No newline at end of file diff --git a/src/media.py b/src/media.py new file mode 100644 index 0000000..6a082e5 --- /dev/null +++ b/src/media.py @@ -0,0 +1,37 @@ +import os +from pad4pi import rpi_gpio +import subprocess + +def playSound(file): + os.system("mpg123 sounds/" + file + ".mp3 > /dev/null 2>&1 &") + +def getPpd(): + prn = subprocess.check_output("lpstat -d | awk '{print $NF}'", shell=True).decode("utf-8").strip() + print("prn: " + prn) + ppd = "/etc/cups/ppd/" + prn +".ppd" + print("ppd: " + ppd) + with open(ppd) as ppdfile: + ppdstd = [x for x in ppdfile if x.startswith("*PCFileName:")] + ppdstd = ppdstd[0].lower().split('"')[1].split(".ppd")[0] + return ppdstd + +class KeyStore(): + def __init__(self): + KEYPAD = [ + ["1", "2", "3", "A"], + ["4", "5", "6", "B"], + ["7", "8", "9", "C"], + ["*", "0", "#", "D"] + ] + ROW_PINS = [21, 20,16, 12]# BCM numbering + COL_PINS = [26, 19, 13, 6] # BCM numberin + factory = rpi_gpio.KeypadFactory() + self.keypad = factory.create_keypad(keypad=KEYPAD, row_pins=ROW_PINS, col_pins=COL_PINS) + self.keypad.registerKeyPressHandler(self.storeKey) + self.keypressed = "" + + def storeKey(self,key): + self.keypressed = key + + def restartKey(self): + self.keypressed = "" diff --git a/src/parser.py b/src/parser.py new file mode 100644 index 0000000..40acadd --- /dev/null +++ b/src/parser.py @@ -0,0 +1,15 @@ +import sys +import argparse + +def readParameters(): + usage_examples = sys.argv[0] + " -digits 4 -i2c 0x3c \n" + parser = argparse.ArgumentParser(epilog=usage_examples,formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument("-digits",help="Number of digits to identify fanzines", default=3,type=int) + parser.add_argument("-copies", help="Number of copies by default", default=1, type=int) + parser.add_argument("-sides", help="Sides for printing by default two-sided-long-edge, accepted values [two-sided-long-edge, two-sided-short-edge, one-sided]",default="two-sided-long-edge") + parser.add_argument("-media", help="Page size, by default it's A4", default="A4") + parser.add_argument("-i2c", help="I2c address for your device, default value 0x27", default="0x27") + parser.add_argument("-st", help="Screen type, accepted values ['oled', 'lcd'] default oled ", default="oled") + args = parser.parse_args() + args.i2c = int(args.i2c,16) + return args \ No newline at end of file diff --git a/src/screen.py b/src/screen.py new file mode 100644 index 0000000..d07b46f --- /dev/null +++ b/src/screen.py @@ -0,0 +1,66 @@ +import time +from board import SCL, SDA +import busio +from PIL import Image, ImageDraw, ImageFont +import adafruit_ssd1306 + +class ScreenManager: + def __init__(self,screentype,temp_digits = 3,font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",address=0): + self.screentype = screentype + self.temp_digits = temp_digits + + if screentype.lower() == "oled": + self.i2c = busio.I2C(SCL, SDA) + + self.disp = adafruit_ssd1306.SSD1306_I2C(128, 32, self.i2c) + self.disp.fill(0) + self.disp.show() + + self.width = self.disp.width + self.height = self.disp.height + self.image = Image.new("1", (self.width,self.height)) + + self.draw = ImageDraw.Draw(self.image) + self.x = 0 + + self.padding = -2 + self.top = self.padding + self.bottom = self.height - self.padding + + self.font = ImageFont.truetype(font_path,size=14) + self.draw.rectangle((0, 0, self.width, self.height), outline=0, fill=0) + elif screentype.lower() == "lcd": + self.mylcd = CharLCD(i2c_expander='PCF8574', address=adress, port=1, cols=16, rows=2, charmap='A02') + else: + print("Error, invalid screen type") + exit(1) + + def __displayLcd(self): + r1 = ro1[:16].center(16,' ') + r2 = ro2[:16].center(16,' ') + self.mylcd.write_string(r1 + '\r\n' + r2) + + def __displayOled(self,ro1,ro2): + self.draw.rectangle((0, 0, self.width, self.height), outline=0, fill=0) + self.draw.text((self.x, self.top + 0), ro1, font=self.font,fill=255) + self.draw.text((self.x, self.top + 16), ro2, font=self.font,fill=255) + self.disp.image(self.image) + self.disp.show() + time.sleep(0.1) + + def display(self,ro1,ro2): + if self.screentype == "oled": + self.__displayOled(ro1,ro2) + elif self.screentype == "lcd": + self.__displayLcd(ro1,ro2) + + def __formatCode(self,code): + return (" " + code + "-"*(self.temp_digits - len(code))) + + def displayCode(self,code): + fc = self.__formatCode(code) + self.display("Stampa La Fanza", fc) + + def display404(self,code): + fc = self.__formatCode(code) + self.display("No fanza",fc) diff --git a/stampalafanza.py b/stampalafanza.py index 90752f7..9662e7a 100755 --- a/stampalafanza.py +++ b/stampalafanza.py @@ -4,7 +4,6 @@ import time import requests import os -import subprocess import glob import configparser import random @@ -15,143 +14,93 @@ from queue import Queue from RPLCD.i2c import CharLCD -#from RPi_GPIO_i2c_LCD import lcd -#import serial - -from pad4pi import rpi_gpio - -CODE_DIGITS = 3 -temp_digits = 0 - -DEFAULT_COPIES = 1 -DEFAULT_SIDES = "two-sided-long-edge" #two-sided-long-edge, two-sided-short-edge, one-sided -DEFAULT_MEDIA = "A4" - -PRINT_CMD = "lp -n %(copies)s -o sides=%(sides)s -o media=%(media)s %(in)s" -PRINTRAW_CMD = "lp -o raw %(in)s" - - -#mylcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=0, cols=16, rows=2, charmap='A02') -mylcd = CharLCD(i2c_expander='PCF8574', address=0x27, port=1, cols=16, rows=2, charmap='A02') - -# mylcd = lcd.HD44780(0x27) -#ser = serial.Serial('/dev/ttyS0', 19200) # open serial port - -KEYPAD = [ - ["1", "2", "3", "A"], - ["4", "5", "6", "B"], - ["7", "8", "9", "C"], - ["*", "0", "#", "D"] -] - -#ROW_PINS = [23, 24, 10, 9] # BCM numbering -#COL_PINS = [11, 25, 8, 7] # BCM numbering -ROW_PINS = [5, 6, 13, 19] # BCM numbering -COL_PINS = [26, 16, 20, 21] # BCM numbering - - -key_lookup = "" - - +# Internal project imports +from src.parser import readParameters +from src.media import playSound, KeyStore, getPpd +from src.screen import ScreenManager def main(): - play("start") - print ("start") + # First read user parameters and asign them to configuration vars + userParameters = readParameters() - display("Stampa la fanza","by itec") - resetdisplay = True - displaytime = time.time() + 10 - - # for ppd in sorted(glob.glob(os.path.dirname(os.path.realpath(__file__)) + "/ppd/*.ppd")): - prn = subprocess.check_output("lpstat -d | awk '{print $NF}'", shell=True).decode("utf-8").strip() - print("prn: " + prn) - ppd = "/etc/cups/ppd/" + prn +".ppd" - print("ppd: " + ppd) - #cerca il nome standard - with open(ppd) as ppdfile: - ppdstd = [x for x in ppdfile if x.startswith("*PCFileName:")] - ppdstd = ppdstd[0].lower().split('"')[1].split(".ppd")[0] - print("ppdstd: " + ppdstd) - - code = "" - global key_lookup - key_lookup = "" - global temp_digits - temp_digits = CODE_DIGITS + CODE_DIGITS = userParameters.digits - factory = rpi_gpio.KeypadFactory() - keypad = factory.create_keypad(keypad=KEYPAD, row_pins=ROW_PINS, col_pins=COL_PINS) + DEFAULT_COPIES = userParameters.copies + DEFAULT_SIDES = userParameters.sides #two-sided-long-edge, two-sided-short-edge, one-sided + DEFAULT_MEDIA = userParameters.media - keypad.registerKeyPressHandler(printKey) + PRINT_CMD = "lp -n %(copies)s -o sides=%(sides)s -o media=%(media)s %(in)s" + PRINTRAW_CMD = "lp -o raw %(in)s" + code = "" + resetdisplay = True + displaytime = time.time() + # Object inizialization + ks = KeyStore() + sm = ScreenManager(userParameters.st,CODE_DIGITS,address=userParameters.i2c) + ppdstd = getPpd() + + # START + playSound("start") + print ("start") + sm.display("Stampa la fanza", "Initializing") - #loop - #try: + # Program main loop while True: time.sleep(0.05) - if resetdisplay == True and time.time() > displaytime: - displaycode(code) - temp_digits = CODE_DIGITS + sm.displayCode(code) + sm.temp_digits = CODE_DIGITS resetdisplay = False + # Resets the introduced code after not pressing buttons for a while if code != '': if time.time() > keytime + 3: code = '' - #keytime = time.time() - print ("Resettato") - play("reset") - displaycode(code) - - - if key_lookup != "": - # print(key_lookup) - + playSound("reset") + sm.displayCode(code) + + if ks.keypressed != "": keytime = time.time() - if(key_lookup == "D"): + # Action bindings + if(ks.keypressed == "D"): code = '' - temp_digits = CODE_DIGITS + sm.temp_digits = CODE_DIGITS print ("Resettato") - play("reset") - displaycode(code) - elif(key_lookup == "xxx"): + playSound("reset") + sm.displayCode(code) + elif(ks.keypressed == "xxx"): code = code[:-1] - play("button") - displaycode(code) - elif key_lookup != "None": - code += key_lookup - play("button") + playSound("button") + sm.displayCode(code) + elif ks.keypressed != "None": + code += ks.keypressed + playSound("button") if code == "ACA": # ACAB easter egg - temp_digits = 4 - displaycode(code) - - if len(code) == temp_digits: - print(code) + sm.temp_digits = 4 + sm.displayCode(code) - # fname = [x for x in sorted(glob.glob(os.path.dirname(os.path.realpath(__file__)) + '/spool/**/%s-*' % code, recursive=True)) - # if not x.endswith('.info') and not x.endswith('.keep') and not x.endswith('.raw')] - - #questo cerca direttamente il raw + # This is when user introduces al the code characters + if len(code) == sm.temp_digits: fname = [x.replace('.' + ppdstd + '.raw','') for x in sorted(glob.glob(os.path.dirname(os.path.realpath(__file__)) + '/spool/**/%s-*.' % code + ppdstd + '.raw', recursive=True))] - - if not fname: print ("Non trovato " + code) - play("fail") - display("No fanza", formatcode(code)) + playSound("fail") + sm.display404(code) else: - #fname = fname[0] + # TO-DO: I think this can be moved to other file + # Printer or something like that fname = random.choice(fname) - #leggo la configurazione + # leggo la configurazione + # Printer configuration config = configparser.ConfigParser() name = "-".join(os.path.basename(fname).split("-")[1:]) copies = DEFAULT_COPIES sides = DEFAULT_SIDES media = DEFAULT_MEDIA - try: # print(os.path.dirname(fname) + "/" + code + '.info') @@ -164,21 +113,10 @@ def main(): except Exception: pass - try: - config.read(fname + '.info') - printconf = config['print'] - name = printconf.get('name', name) - copies = printconf.getint('copies', copies) - sides = printconf.get('sides', sides) - media = printconf.get('media', media) - except Exception: - pass - print("Conf:",name, copies, sides, media) - print ("Stampo " + code) - play("print") - display("Stampo", name) + playSound("print") + sm.display("Stampo", name) #cerca il raw: rawname = fname + "." + ppdstd + ".raw" @@ -187,57 +125,13 @@ def main(): cmd = PRINTRAW_CMD.split(' ') cmd = [x % {'in': rawname} for x in cmd] cmd = " ".join(cmd) - print (cmd) - os.system(cmd) - else: - #stampo - cmd = PRINT_CMD.split(' ') - cmd = [x % {'in': fname, 'copies': copies, 'sides': sides, 'media': media} for x in cmd] - cmd = " ".join(cmd) - print (cmd) os.system(cmd) code = '' resetdisplay = True - temp_digits = CODE_DIGITS + sm.temp_digits = CODE_DIGITS displaytime = time.time() + 5 - - key_lookup = "" - #except: - # keypad.cleanup() - - -def displaycode(code): - display("Stampa la fanza", formatcode(code)) - -def display(ro1, ro2): - r1 = ro1[:16].center(16,' ') - r2 = ro2[:16].center(16,' ') - - mylcd.write_string(r1 + '\r\n' + r2) - - - #mylcd.set(r1, 1) - #mylcd.set(r2, 2) - - #r1 = ro1[:20].center(20,' ') - #r2 = ro2[:20].center(20,' ') - #ser.write(b'\xfe\x42') #power on display - #ser.write(("\n" + r1 + r2).encode()) - - #print("-" + r1 + "-" + r2 + "-") - -def formatcode(code): - #return (code + "-")[0:CODE_DIGITS] - return (code + "-"*(temp_digits - len(code))) - -def play(file): - os.system("mpg123 sounds/" + file + ".mp3 > /dev/null 2>&1 &") - -def printKey(key): - #print(key) - global key_lookup - key_lookup = key + ks.restartKey() if __name__ == "__main__": main()