diff --git a/config.py b/config.py index 8226385..6380257 100644 --- a/config.py +++ b/config.py @@ -125,7 +125,6 @@ def create_config(config_file=None): logger.warning("Papirus display library not installed.") sys.exit("Exiting...") - # Display - Waveshare 2.13 is 250 * 122 pixels if "waveshare" in conf["atm"]["display"]: try: @@ -135,6 +134,15 @@ def create_config(config_file=None): logger.warning("Waveshare display library not installed.") sys.exit("Exiting...") +# Display - Waveshare 2.13 (D) is 212 * 104 pixels +if "waveshare2in13d" in conf["atm"]["display"]: + try: + from waveshare_epd import epd2in13d + WAVESHARE = epd2in13d.EPD() + except ImportError: + logger.warning("Waveshare display library not installed.") + sys.exit("Exiting...") + # API URL for coingecko COINGECKO_URL_BASE = "https://api.coingecko.com/api/v3/" diff --git a/displays/waveshare2in13d.py b/displays/waveshare2in13d.py new file mode 100644 index 0000000..66edefe --- /dev/null +++ b/displays/waveshare2in13d.py @@ -0,0 +1,495 @@ +#!/usr/bin/python3 + +import time +import math + +import config +import utils + +from displays import messages + +from PIL import Image, ImageFont, ImageDraw + + +def update_startup_screen(): + """Show startup screen on eInk Display + """ + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (24, 4), + messages.startup_screen_1, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + draw.text( + (12, 24), + messages.startup_screen_2, + fill=config.BLACK, + font=utils.create_font("sawasdee", 30), + ) + draw.text( + (3, 82), + messages.startup_screen_3, + fill=config.BLACK, + font=utils.create_font("freemono", 15), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_qr_request(): + # initially set all white background + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (30, 10), + messages.qr_request_1, + fill=config.BLACK, + font=utils.create_font("freemono", 23), + ) + draw.text( + (16, 32), + messages.qr_request_2, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + for i in range(0, 3): + draw.text( + (90, 55), + str(3 - i), + fill=config.BLACK, + font=utils.create_font("freemono", 55), + ) + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + draw.rectangle((75, 50, 115, 90), fill=config.WHITE, outline=config.WHITE) + time.sleep(0.5) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (20, 15), + messages.qr_request_3, + fill=config.BLACK, + font=utils.create_font("freemono", 24), + ) + draw.text( + (20, 45), + messages.qr_request_4 + str(math.floor(config.SATS)) + messages.qr_request_5, + fill=config.BLACK, + font=utils.create_font("freemono", 24), + ) + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_qr_failed(): + # initially set all white background + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + + draw.text( + (20, 15), + messages.qr_failed_1, + fill=config.BLACK, + font=utils.create_font("freemono", 24), + ) + draw.text( + (20, 45), + messages.qr_failed_2, + fill=config.BLACK, + font=utils.create_font("freemono", 24), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_payout_screen(): + """Update the payout screen to reflect balance of deposited coins. + Scan the invoice??? I don't think so! + """ + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (20, 25), + str(math.floor(config.SATS)) + messages.payout_screen_1, + fill=config.BLACK, + font=utils.create_font("freemono", 28), + ) + draw.text( + (20, 60), + messages.payout_screen_2, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + # scan the invoice + # TODO: I notice this is commented out, I presume this function should _not_ be + # scanning a QR code on each update? + # config.INVOICE = qr.scan() + + +def update_payment_failed(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (14, 20), + messages.payment_failed_1, + fill=config.BLACK, + font=utils.create_font("freemono", 22), + ) + draw.text( + (35, 60), + messages.payment_failed_2, + fill=config.BLACK, + font=utils.create_font("freemono", 19), + ) + draw.text( + (60, 80), + messages.payment_failed_3, + fill=config.BLACK, + font=utils.create_font("freemono", 19), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_thankyou_screen(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (25, 15), + messages.thankyou_screen_1, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + draw.text( + (50, 42), + messages.thankyou_screen_2, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + draw.text( + (13, 80), + messages.thankyou_screen_3, + fill=config.BLACK, + font=utils.create_font("freemono", 16), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + time.sleep(5) + + +def update_nocoin_screen(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (10, 10), + messages.nocoin_screen_1, + fill=config.BLACK, + font=utils.create_font("freemonobold", 22), + ) + draw.text( + (45, 50), + messages.nocoin_screen_2, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + draw.text( + (45, 75), + messages.nocoin_screen_3, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_lnurl_generation(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (40, 20), + messages.lnurl_generation_1, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + draw.text( + (14, 60), + messages.lnurl_generation_2, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + +def update_shutdown_screen(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (10, 10), + messages.shutdown_screen_1, + fill=config.BLACK, + font=utils.create_font("freemono", 22), + ) + draw.text( + (19, 50), + messages.shutdown_screen_2, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + draw.text( + (52, 75), + messages.shutdown_screen_3, + fill=config.BLACK, + font=utils.create_font("freemono", 20), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_wallet_scan(): + # initially set all white background + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (25, 15), + messages.wallet_scan_1, + fill=config.BLACK, + font=utils.create_font("freemono", 23), + ) + draw.text( + (25, 40), + messages.wallet_scan_2, + fill=config.BLACK, + font=utils.create_font("freemono", 23), + ) + draw.text( + (25, 65), + messages.wallet_scan_3, + fill=config.BLACK, + font=utils.create_font("freemono", 23), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + time.sleep(2) + + +def update_lntxbot_balance(balance): + # initially set all white background + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (45, 15), + messages.lntxbot_balance_1, + fill=config.BLACK, + font=utils.create_font("freemonobold", 24), + ) + draw.text( + (12, 55), + messages.lntxbot_balance_2, + fill=config.BLACK, + font=utils.create_font("freemono", 15), + ) + draw.text( + (45, 75), + str("{:,}".format(balance)) + messages.lntxbot_balance_3, + fill=config.BLACK, + font=utils.create_font("freemono", 22), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + time.sleep(3) + + +def update_btcpay_lnd(): + # initially set all white background + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (45, 20), + messages.btcpay_lnd_1, + fill=config.BLACK, + font=utils.create_font("freemonobold", 24), + ) + draw.text( + (10, 55), + messages.btcpay_lnd_2, + fill=config.BLACK, + font=utils.create_font("freemono", 17), + ) + draw.text( + (10, 80), + messages.btcpay_lnd_3, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + time.sleep(3) + + +def draw_lnurl_qr(qr_img): + """Draw a lnurl qr code on the e-ink screen + """ + image, width, height, draw = init_screen(color=config.BLACK) + + qr_img = qr_img.resize((104, 104), resample=0) + + draw = ImageDraw.Draw(image) + draw.bitmap((0, 0), qr_img, fill=config.WHITE) + draw.text( + (115, 30), + messages.lnurl_qr_1, + fill=config.WHITE, + font=utils.create_font("freemonobold", 20), + ) + draw.text( + (115, 50), + messages.lnurl_qr_2, + fill=config.WHITE, + font=utils.create_font("freemonobold", 20), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_amount_screen(): + """Update the amount screen to reflect new coins inserted + """ + image, width, height, draw = init_screen(color=config.WHITE) + + draw.rectangle( + (2, 2, width - 2, height - 2), fill=config.WHITE, outline=config.BLACK + ) + draw.text( + (12, 10), + str("{:,}".format(math.floor(config.SATS))) + messages.amount_screen_1, + fill=config.BLACK, + font=utils.create_font("dotmbold", 28), + ) + draw.text( + (12, 40), + "%.2f" % round(config.FIAT, 2) + " " + config.conf["atm"]["cur"].upper(), + fill=config.BLACK, + font=utils.create_font("dotmbold", 23), + ) + draw.text( + (12, 65), + messages.amount_screen_2, + fill=config.BLACK, + font=utils.create_font("freemono", 16), + ) + draw.text( + (60, 65), + messages.amount_screen_3 + + str(math.floor(config.SATPRICE)) + + messages.amount_screen_4 + + config.conf["atm"]["centname"], + fill=config.BLACK, + font=utils.create_font("freemono", 16), + ) + draw.text( + (12, 80), + messages.amount_screen_5, + fill=config.BLACK, + font=utils.create_font("freemono", 16), + ) + draw.text( + (60, 80), + messages.amount_screen_6 + + config.conf["atm"]["fee"] + + messages.amount_screen_7 + + str(math.floor(config.SATSFEE)) + + messages.amount_screen_8, + fill=config.BLACK, + font=utils.create_font("freemono", 16), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_lnurl_cancel_notice(): + image, width, height, draw = init_screen(color=config.WHITE) + + draw.text( + (6, 20), + messages.lnurl_cancel_notice_1, + fill=config.BLACK, + font=utils.create_font("freemono", 18), + ) + draw.text( + (6, 65), + messages.lnurl_cancel_notice_2, + fill=config.BLACK, + font=utils.create_font("freemono", 14), + ) + draw.text( + (6, 85), + messages.lnurl_cancel_notice_3, + fill=config.BLACK, + font=utils.create_font("freemono", 14), + ) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def update_blank_screen(): + image, width, height, draw = init_screen(color=config.WHITE) + + config.WAVESHARE.init() + config.WAVESHARE.display(config.WAVESHARE.getbuffer(image)) + + +def init_screen(color): + """Prepare the screen for drawing and return the draw variables + """ + image = Image.new("1", (config.WAVESHARE.height, config.WAVESHARE.width), color) + # Set width and height of screen + width, height = image.size + # prepare for drawing + draw = ImageDraw.Draw(image) + return image, width, height, draw diff --git a/example_config.ini b/example_config.ini index e90c1e0..f4a3677 100644 --- a/example_config.ini +++ b/example_config.ini @@ -19,6 +19,7 @@ dangermode = on # Current options are: # display = papiruszero2in # display = waveshare2in13 +# display = waveshare2in13d display = papiruszero2in # Automatically set during initial setup to LND or LNTXBOT