diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ff7b8b6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +/queue diff --git a/README.md b/README.md index 71fc87a..e63dbf7 100644 --- a/README.md +++ b/README.md @@ -15,35 +15,66 @@ echo -e "This is a test.\\n\\n\\n" > /dev/serial0 ### Installing -Update the system and install prequisities. +1. Enable the serial port. -``` -sudo apt-get update -sudo apt-get install git cups wiringpi build-essential libcups2-dev libcupsimage2-dev python-serial python-pil python-unidecode -``` + ```bash + sudo raspi-config + ``` -Install the printer driver. Don't worry about the warnings that g++ gives. + ![](screenshots/interface-options.png) -``` -git clone https://github.com/adafruit/zj-58 -cd zj-58 -make -sudo ./install -``` + ![](screenshots/serial-port.png) -Make the printer the default printer. This is useful if you are going to be doing other things with it. + ![](screenshots/login-shell.png) -``` -sudo lpadmin -p ZJ-58 -E -v serial:/dev/serial0?baud=19200 -m zjiang/ZJ-58.ppd -sudo lpoptions -d ZJ-58 -``` + ![](screenshots/hardware.png) -Restart the system. Clone this repository and try to run *printertest.py*. + ![](screenshots/summary.png) -``` -git clone https://github.com/galacticfan/Python-Thermal-Printer/ -cd Python-Thermal-Printer -python3 printertest.py -``` +2. Update the system and install perquisites. + + ``` + sudo apt-get update + sudo apt-get install git cups wiringpi build-essential libcups2-dev libcupsimage2-dev python-serial python-pil python-unidecode + ``` + +3. Install the printer driver. Don't worry about the warnings that g++ gives. + + ``` + git clone https://github.com/adafruit/zj-58 + cd zj-58 + make + sudo ./install + ``` + +4. Make the printer the default printer. This is useful if you are going to be doing other things with it. + + ``` + sudo lpadmin -p ZJ-58 -E -v "serial:/dev/serial0?baud=19200" -m zjiang/ZJ-58.ppd + sudo lpoptions -d ZJ-58 + ``` + +5. Install the Python dependencies: + + ```bash + sudo apt-get install --yes python3-pip + pip3 install --user \ + Pillow \ + pyserial + ``` + +6. Restart the system. Clone this repository and try to run *printertest.py*. + + ``` + git clone https://github.com/galacticfan/Python-Thermal-Printer/ + cd Python-Thermal-Printer + python3 printertest.py + ``` + +7. Use `cron` to run the management script on startup by adding the following line to your crontab (`crontab -e`): + + ``` + @reboot /usr/bin/python3 /home/pi/Projects/Python-Thermal-Printer/main.py + ``` -Let me know if you have any issues. + _You will need to update the path to `main.py` depending on where you cloned the repository._ diff --git a/calibrate.py b/calibrate.py index e29585e..a29ccf6 100755 --- a/calibrate.py +++ b/calibrate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Thermal calibration utility for Adafruit_Thermal Python library. # Run this utility before using the printer for the first time, any diff --git a/forecast.py b/forecast.py index 3d9da85..8bc2561 100755 --- a/forecast.py +++ b/forecast.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer. # Retrieves data from DarkSky.net's API, prints current conditions and diff --git a/main.py b/main.py index 9ebff71..ffa017c 100755 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # Main script for Adafruit Internet of Things Printer 2. Monitors button # for taps and holds, performs periodic actions (Twitter polling by default) @@ -15,11 +15,27 @@ # http://www.adafruit.com/products/600 Printer starter pack from __future__ import print_function + import RPi.GPIO as GPIO -import subprocess, time, socket +import datetime +import glob +import logging +import os +import socket +import subprocess +import time + +import requests + from PIL import Image from Adafruit_Thermal import * +ROOT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) +QUEUE_DIRECTORY = os.path.join(ROOT_DIRECTORY, "queue") + +verbose = '--verbose' in sys.argv[1:] or '-v' in sys.argv[1:] +logging.basicConfig(level=logging.DEBUG if verbose else logging.INFO, format="[%(levelname)s] %(message)s") + ledPin = 18 buttonPin = 23 holdTime = 2 # Duration for button hold (shutdown) @@ -30,41 +46,91 @@ printer = Adafruit_Thermal("/dev/serial0", 19200, timeout=5) +class Chdir(object): + + def __init__(self, path): + self.path = os.path.abspath(path) + + def __enter__(self): + self.pwd = os.getcwd() + os.chdir(self.path) + return self.path + + def __exit__(self, exc_type, exc_value, traceback): + os.chdir(self.pwd) + + +class LED(object): + + def __enter__(self): + GPIO.output(ledPin, GPIO.HIGH) + return self + + def __exit__(self, *args): + GPIO.output(ledPin, GPIO.LOW) + + # Called when button is briefly tapped. Invokes time/temperature script. def tap(): - GPIO.output(ledPin, GPIO.HIGH) # LED on while working - subprocess.call(["python", "timetemp.py"]) - GPIO.output(ledPin, GPIO.LOW) + with LED(): + # White space. + printer.feed(6) + + # Release date. + now = datetime.datetime.now() + release = now + datetime.timedelta(days=2) + release_string = release.strftime("%A, %e %B at %H:%M") + printer.print(f"Your mail can be released from quarantine on {release_string}.") + printer.feed(3) + + # Quote. + text, author = get_quote() + printer.println(text) + printer.print(f"- {author}") + printer.justify('R') + printer.feed(3) + printer.justify('L') + + # Statement. + printer.justify('C') + printer.println("Share and Enjoy <3") + printer.justify('L') + printer.feed(3) + + +def get_quote(): + response = requests.get("https://www.adafruit.com/api/quotes.php") + json = response.json() + text, author = json[0]["text"], json[0]["author"] + return (text, author) # Called when button is held down. Prints image, invokes shutdown process. def hold(): GPIO.output(ledPin, GPIO.HIGH) - printer.printImage(Image.open('gfx/goodbye.png'), True) + #printer.printImage(Image.open('gfx/goodbye.png'), True) + printer.print("Goodbye!") printer.feed(3) subprocess.call("sync") - subprocess.call(["shutdown", "-h", "now"]) + subprocess.call(["/sbin/shutdown", "-h", "now"]) GPIO.output(ledPin, GPIO.LOW) # Called at periodic intervals (30 seconds by default). # Invokes twitter script. def interval(): - GPIO.output(ledPin, GPIO.HIGH) - p = subprocess.Popen(["python", "twitter.py", str(lastId)], - stdout=subprocess.PIPE) - GPIO.output(ledPin, GPIO.LOW) - return p.communicate()[0] # Script pipes back lastId, returned to main + return # Called once per day (6:30am by default). # Invokes weather forecast and sudoku-gfx scripts. def daily(): - GPIO.output(ledPin, GPIO.HIGH) - subprocess.call(["python", "forecast.py"]) - subprocess.call(["python", "sudoku-gfx.py"]) - GPIO.output(ledPin, GPIO.LOW) + return + +# Ensure the queue directory exists. +if not os.path.isdir(QUEUE_DIRECTORY): + os.makedirs(QUEUE_DIRECTORY) # Initialization @@ -80,26 +146,13 @@ def daily(): # Processor load is heavy at startup; wait a moment to avoid # stalling during greeting. -time.sleep(30) - -# Show IP address (if network is available) -try: - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.connect(('8.8.8.8', 0)) - printer.print('My IP address is ' + s.getsockname()[0]) - printer.feed(3) -except: - printer.boldOn() - printer.println('Network is unreachable.') - printer.boldOff() - printer.print('Connect display and keyboard\n' - 'for network troubleshooting.') - printer.feed(3) - exit(0) - -# Print greeting image -printer.printImage(Image.open('gfx/hello.png'), True) +# time.sleep(30) + +printer.print("Hello!") +# printer.printImage('gfx/hello.png', True) printer.feed(3) + + GPIO.output(ledPin, GPIO.LOW) # Poll initial button state and time @@ -156,12 +209,13 @@ def daily(): else: dailyFlag = False # Reset daily trigger - # Every 30 seconds, run Twitter scripts. 'lastId' is passed around - # to preserve state between invocations. Probably simpler to do an - # import thing. if t > nextInterval: - nextInterval = t + 30.0 - result = interval() - if result is not None: - lastId = result.rstrip('\r\n') - + nextInterval = t + 5.0 + logging.info("Checking spool...") + with Chdir(QUEUE_DIRECTORY): + files = glob.glob("*.png") + for f in files: + logging.info("Printing '%s'...", f) + printer.printImage(f, False) + printer.feed(10) + os.remove(f) diff --git a/printertest.py b/printertest.py index 2664884..53d60f1 100755 --- a/printertest.py +++ b/printertest.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 from Adafruit_Thermal import * diff --git a/screenshots/hardware.png b/screenshots/hardware.png new file mode 100644 index 0000000..8c7656e Binary files /dev/null and b/screenshots/hardware.png differ diff --git a/screenshots/interface-options.png b/screenshots/interface-options.png new file mode 100644 index 0000000..3bfc189 Binary files /dev/null and b/screenshots/interface-options.png differ diff --git a/screenshots/login-shell.png b/screenshots/login-shell.png new file mode 100644 index 0000000..125b0d3 Binary files /dev/null and b/screenshots/login-shell.png differ diff --git a/screenshots/serial-port.png b/screenshots/serial-port.png new file mode 100644 index 0000000..76dc578 Binary files /dev/null and b/screenshots/serial-port.png differ diff --git a/screenshots/summary.png b/screenshots/summary.png new file mode 100644 index 0000000..5590846 Binary files /dev/null and b/screenshots/summary.png differ diff --git a/sudoku-gfx.py b/sudoku-gfx.py index 2a7ac12..779a5ce 100755 --- a/sudoku-gfx.py +++ b/sudoku-gfx.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Sudoku Generator and Solver in 250 lines of python # Copyright (c) 2006 David Bau. All rights reserved. diff --git a/timetemp.py b/timetemp.py index fcd16ba..833db3a 100755 --- a/timetemp.py +++ b/timetemp.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # Current time and temperature display for Raspberry Pi w/Adafruit Mini # Thermal Printer. Retrieves data from DarkSky.net's API, prints current diff --git a/twitter.py b/twitter.py index 1d980ba..329b046 100755 --- a/twitter.py +++ b/twitter.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # This is a Python port of Adafruit's "Gutenbird" sketch for Arduino. # Polls one or more Twitter accounts for changes, displaying updates